From: <pj...@us...> - 2010-04-09 03:22:01
|
Revision: 7007 http://jython.svn.sourceforge.net/jython/?rev=7007&view=rev Author: pjenvey Date: 2010-04-09 03:21:55 +0000 (Fri, 09 Apr 2010) Log Message: ----------- fix an incompat. with CPython: allow data descriptors without a __get__ to override themselves in the instance dict fixes #1534 Modified Paths: -------------- trunk/jython/Lib/test/test_descr_jy.py trunk/jython/NEWS trunk/jython/src/org/python/core/PyJavaType.java trunk/jython/src/org/python/core/PyObject.java trunk/jython/src/org/python/core/PyType.java trunk/jython/src/org/python/expose/generate/DescriptorExposer.java Modified: trunk/jython/Lib/test/test_descr_jy.py =================================================================== --- trunk/jython/Lib/test/test_descr_jy.py 2010-04-09 03:01:56 UTC (rev 7006) +++ trunk/jython/Lib/test/test_descr_jy.py 2010-04-09 03:21:55 UTC (rev 7007) @@ -97,7 +97,25 @@ except AttributeError, e: self.assertEquals("Custom message", str(e)) + def test_set_without_get(self): + class Descr(object): + def __init__(self, name): + self.name = name + + def __set__(self, obj, value): + obj.__dict__[self.name] = value + descr = Descr("a") + + class X(object): + a = descr + + x = X() + self.assertTrue(x.a is descr) + x.a = 42 + self.assertEqual(x.a, 42) + + class SubclassDescrTestCase(unittest.TestCase): def test_subclass_cmp_right_op(self): Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2010-04-09 03:01:56 UTC (rev 7006) +++ trunk/jython/NEWS 2010-04-09 03:21:55 UTC (rev 7007) @@ -24,6 +24,7 @@ - [ 1566 ] os.popen(cmd).read() returns `\r\n` as newline on Windows with Jython 2.5 - [ 1517 ] TypeError: get_referrers - [ 1502 ] string-escape codec incorrect + - [ 1534 ] new style object __dict__[name] ignored - Fix runtime issues during exitfuncs triggered via SystemRestart (such as during Django or Pylons development mode reloading) - Fix pickling of collections.defaultdict objects Modified: trunk/jython/src/org/python/core/PyJavaType.java =================================================================== --- trunk/jython/src/org/python/core/PyJavaType.java 2010-04-09 03:01:56 UTC (rev 7006) +++ trunk/jython/src/org/python/core/PyJavaType.java 2010-04-09 03:21:55 UTC (rev 7007) @@ -507,9 +507,12 @@ } } if (baseClass != Object.class) { - has_set = getDescrMethod(forClass, "__set__", OO) != null + hasGet = getDescrMethod(forClass, "__get__", OO) != null + || getDescrMethod(forClass, "_doget", PyObject.class) != null + || getDescrMethod(forClass, "_doget", OO) != null; + hasSet = getDescrMethod(forClass, "__set__", OO) != null || getDescrMethod(forClass, "_doset", OO) != null; - has_delete = getDescrMethod(forClass, "__delete__", PyObject.class) != null + hasDelete = getDescrMethod(forClass, "__delete__", PyObject.class) != null || getDescrMethod(forClass, "_dodel", PyObject.class) != null; } if (forClass == Object.class) { Modified: trunk/jython/src/org/python/core/PyObject.java =================================================================== --- trunk/jython/src/org/python/core/PyObject.java 2010-04-09 03:01:56 UTC (rev 7006) +++ trunk/jython/src/org/python/core/PyObject.java 2010-04-09 03:21:55 UTC (rev 7007) @@ -3639,22 +3639,22 @@ throw Py.TypeError("can't delete attribute '__dict__' of instance of '" + getType().fastGetName()+ "'"); } + public boolean implementsDescrGet() { + return objtype.hasGet; + } + public boolean implementsDescrSet() { - return objtype.has_set; + return objtype.hasSet; } public boolean implementsDescrDelete() { - return objtype.has_delete; + return objtype.hasDelete; } - public boolean isDataDescr() { // implements either __set__ or __delete__ - return objtype.has_set || objtype.has_delete; + public boolean isDataDescr() { + return objtype.hasSet || objtype.hasDelete; } - // doc & xxx ok this way? - // can return null meaning set-only or throw exception - - // backward comp impls. /** * Get descriptor for this PyObject. * @@ -3685,8 +3685,9 @@ final PyObject object___getattribute__(PyObject arg0) { String name = asName(arg0); PyObject ret = object___findattr__(name); - if(ret == null) + if (ret == null) { noAttributeError(name); + } return ret; } @@ -3694,26 +3695,31 @@ final PyObject object___findattr__(String name) { PyObject descr = objtype.lookup(name); PyObject res; + boolean get = false; if (descr != null) { - if (descr.isDataDescr()) { - res = descr.__get__(this, objtype); - if (res != null) - return res; + get = descr.implementsDescrGet(); + if (get && descr.isDataDescr()) { + return descr.__get__(this, objtype); } } PyObject obj_dict = fastGetDict(); if (obj_dict != null) { res = obj_dict.__finditem__(name); - if (res != null) + if (res != null) { return res; + } } - if (descr != null) { + if (get) { return descr.__get__(this, objtype); } + if (descr != null) { + return descr; + } + return null; } @@ -3783,10 +3789,11 @@ try { obj_dict.__delitem__(name); } catch (PyException exc) { - if (exc.match(Py.KeyError)) + if (exc.match(Py.KeyError)) { noAttributeError(name); - else + } else { throw exc; + } } return; } Modified: trunk/jython/src/org/python/core/PyType.java =================================================================== --- trunk/jython/src/org/python/core/PyType.java 2010-04-09 03:01:56 UTC (rev 7006) +++ trunk/jython/src/org/python/core/PyType.java 2010-04-09 03:21:55 UTC (rev 7007) @@ -63,9 +63,10 @@ /** Whether new instances of this type can be instantiated */ protected boolean instantiable = true; - /** Whether this type has set/delete descriptors */ - boolean has_set; - boolean has_delete; + /** Whether this type implements descriptor __get/set/delete__ methods. */ + boolean hasGet; + boolean hasSet; + boolean hasDelete; /** Whether this type allows subclassing. */ private boolean isBaseType = true; @@ -294,6 +295,11 @@ String doc = "dictionary for instance variables (if defined)"; dict.__setitem__("__dict__", new PyDataDescr(this, "__dict__", PyObject.class, doc) { @Override + public boolean implementsDescrGet() { + return true; + } + + @Override public Object invokeGet(PyObject obj) { return obj.getDict(); } @@ -336,6 +342,11 @@ } @Override + public boolean implementsDescrGet() { + return true; + } + + @Override public Object invokeGet(PyObject obj) { PyList weakrefs = WeakrefModule.getweakrefs(obj); switch (weakrefs.size()) { @@ -391,7 +402,7 @@ // Calculate method resolution order mro_internal(); - fillHasSetAndDelete(); + cacheDescrBinds(); } /** @@ -498,7 +509,7 @@ setIsBaseType(builder.getIsBaseType()); needs_userdict = dict.__finditem__("__dict__") != null; instantiable = dict.__finditem__("__new__") != null; - fillHasSetAndDelete(); + cacheDescrBinds(); } /** @@ -513,9 +524,14 @@ bases = new PyObject[] {base}; } - private void fillHasSetAndDelete() { - has_set = lookup_mro("__set__") != null; - has_delete = lookup_mro("__delete__") != null; + + /** + * Determine if this type is a descriptor, and if so what kind. + */ + private void cacheDescrBinds() { + hasGet = lookup_mro("__get__") != null; + hasSet = lookup_mro("__set__") != null; + hasDelete = lookup_mro("__delete__") != null; } public PyObject getStatic() { @@ -1298,11 +1314,12 @@ // name must be interned final PyObject type___findattr_ex__(String name) { PyType metatype = getType(); - PyObject metaattr = metatype.lookup(name); + boolean get = false; - if (metaattr != null && useMetatypeFirst(metaattr)) { - if (metaattr.isDataDescr()) { + if (metaattr != null) { + get = metaattr.implementsDescrGet(); + if (useMetatypeFirst(metaattr) && get && metaattr.isDataDescr()) { PyObject res = metaattr.__get__(this, metatype); if (res != null) return res; @@ -1318,10 +1335,14 @@ } } - if (metaattr != null) { + if (get) { return metaattr.__get__(this, metatype); } + if (metaattr != null) { + return metaattr; + } + return null; } @@ -1369,22 +1390,32 @@ void postSetattr(String name) { invalidateMethodCache(); - if (name == "__set__") { - if (!has_set && lookup("__set__") != null) { + if (name == "__get__") { + if (!hasGet && lookup("__get__") != null) { traverse_hierarchy(false, new OnType() { public boolean onType(PyType type) { - boolean old = type.has_set; - type.has_set = true; + boolean old = type.hasGet; + type.hasGet = true; return old; } }); } + } else if (name == "__set__") { + if (!hasSet && lookup("__set__") != null) { + traverse_hierarchy(false, new OnType() { + public boolean onType(PyType type) { + boolean old = type.hasSet; + type.hasSet = true; + return old; + } + }); + } } else if (name == "__delete__") { - if (!has_delete && lookup("__delete__") != null) { + if (!hasDelete && lookup("__delete__") != null) { traverse_hierarchy(false, new OnType() { public boolean onType(PyType type) { - boolean old = type.has_delete; - type.has_delete = true; + boolean old = type.hasDelete; + type.hasDelete = true; return old; } }); @@ -1421,13 +1452,26 @@ void postDelattr(String name) { invalidateMethodCache(); - if (name == "__set__") { - if (has_set && lookup("__set__") == null) { + if (name == "__get__") { + if (hasGet && lookup("__get__") == null) { traverse_hierarchy(false, new OnType() { public boolean onType(PyType type) { + boolean absent = type.getDict().__finditem__("__get__") == null; + if (absent) { + type.hasGet = false; + return false; + } + return true; + } + }); + } + } else if (name == "__set__") { + if (hasSet && lookup("__set__") == null) { + traverse_hierarchy(false, new OnType() { + public boolean onType(PyType type) { boolean absent = type.getDict().__finditem__("__set__") == null; if (absent) { - type.has_set = false; + type.hasSet = false; return false; } return true; @@ -1435,12 +1479,12 @@ }); } } else if (name == "__delete__") { - if (has_delete && lookup("__delete__") == null) { + if (hasDelete && lookup("__delete__") == null) { traverse_hierarchy(false, new OnType() { public boolean onType(PyType type) { boolean absent = type.getDict().__finditem__("__delete__") == null; if (absent) { - type.has_delete = false; + type.hasDelete = false; return false; } return true; Modified: trunk/jython/src/org/python/expose/generate/DescriptorExposer.java =================================================================== --- trunk/jython/src/org/python/expose/generate/DescriptorExposer.java 2010-04-09 03:01:56 UTC (rev 7006) +++ trunk/jython/src/org/python/expose/generate/DescriptorExposer.java 2010-04-09 03:21:55 UTC (rev 7007) @@ -121,6 +121,7 @@ } else { generateFieldGetter(); } + generateImplement("Get", getterMethodName != null || getterFieldName != null); if(setterMethodName != null) { generateMethodSetter(); } else if(setterFieldName != null) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |