diff --git a/CHANGES.rst b/CHANGES.rst index 04f0908..9bfb384 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,9 @@ 4.0.8 (Unreleased) ------------------ +- The pure-Python ``Persistent`` class no longer calls subclass's + ``__setattr__`` at instance creation time. (PR #8) + - Make it possible to delete ``_p_jar`` / ``_p_oid`` of a pure-Python ``Persistent`` object which has been removed from the jar's cache (fixes aborting a ZODB Connection that has added objects). (PR #7) diff --git a/persistent/persistence.py b/persistent/persistence.py index 7640fbd..68eeb47 100644 --- a/persistent/persistence.py +++ b/persistent/persistence.py @@ -53,11 +53,15 @@ class Persistent(object): def __new__(cls, *args, **kw): inst = super(Persistent, cls).__new__(cls) - inst.__jar = None - inst.__oid = None - inst.__serial = None - inst.__flags = None - inst.__size = 0 + # We bypass the __setattr__ implementation of this object + # at __new__ time, just like the C implementation does. This + # makes us compatible with subclasses that want to access + # properties like _p_changed in their setattr implementation + _OSA(inst, '_Persistent__jar', None) + _OSA(inst, '_Persistent__oid', None) + _OSA(inst, '_Persistent__serial', None) + _OSA(inst, '_Persistent__flags', None) + _OSA(inst, '_Persistent__size', 0) return inst # _p_jar: see IPersistent. diff --git a/persistent/tests/test_persistence.py b/persistent/tests/test_persistence.py index 9e6df10..3ce2478 100644 --- a/persistent/tests/test_persistence.py +++ b/persistent/tests/test_persistence.py @@ -1325,6 +1325,14 @@ class mixed1(alternate, self._getTargetClass()): class mixed2(self._getTargetClass(), alternate): pass + def test_setattr_in_subclass_is_not_called_creating_an_instance(self): + class subclass(self._getTargetClass()): + _v_setattr_called = False + def __setattr__(self, name, value): + object.__setattr__(self, '_v_setattr_called', True) + super(subclass,self).__setattr__(name, value) + inst = subclass() + self.assertEqual(object.__getattribute__(inst,'_v_setattr_called'), False) class PyPersistentTests(unittest.TestCase, _Persistent_Base):