Commit 08969fe0 authored by Kirill Smelkov's avatar Kirill Smelkov

py/deactivate vs slots: A slot variable could not be initialized at all

fe2219f4 (On deactivate release in-slots objects too) started to release
objects from slotted variables but was not careful enough while doing so: we
have to be careful while deleting as for unset variables it will raise
AttributeError:

    class C(object):
        __slots__ = ['aaa', 'unset']

        def __init__(self, aaa):
            self.aaa = 1

    c = C(111)
    del c.aaa
    del c.unset

    Traceback (most recent call last):
      File "y.py", line 9, in <module>
        del c.unset
    AttributeError: unset

Caught by preparing fix for https://github.com/zopefoundation/persistent/pull/44#issuecomment-256768600

C version already have this protection in the original fe2219f4 patch:

    +            if (PyObject_GenericSetAttr((PyObject *)self, name, NULL) < 0)
    +                /* delattr of non-set slot will raise AttributeError - we
    +                 * simply ignore. */
    +                PyErr_Clear();
parent 69633df4
......@@ -425,7 +425,12 @@ class Persistent(object):
idict.clear()
type_ = type(self)
for slotname in Persistent._slotnames(self, _v_exclude=False):
getattr(type_, slotname).__delete__(self)
try:
getattr(type_, slotname).__delete__(self)
except AttributeError:
# AttributeError means slot variable was not initialized at all -
# - we can simply skip its deletion.
pass
# Implementation detail: deactivating/invalidating
# updates the size of the cache (if we have one)
......
......@@ -1321,7 +1321,7 @@ class _Persistent_Base(object):
def test__p_invalidate_from_changed_w_slots(self):
class Derived(self._getTargetClass()):
__slots__ = ('myattr1', 'myattr2')
__slots__ = ('myattr1', 'myattr2', 'unset')
def __init__(self):
self.myattr1 = 'value1'
self.myattr2 = 'value2'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment