[Zodb-checkins] SVN: ZODB/branches/tseaver-python_picklecache-2/src/persistent/ Add more methods from the C class.
Tres Seaver
tseaver at palladion.com
Tue Feb 15 17:08:26 EST 2011
Log message for revision 120358:
Add more methods from the C class.
Changed:
U ZODB/branches/tseaver-python_picklecache-2/src/persistent/pypersistent.py
U ZODB/branches/tseaver-python_picklecache-2/src/persistent/tests/test_pypersistent.py
-=-
Modified: ZODB/branches/tseaver-python_picklecache-2/src/persistent/pypersistent.py
===================================================================
--- ZODB/branches/tseaver-python_picklecache-2/src/persistent/pypersistent.py 2011-02-15 19:13:38 UTC (rev 120357)
+++ ZODB/branches/tseaver-python_picklecache-2/src/persistent/pypersistent.py 2011-02-15 22:08:25 UTC (rev 120358)
@@ -36,6 +36,14 @@
CHANGED = 1
STICKY = 2
+# These names can be used from a ghost without causing it to be activated.
+SPECIAL_NAMES = ('__class__',
+ '__del__',
+ '__dict__',
+ '__of__',
+ '__setstate__'
+ )
+
_SCONV = 60.0 / (1<<16) / (1<<16)
def makeTimestamp(year, month, day, hour, minute, second):
@@ -54,7 +62,10 @@
second = b * _SCONV
return (year, month, day, hour, minute, second)
+
class Persistent(object):
+ """ Pure Python implmentation of Persistent base class
+ """
__slots__ = ('__jar', '__oid', '__serial', '__flags')
implements(IPersistent)
@@ -201,12 +212,12 @@
def __getstate__(self):
""" See IPersistent.
"""
- return {}
+ return ()
def __setstate__(self, state):
""" See IPersistent.
"""
- if state != {}:
+ if state != ():
raise ValueError('No state allowed on base Persistent class')
def _p_activate(self):
@@ -230,6 +241,65 @@
raise ValueError('Sticky')
self.__flags = None
+ # Methods defined in C, not part of IPersistent
+ def _p_getattr(self, name):
+ """\
+ _p_getattr(name) -- Test whether the base class must handle the name
+
+ The method unghostifies the object, if necessary.
+ The method records the object access, if necessary.
+
+ This method should be called by subclass __getattribute__
+ implementations before doing anything else. If the method
+ returns True, then __getattribute__ implementations must delegate
+ to the base class, Persistent.
+ """
+ if name.startswith('_p_') or name in SPECIAL_NAMES:
+ return True
+ self._p_activate()
+ # TODO set the object as acceessed with the jar's cache.
+ return False
+
+ def _p_setattr(self, name, value):
+ """_p_setattr(name, value) -- Save persistent meta data
+
+ This method should be called by subclass __setattr__ implementations
+ before doing anything else. If it returns true, then the attribute
+ was handled by the base class.
+
+ The method unghostifies the object, if necessary.
+ The method records the object access, if necessary.
+ """
+ if name.startswith('_p_'):
+ setattr(self, name, value)
+ return True
+ self._p_activate()
+ # TODO set the object as acceessed with the jar's cache.
+ return False
+
+ def _p_delattr(self, name):
+ """_p_delattr(name) -- Delete persistent meta data
+
+ This method should be called by subclass __delattr__ implementations
+ before doing anything else. If it returns true, then the attribute
+ was handled by the base class.
+
+ The method unghostifies the object, if necessary.
+ The method records the object access, if necessary.
+ """
+ if name.startswith('_p_'):
+ delattr(self, name)
+ return True
+ self._p_activate()
+ # TODO set the object as acceessed with the jar's cache.
+ return False
+
+ def __reduce__(self):
+ """Reduce an object to contituent parts for serialization.
+ """
+ gna = getattr(self, '__getnewargs__', lambda: ())
+ return ((type(self),) + gna(), self.__getstate__())
+
# Helper methods: not APIs
def _register(self):
if self.__jar is not None and self.__oid is not None:
Modified: ZODB/branches/tseaver-python_picklecache-2/src/persistent/tests/test_pypersistent.py
===================================================================
--- ZODB/branches/tseaver-python_picklecache-2/src/persistent/tests/test_pypersistent.py 2011-02-15 19:13:38 UTC (rev 120357)
+++ ZODB/branches/tseaver-python_picklecache-2/src/persistent/tests/test_pypersistent.py 2011-02-15 22:08:25 UTC (rev 120358)
@@ -36,7 +36,7 @@
self._registered.append(obj._p_oid)
return _Jar()
- def _makeOneWithJar(self, *args, **kw):
+ def _makeOneWithJar(self):
OID = '1' * 8
inst = self._makeOne()
jar = self._makeJar()
@@ -421,11 +421,11 @@
def test___getstate__(self):
inst = self._makeOne()
- self.assertEqual(inst.__getstate__(), {})
+ self.assertEqual(inst.__getstate__(), ())
def test___setstate___empty(self):
inst = self._makeOne()
- inst.__setstate__({}) # doesn't raise, but doesn't change anything
+ inst.__setstate__(()) # doesn't raise, but doesn't change anything
def test___setstate___nonempty(self):
inst = self._makeOne()
@@ -543,3 +543,77 @@
inst._p_changed = False
inst._p_sticky = True
self.assertRaises(ValueError, inst._p_invalidate)
+
+ def test__p_getattr_w__p__name(self):
+ inst, jar, OID = self._makeOneWithJar()
+ self.failUnless(inst._p_getattr('_p_foo'))
+ self.assertEqual(inst._p_status, 'ghost')
+ self.assertEqual(list(jar._loaded), [])
+
+ def test__p_getattr_w_special_names(self):
+ from persistent.pypersistent import SPECIAL_NAMES
+ inst, jar, OID = self._makeOneWithJar()
+ for name in SPECIAL_NAMES:
+ self.failUnless(inst._p_getattr(name))
+ self.assertEqual(inst._p_status, 'ghost')
+ self.assertEqual(list(jar._loaded), [])
+
+ def test__p_getattr_w_normal_name(self):
+ inst, jar, OID = self._makeOneWithJar()
+ self.failIf(inst._p_getattr('normal'))
+ self.assertEqual(inst._p_status, 'saved')
+ self.assertEqual(list(jar._loaded), [OID])
+
+ def test__p_setattr_w__p__name(self):
+ inst, jar, OID = self._makeOneWithJar()
+ self.failUnless(inst._p_setattr('_p_serial', '1' * 8))
+ self.assertEqual(inst._p_status, 'ghost')
+ self.assertEqual(inst._p_serial, '1' * 8)
+ self.assertEqual(list(jar._loaded), [])
+
+ def test__p_setattr_w_normal_name(self):
+ inst, jar, OID = self._makeOneWithJar()
+ self.failIf(inst._p_setattr('normal', 'value'))
+ self.assertEqual(inst._p_status, 'saved')
+ self.assertEqual(list(jar._loaded), [OID])
+
+ def test__p_delattr_w__p__name(self):
+ inst, jar, OID = self._makeOneWithJar()
+ inst._p_changed = True
+ jar._loaded = []
+ self.failUnless(inst._p_delattr('_p_changed'))
+ self.assertEqual(inst._p_status, 'ghost')
+ self.assertEqual(inst._p_changed, None)
+ self.assertEqual(list(jar._loaded), [])
+
+ def test__p_delattr_w_normal_name(self):
+ inst, jar, OID = self._makeOneWithJar()
+ self.failIf(inst._p_delattr('normal'))
+ self.assertEqual(inst._p_status, 'saved')
+ self.assertEqual(list(jar._loaded), [OID])
+
+ def test___reduce__(self):
+ inst = self._makeOne()
+ first, second = inst.__reduce__()
+ self.assertEqual(first, (self._getTargetClass(),))
+ self.assertEqual(second, ())
+
+ def test___reduce__w_subclass_having_getstate(self):
+ class Derived(self._getTargetClass()):
+ def __getstate__(self):
+ return {}
+ inst = Derived()
+ first, second = inst.__reduce__()
+ self.assertEqual(first, (Derived,))
+ self.assertEqual(second, {})
+
+ def test___reduce__w_subclass_having_gna_and_getstate(self):
+ class Derived(self._getTargetClass()):
+ def __getnewargs__(self):
+ return ('a', 'b')
+ def __getstate__(self):
+ return {'foo': 'bar'}
+ inst = Derived()
+ first, second = inst.__reduce__()
+ self.assertEqual(first, (Derived, 'a', 'b'))
+ self.assertEqual(second, {'foo': 'bar'})
More information about the Zodb-checkins
mailing list