New issue 2039: delattr() and del can raise TypeError when CPython would raise AttributeError https://bitbucket.org/pypy/pypy/issue/2039/delattr-and-del-can-raise-typeerror-when
Jason Madden: Given an instance whose class contains a data descriptor that does not implement `__delete__`, using `delattr()` (or `del`) on that descriptor raises `TypeError` under PyPy, but `AttributeError` under CPython. CPython (2.7 here, but the same thing happens with 3.4): ``` $ python Python 2.7.9 (default, Dec 13 2014, 15:13:49) [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> class FieldProperty(object): ... def __get__(self, inst, klass): ... if inst is None: return self ... return 42 ... def __set__(self, inst, value): ... pass ... >>> class WithProperty(object): ... field = FieldProperty() ... >>> with_property = WithProperty() >>> delattr(with_property, 'field') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: __delete__ ``` PyPy: ``` $ pypy Python 2.7.9 (9c4588d731b7, Mar 23 2015, 16:20:40) [PyPy 2.5.1 with GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>> class FieldProperty(object): .... def __get__(self, inst, klass): .... if inst is None: return self .... return 42 .... def __set__(self, inst, value): .... pass .... .... >>>> class WithProperty(object): .... field = FieldProperty() .... .... >>>> with_property = WithProperty() >>>> delattr(with_property, 'field') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'FieldProperty' object is not a descriptor with delete ``` We ran into this testing a large Zope-based application where these kind of descriptors are common. It can break code expecting to catch only `AttributeError`. As far as I can tell, the Python language spec is silent on what happens in this scenario. The closest I've found is when it gives this example in [section 3.4.2.3](https://docs.python.org/2/reference/datamodel.html#invoking-descriptors): > Instance Binding > > If binding to a new-style object instance, `a.x` is transformed into the > call: `type(a).__dict__['x'].__get__(a, type(a))`. That seems to suggest the `AttributeError` is to be expected. An `AttributeError` is also least surprising because that's what happens in both implementations when deleting a standard `@property` that doesn't specify a `__delete__`, or when deleting an attribute that just doesn't exist: PyPy, but CPython behaves the same: ``` >>>> class WithBuiltinProperty(object): .... @property .... def x(self): .... return 1 .... .... >>>> with_builtin_property = WithBuiltinProperty() >>>> delattr(with_builtin_property, 'x') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: can't delete attribute >>>> delattr(with_builtin_property, 'dne') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'WithBuiltinProperty' object has no attribute 'dne' ``` _______________________________________________ pypy-issue mailing list pypy-issue@python.org https://mail.python.org/mailman/listinfo/pypy-issue