From: <le...@us...> - 2008-08-11 23:27:44
|
Revision: 5155 http://jython.svn.sourceforge.net/jython/?rev=5155&view=rev Author: leosoto Date: 2008-08-11 23:27:27 +0000 (Mon, 11 Aug 2008) Log Message: ----------- __findattr__ refactor. The overridable version is not called __findattr_ex__ (in the abscense of a better name), and can return null or raise AttributeError, whatever is more efficient for the implementing code. This makes *Derived getattr() more correct and fixes #1041 and #1095. Modified Paths: -------------- branches/asm/Lib/test/test_descr_jy.py branches/asm/src/com/ziclix/python/sql/PyConnection.java branches/asm/src/com/ziclix/python/sql/PyCursor.java branches/asm/src/com/ziclix/python/sql/PyExtendedCursor.java branches/asm/src/com/ziclix/python/sql/PyStatement.java branches/asm/src/com/ziclix/python/sql/connect/Connect.java branches/asm/src/com/ziclix/python/sql/connect/Connectx.java branches/asm/src/com/ziclix/python/sql/connect/Lookup.java branches/asm/src/com/ziclix/python/sql/util/BCP.java branches/asm/src/org/python/core/PyArrayDerived.java branches/asm/src/org/python/core/PyBaseException.java branches/asm/src/org/python/core/PyBaseExceptionDerived.java branches/asm/src/org/python/core/PyBooleanDerived.java branches/asm/src/org/python/core/PyClass.java branches/asm/src/org/python/core/PyClassMethodDerived.java branches/asm/src/org/python/core/PyComplexDerived.java branches/asm/src/org/python/core/PyDictionaryDerived.java branches/asm/src/org/python/core/PyEnumerateDerived.java branches/asm/src/org/python/core/PyFileDerived.java branches/asm/src/org/python/core/PyFloatDerived.java branches/asm/src/org/python/core/PyFrame.java branches/asm/src/org/python/core/PyFrozenSetDerived.java branches/asm/src/org/python/core/PyInstance.java branches/asm/src/org/python/core/PyIntegerDerived.java branches/asm/src/org/python/core/PyJavaClass.java branches/asm/src/org/python/core/PyJavaPackage.java branches/asm/src/org/python/core/PyListDerived.java branches/asm/src/org/python/core/PyLongDerived.java branches/asm/src/org/python/core/PyMethod.java branches/asm/src/org/python/core/PyModule.java branches/asm/src/org/python/core/PyModuleDerived.java branches/asm/src/org/python/core/PyObject.java branches/asm/src/org/python/core/PyObjectDerived.java branches/asm/src/org/python/core/PyPropertyDerived.java branches/asm/src/org/python/core/PySetDerived.java branches/asm/src/org/python/core/PySliceDerived.java branches/asm/src/org/python/core/PyStringDerived.java branches/asm/src/org/python/core/PySuper.java branches/asm/src/org/python/core/PySuperDerived.java branches/asm/src/org/python/core/PySystemState.java branches/asm/src/org/python/core/PyTableCode.java branches/asm/src/org/python/core/PyTupleDerived.java branches/asm/src/org/python/core/PyType.java branches/asm/src/org/python/core/PyTypeDerived.java branches/asm/src/org/python/core/PyUnicodeDerived.java branches/asm/src/org/python/modules/_csv/PyDialectDerived.java branches/asm/src/org/python/modules/_functools/PyPartialDerived.java branches/asm/src/org/python/modules/_weakref/ProxyType.java branches/asm/src/org/python/modules/_weakref/ReferenceTypeDerived.java branches/asm/src/org/python/modules/collections/PyDefaultDictDerived.java branches/asm/src/org/python/modules/collections/PyDequeDerived.java branches/asm/src/org/python/modules/random/PyRandomDerived.java branches/asm/src/org/python/modules/sre/MatchObject.java branches/asm/src/org/python/modules/thread/PyLocalDerived.java branches/asm/src/org/python/modules/zipimport/zipimporterDerived.java branches/asm/src/templates/object.derived Modified: branches/asm/Lib/test/test_descr_jy.py =================================================================== --- branches/asm/Lib/test/test_descr_jy.py 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/Lib/test/test_descr_jy.py 2008-08-11 23:27:27 UTC (rev 5155) @@ -73,6 +73,29 @@ else: self.assert_(False, "should have raised TypeError") + def test_raising_custom_attribute_error(self): + class RaisesCustomMsg(object): + def __get__(self, instance, type): + raise AttributeError("Custom message") + + + class CustomAttributeError(AttributeError): pass + + class RaisesCustomErr(object): + def __get__(self, instance, type): + raise CustomAttributeError + + class Foo(object): + custom_msg = RaisesCustomMsg() + custom_err = RaisesCustomErr() + + self.assertRaises(CustomAttributeError, lambda: Foo().custom_err) + try: + Foo().custom_msg + self.assert_(False) # Previous line should raise AttributteError + except AttributeError, e: + self.assertEquals("Custom message", str(e)) + class SubclassDescrTestCase(unittest.TestCase): def test_subclass_cmp_right_op(self): @@ -144,7 +167,7 @@ # Test strs, unicode, lists and tuples mapping = [] - + # + binop mapping.append((lambda o: 'foo' + o, TypeError, "cannot concatenate 'str' and 'B' objects", @@ -293,12 +316,32 @@ self.assertRaises(AttributeError, func, old) self.assertRaises(TypeError, func, new) +class GetAttrTestCase(unittest.TestCase): + def test_raising_custom_attribute_error(self): + # Very similar to + # test_descr_jy.TestDescrTestCase.test_raising_custom_attribute_error + class BarAttributeError(AttributeError): pass + class Bar(object): + def __getattr__(self, name): + raise BarAttributeError + + class Foo(object): + def __getattr__(self, name): + raise AttributeError("Custom message") + self.assertRaises(BarAttributeError, lambda: Bar().x) + try: + Foo().x + self.assert_(False) # Previous line should raise AttributteError + except AttributeError, e: + self.assertEquals("Custom message", str(e)) + def test_main(): test_support.run_unittest(TestDescrTestCase, SubclassDescrTestCase, InPlaceTestCase, - DescrExceptionsTestCase) + DescrExceptionsTestCase, + GetAttrTestCase) if __name__ == '__main__': test_main() Modified: branches/asm/src/com/ziclix/python/sql/PyConnection.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/PyConnection.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/PyConnection.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -178,7 +178,7 @@ * @param name the name of the attribute of interest * @return the value for the attribute of the specified name */ - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if ("autocommit".equals(name)) { try { @@ -230,7 +230,7 @@ return Py.newBoolean(closed); } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/PyCursor.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/PyCursor.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/PyCursor.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -196,7 +196,7 @@ * @param name * @return the attribute for the given name */ - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if ("arraysize".equals(name)) { return Py.newInteger(arraysize); @@ -236,7 +236,7 @@ } catch (Throwable t) {} } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/PyExtendedCursor.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/PyExtendedCursor.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/PyExtendedCursor.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -131,7 +131,7 @@ * @param name the name of the attribute of interest * @return the value for the attribute of the specified name */ - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if ("__methods__".equals(name)) { return __methods__; @@ -139,7 +139,7 @@ return __members__; } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/PyStatement.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/PyStatement.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/PyStatement.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -161,7 +161,7 @@ * @param name * @return the attribute for the given name */ - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if ("style".equals(name)) { return Py.newInteger(style); @@ -175,7 +175,7 @@ return __members__; } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/connect/Connect.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/connect/Connect.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/connect/Connect.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -32,19 +32,11 @@ public Connect() { } - /** - * Method __findattr__ - * - * @param String name - * @return PyObject - */ - public PyObject __findattr__(String name) { - + public PyObject __findattr_ex__(String name) { if ("__doc__".equals(name)) { return _doc; } - - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/connect/Connectx.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/connect/Connectx.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/connect/Connectx.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -43,19 +43,11 @@ public Connectx() { } - /** - * Method __findattr__ - * - * @param String name - * @return PyObject - */ - public PyObject __findattr__(String name) { - + public PyObject __findattr_ex__(String name) { if ("__doc__".equals(name)) { return doc; } - - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/connect/Lookup.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/connect/Lookup.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/connect/Lookup.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -44,13 +44,13 @@ * @param name * @return PyObject */ - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if ("__doc__".equals(name)) { return _doc; } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/com/ziclix/python/sql/util/BCP.java =================================================================== --- branches/asm/src/com/ziclix/python/sql/util/BCP.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/com/ziclix/python/sql/util/BCP.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -128,7 +128,7 @@ * @param name * @return the attribute for the given name */ - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if ("destinationDataHandler".equals(name)) { return Py.java2py(this.destDH); @@ -140,7 +140,7 @@ return Py.newInteger(this.queuesize); } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/org/python/core/PyArrayDerived.java =================================================================== --- branches/asm/src/org/python/core/PyArrayDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyArrayDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyBaseException.java =================================================================== --- branches/asm/src/org/python/core/PyBaseException.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyBaseException.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -101,7 +101,7 @@ return Py.None; } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { return BaseException___findattr__(name); } @@ -113,7 +113,7 @@ } } - return super.__findattr__(name); + return super.__findattr_ex__(name); } public void __setattr__(String name, PyObject value) { Modified: branches/asm/src/org/python/core/PyBaseExceptionDerived.java =================================================================== --- branches/asm/src/org/python/core/PyBaseExceptionDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyBaseExceptionDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -948,30 +948,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyBooleanDerived.java =================================================================== --- branches/asm/src/org/python/core/PyBooleanDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyBooleanDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyClass.java =================================================================== --- branches/asm/src/org/python/core/PyClass.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyClass.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -228,7 +228,7 @@ return result[0]; } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if (name == "__dict__") { return __dict__; } @@ -245,7 +245,7 @@ PyObject[] result = lookupGivingClass(name, false); if (result[0] == null) { - return super.__findattr__(name); + return super.__findattr_ex__(name); } // xxx do we need to use result[1] (wherefound) for java cases for backw // comp? Modified: branches/asm/src/org/python/core/PyClassMethodDerived.java =================================================================== --- branches/asm/src/org/python/core/PyClassMethodDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyClassMethodDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyComplexDerived.java =================================================================== --- branches/asm/src/org/python/core/PyComplexDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyComplexDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyDictionaryDerived.java =================================================================== --- branches/asm/src/org/python/core/PyDictionaryDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyDictionaryDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyEnumerateDerived.java =================================================================== --- branches/asm/src/org/python/core/PyEnumerateDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyEnumerateDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyFileDerived.java =================================================================== --- branches/asm/src/org/python/core/PyFileDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyFileDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyFloatDerived.java =================================================================== --- branches/asm/src/org/python/core/PyFloatDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyFloatDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyFrame.java =================================================================== --- branches/asm/src/org/python/core/PyFrame.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyFrame.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -168,7 +168,7 @@ // f_exc_traceback } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if (name == "f_locals") { return getLocals(); } else if (name == "f_trace") { @@ -177,7 +177,7 @@ } return Py.None; } - return super.__findattr__(name); + return super.__findattr_ex__(name); } /** Modified: branches/asm/src/org/python/core/PyFrozenSetDerived.java =================================================================== --- branches/asm/src/org/python/core/PyFrozenSetDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyFrozenSetDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyInstance.java =================================================================== --- branches/asm/src/org/python/core/PyInstance.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyInstance.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -200,7 +200,7 @@ return __findattr__(name, true); } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { return __findattr__(name, false); } Modified: branches/asm/src/org/python/core/PyIntegerDerived.java =================================================================== --- branches/asm/src/org/python/core/PyIntegerDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyIntegerDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyJavaClass.java =================================================================== --- branches/asm/src/org/python/core/PyJavaClass.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyJavaClass.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -753,7 +753,7 @@ } private PyStringMap missingAttributes = null; - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { if (name == "__dict__") { if (__dict__ == null) initialize(); Modified: branches/asm/src/org/python/core/PyJavaPackage.java =================================================================== --- branches/asm/src/org/python/core/PyJavaPackage.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyJavaPackage.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -132,7 +132,7 @@ } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyObject ret = __dict__.__finditem__(name); if (ret != null) return ret; Modified: branches/asm/src/org/python/core/PyListDerived.java =================================================================== --- branches/asm/src/org/python/core/PyListDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyListDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyLongDerived.java =================================================================== --- branches/asm/src/org/python/core/PyLongDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyLongDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -972,30 +972,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyMethod.java =================================================================== --- branches/asm/src/org/python/core/PyMethod.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyMethod.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -55,13 +55,27 @@ } @Override - public PyObject __findattr__(String name) { - PyObject ret = super.__findattr__(name); + public PyObject __findattr_ex__(String name) { + return instancemethod___findattr_ex__(name); + } + + final PyObject instancemethod___findattr_ex__(String name) { + PyObject ret = super.__findattr_ex__(name); if (ret != null) { return ret; } - return im_func.__findattr__(name); + return im_func.__findattr_ex__(name); } + + @ExposedMethod + final PyObject instancemethod___getattribute__(PyObject arg0) { + String name = asName(arg0); + PyObject ret = instancemethod___findattr_ex__(name); + if (ret == null) { + noAttributeError(name); + } + return ret; + } @Override public PyObject __get__(PyObject obj, PyObject type) { Modified: branches/asm/src/org/python/core/PyModule.java =================================================================== --- branches/asm/src/org/python/core/PyModule.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyModule.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -128,21 +128,6 @@ return null; } - public PyObject __findattr__(String name) { - return module___findattr__(name); - } - - final PyObject module___findattr__(String name) { - if (__dict__ != null) { - PyObject attr = __dict__.__finditem__(name); - if (attr != null) { - return attr; - } - } - - return super.__findattr__(name); - } - public void __setattr__(String name, PyObject value) { module___setattr__(name, value); } Modified: branches/asm/src/org/python/core/PyModuleDerived.java =================================================================== --- branches/asm/src/org/python/core/PyModuleDerived.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyModuleDerived.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -948,30 +948,44 @@ } } - public PyObject __findattr__(String name) { + public PyObject __findattr_ex__(String name) { PyType self_type=getType(); + // TODO: We should speed this up. As the __getattribute__ slot almost never + // changes, it is a good candidate for caching, as PyClass does with + // __getattr__. See #1102. PyObject getattribute=self_type.lookup("__getattribute__"); PyString py_name=null; + PyException firstAttributeError=null; try { if (getattribute!=null) { - return getattribute.__get__(this,self_type).__call__(py_name=PyString.fromInterned(name)); + py_name=PyString.fromInterned(name); + return getattribute.__get__(this,self_type).__call__(py_name); } else { - return super.__findattr__(name); + Py.Warning(String.format("__getattribute__ not found on type %s",self_type.getName())); + PyObject ret=super.__findattr_ex__(name); + if (ret!=null) { + return ret; + } // else: pass through to __getitem__ invocation } } catch (PyException e) { - if (Py.matchException(e,Py.AttributeError)) { - PyObject getattr=self_type.lookup("__getattr__"); - if (getattr!=null) - try { - return getattr.__get__(this,self_type).__call__(py_name!=null?py_name:PyString.fromInterned(name)); - } catch (PyException e1) { - if (!Py.matchException(e1,Py.AttributeError)) - throw e1; - } - return null; + if (!Py.matchException(e,Py.AttributeError)) { + throw e; + } else { + firstAttributeError=e; // saved to avoid swallowing custom AttributeErrors + // and pass through to __getattr__ invocation. } - throw e; } + PyObject getattr=self_type.lookup("__getattr__"); + if (getattr!=null) { + if (py_name==null) { + py_name=PyString.fromInterned(name); + } + return getattr.__get__(this,self_type).__call__(py_name); + } + if (firstAttributeError!=null) { + throw firstAttributeError; + } + return null; } public void __setattr__(String name,PyObject value) { Modified: branches/asm/src/org/python/core/PyObject.java =================================================================== --- branches/asm/src/org/python/core/PyObject.java 2008-08-11 22:24:20 UTC (rev 5154) +++ branches/asm/src/org/python/core/PyObject.java 2008-08-11 23:27:27 UTC (rev 5155) @@ -734,12 +734,8 @@ * <code>__findattr__(name.internedString)</code> with the appropriate * args. * - * Classes that wish to implement __getattr__ should override this method - * instead (with the appropriate semantics. + * @param name the name to lookup in this namespace * - * @param name - * the name to lookup in this namespace - * * @return the value corresponding to name or null if name is not found */ public final PyObject __findattr__(PyString name) { @@ -758,36 +754,58 @@ * @param name the name to lookup in this namespace * <b> must be an interned string </b>. * @return the value corresponding to name or null if name is not found - * - * @see #__findattr__(PyString) **/ - public PyObject __findattr__(String name) { + public final PyObject __findattr__(String name) { + try { + return __findattr_ex__(name); + } catch (PyException exc) { + if (Py.matchException(exc, Py.AttributeError)) { + return null; + } + throw exc; + } + } + + /** + * Attribute lookup hook. If the attribute is not found, null may be + * returned or a Py.AttributeError can be thrown, whatever is more + * correct, efficient and/or convenient for the implementing cl... [truncated message content] |