Commit 1a525601 authored by Tres Seaver's avatar Tres Seaver

Py3k compat:

- Bytes everywhere for OID / serials.

- Different obejct comparison semantics.

- Replace class advice 'implments' w/ 'implementer' decorator.

- Flatten 'items()' / 'keys()' iterators for testing.
parent a83f388b
...@@ -22,6 +22,11 @@ if sys.version_info[0] > 2: #pragma NO COVER ...@@ -22,6 +22,11 @@ if sys.version_info[0] > 2: #pragma NO COVER
def _u(s): def _u(s):
return s return s
def _b(s):
if isinstance(s, str):
return s.encode('unicode_escape')
return s
def _native(s): def _native(s):
if isinstance(s, bytes): if isinstance(s, bytes):
return s.decode('unicode_escape') return s.decode('unicode_escape')
...@@ -43,5 +48,7 @@ else: #pragma NO COVER ...@@ -43,5 +48,7 @@ else: #pragma NO COVER
return s.encode('unicode_escape') return s.encode('unicode_escape')
return s return s
_b = _native
PYTHON3 = False PYTHON3 = False
PYTHON2 = True PYTHON2 = True
...@@ -30,6 +30,8 @@ except ImportError: #pragma NO COVER ...@@ -30,6 +30,8 @@ except ImportError: #pragma NO COVER
STICKY = 2 STICKY = 2
OID_TYPE = SERIAL_TYPE = bytes
class IPersistent(Interface): class IPersistent(Interface):
"""Python persistent interface """Python persistent interface
......
...@@ -20,6 +20,8 @@ from persistent.interfaces import CHANGED ...@@ -20,6 +20,8 @@ from persistent.interfaces import CHANGED
from persistent.interfaces import GHOST from persistent.interfaces import GHOST
from persistent.interfaces import IPickleCache from persistent.interfaces import IPickleCache
from persistent.interfaces import STICKY from persistent.interfaces import STICKY
from persistent.interfaces import OID_TYPE
from persistent.interfaces import SERIAL_TYPE
class RingNode(object): class RingNode(object):
# 32 byte fixed size wrapper. # 32 byte fixed size wrapper.
...@@ -61,8 +63,8 @@ class PickleCache(object): ...@@ -61,8 +63,8 @@ class PickleCache(object):
def __setitem__(self, oid, value): def __setitem__(self, oid, value):
""" See IPickleCache. """ See IPickleCache.
""" """
if not isinstance(oid, str): # XXX bytes if not isinstance(oid, OID_TYPE): # XXX bytes
raise ValueError('OID must be string: %s' % oid) raise ValueError('OID must be %s: %s' % (OID_TYPE, oid))
# XXX # XXX
if oid in self.persistent_classes or oid in self.data: if oid in self.persistent_classes or oid in self.data:
if self.data[oid] is not value: if self.data[oid] is not value:
...@@ -80,7 +82,7 @@ class PickleCache(object): ...@@ -80,7 +82,7 @@ class PickleCache(object):
def __delitem__(self, oid): def __delitem__(self, oid):
""" See IPickleCache. """ See IPickleCache.
""" """
if not isinstance(oid, str): if not isinstance(oid, OID_TYPE):
raise ValueError('OID must be string: %s' % oid) raise ValueError('OID must be string: %s' % oid)
if oid in self.persistent_classes: if oid in self.persistent_classes:
del self.persistent_classes[oid] del self.persistent_classes[oid]
...@@ -189,7 +191,7 @@ class PickleCache(object): ...@@ -189,7 +191,7 @@ class PickleCache(object):
def reify(self, to_reify): def reify(self, to_reify):
""" See IPickleCache. """ See IPickleCache.
""" """
if isinstance(to_reify, str): #bytes if isinstance(to_reify, OID_TYPE): #bytes
to_reify = [to_reify] to_reify = [to_reify]
for oid in to_reify: for oid in to_reify:
value = self[oid] value = self[oid]
......
...@@ -20,12 +20,12 @@ from persistent.interfaces import GHOST ...@@ -20,12 +20,12 @@ from persistent.interfaces import GHOST
from persistent.interfaces import UPTODATE from persistent.interfaces import UPTODATE
from persistent.interfaces import CHANGED from persistent.interfaces import CHANGED
from persistent.interfaces import STICKY from persistent.interfaces import STICKY
from persistent.interfaces import OID_TYPE
from persistent.interfaces import SERIAL_TYPE
from persistent.timestamp import TimeStamp from persistent.timestamp import TimeStamp
from persistent.timestamp import _ZERO from persistent.timestamp import _ZERO
from persistent._compat import copy_reg from persistent._compat import copy_reg
OID_TYPE = SERIAL_TYPE = bytes
_INITIAL_SERIAL = _ZERO _INITIAL_SERIAL = _ZERO
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# Example objects for pickling. # Example objects for pickling.
from persistent import Persistent from persistent import Persistent
from persistent._compat import PYTHON2
def print_dict(d): def print_dict(d):
...@@ -27,9 +28,14 @@ def cmpattrs(self, other, *attrs): ...@@ -27,9 +28,14 @@ def cmpattrs(self, other, *attrs):
for attr in attrs: for attr in attrs:
if attr[:3] in ('_v_', '_p_'): if attr[:3] in ('_v_', '_p_'):
continue continue
c = cmp(getattr(self, attr, None), getattr(other, attr, None)) lhs, rhs = getattr(self, attr, None), getattr(other, attr, None)
if c: if PYTHON2:
return c c = cmp(lhs, rhs)
if c:
return c
else:
if lhs != rhs:
return 1
return 0 return 0
class Simple(Persistent): class Simple(Persistent):
...@@ -39,8 +45,13 @@ class Simple(Persistent): ...@@ -39,8 +45,13 @@ class Simple(Persistent):
self._v_favorite_color = 'blue' self._v_favorite_color = 'blue'
self._p_foo = 'bar' self._p_foo = 'bar'
def __cmp__(self, other): @property
return cmpattrs(self, other, '__class__', *(self.__dict__.keys())) def _attrs(self):
return list(self.__dict__.keys())
def __eq__(self, other):
return cmpattrs(self, other, '__class__', *self._attrs) == 0
class Custom(Simple): class Custom(Simple):
...@@ -71,6 +82,13 @@ class Slotted(Persistent): ...@@ -71,6 +82,13 @@ class Slotted(Persistent):
self._v_eek = 1 self._v_eek = 1
self._p_splat = 2 self._p_splat = 2
@property
def _attrs(self):
return list(self.__dict__.keys())
def __eq__(self, other):
return cmpattrs(self, other, '__class__', *self._attrs) == 0
class SubSlotted(Slotted): class SubSlotted(Slotted):
...@@ -80,8 +98,9 @@ class SubSlotted(Slotted): ...@@ -80,8 +98,9 @@ class SubSlotted(Slotted):
Slotted.__init__(self, s1, s2) Slotted.__init__(self, s1, s2)
self.s3 = s3 self.s3 = s3
def __cmp__(self, other): @property
return cmpattrs(self, other, '__class__', 's1', 's2', 's3', 's4') def _attrs(self):
return ('s1', 's2', 's3', 's4')
class SubSubSlotted(SubSlotted): class SubSubSlotted(SubSlotted):
...@@ -92,7 +111,6 @@ class SubSubSlotted(SubSlotted): ...@@ -92,7 +111,6 @@ class SubSubSlotted(SubSlotted):
self._v_favorite_color = 'blue' self._v_favorite_color = 'blue'
self._p_foo = 'bar' self._p_foo = 'bar'
def __cmp__(self, other): @property
return cmpattrs(self, other, def _attrs(self):
'__class__', 's1', 's2', 's3', 's4', return ['s1', 's2', 's3', 's4'] + list(self.__dict__.keys())
*(self.__dict__.keys()))
...@@ -34,7 +34,8 @@ class PersistenceTest(unittest.TestCase): ...@@ -34,7 +34,8 @@ class PersistenceTest(unittest.TestCase):
self.assertEqual(obj._p_oid, None) self.assertEqual(obj._p_oid, None)
def test_oid_mutable_and_deletable_when_no_jar(self): def test_oid_mutable_and_deletable_when_no_jar(self):
OID = '\x01' * 8 from persistent._compat import _b
OID = _b('\x01' * 8)
obj = self._makeOne() obj = self._makeOne()
obj._p_oid = OID obj._p_oid = OID
self.assertEqual(obj._p_oid, OID) self.assertEqual(obj._p_oid, OID)
...@@ -42,7 +43,8 @@ class PersistenceTest(unittest.TestCase): ...@@ -42,7 +43,8 @@ class PersistenceTest(unittest.TestCase):
self.assertEqual(obj._p_oid, None) self.assertEqual(obj._p_oid, None)
def test_oid_immutable_when_in_jar(self): def test_oid_immutable_when_in_jar(self):
OID = '\x01' * 8 from persistent._compat import _b
OID = _b('\x01' * 8)
obj = self._makeOne() obj = self._makeOne()
jar = self._makeJar() jar = self._makeJar()
jar.add(obj) jar.add(obj)
...@@ -185,9 +187,9 @@ class PersistenceTest(unittest.TestCase): ...@@ -185,9 +187,9 @@ class PersistenceTest(unittest.TestCase):
self.assertEqual(obj._p_state, GHOST) self.assertEqual(obj._p_state, GHOST)
def test_initial_serial(self): def test_initial_serial(self):
NOSERIAL = "\000" * 8 from persistent.timestamp import _ZERO
obj = self._makeOne() obj = self._makeOne()
self.assertEqual(obj._p_serial, NOSERIAL) self.assertEqual(obj._p_serial, _ZERO)
def test_setting_serial_w_invalid_types_raises(self): def test_setting_serial_w_invalid_types_raises(self):
# Serial must be an 8-digit string # Serial must be an 8-digit string
...@@ -203,11 +205,12 @@ class PersistenceTest(unittest.TestCase): ...@@ -203,11 +205,12 @@ class PersistenceTest(unittest.TestCase):
self.assertRaises(ValueError, set, _u("01234567")) self.assertRaises(ValueError, set, _u("01234567"))
def test_del_serial_returns_to_initial(self): def test_del_serial_returns_to_initial(self):
NOSERIAL = "\000" * 8 from persistent.timestamp import _ZERO
from persistent._compat import _b
obj = self._makeOne() obj = self._makeOne()
obj._p_serial = "01234567" obj._p_serial = _b("01234567")
del obj._p_serial del obj._p_serial
self.assertEqual(obj._p_serial, NOSERIAL) self.assertEqual(obj._p_serial, _ZERO)
def test_initial_mtime(self): def test_initial_mtime(self):
obj = self._makeOne() obj = self._makeOne()
......
...@@ -181,14 +181,14 @@ class PersistentMappingTests(unittest.TestCase): ...@@ -181,14 +181,14 @@ class PersistentMappingTests(unittest.TestCase):
except KeyError: except KeyError:
pass pass
else: else:
raise TestFailed("1 should not be poppable from u2") self.fail("1 should not be poppable from u2")
x = u2.pop(1, 7) x = u2.pop(1, 7)
eq(x, 7, "u2.pop(1, 7) == 7") eq(x, 7, "u2.pop(1, 7) == 7")
# Test popitem # Test popitem
items = u2.items() items = list(u2.items())
key, value = u2.popitem() key, value = u2.popitem()
self.failUnless((key, value) in items, "key, value in items") self.failUnless((key, value) in items, "key, value in items")
self.failUnless(key not in u2, "key not in u2") self.failUnless(key not in u2, "key not in u2")
......
...@@ -19,11 +19,11 @@ class _Persistent_Base(object): ...@@ -19,11 +19,11 @@ class _Persistent_Base(object):
return self._getTargetClass()(*args, **kw) return self._getTargetClass()(*args, **kw)
def _makeJar(self): def _makeJar(self):
from zope.interface import implements from zope.interface import implementer
from persistent.interfaces import IPersistentDataManager from persistent.interfaces import IPersistentDataManager
@implementer(IPersistentDataManager)
class _Jar(object): class _Jar(object):
implements(IPersistentDataManager)
def __init__(self): def __init__(self):
self._loaded = [] self._loaded = []
self._registered = [] self._registered = []
......
This diff is collapsed.
...@@ -177,23 +177,30 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase): ...@@ -177,23 +177,30 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase):
def test___setstate___empty(self): def test___setstate___empty(self):
from persistent.wref import WeakRef from persistent.wref import WeakRef
from persistent._compat import _b
jar = _makeJar() jar = _makeJar()
key = jar['key'] = _makeTarget(oid='KEY') KEY = _b('KEY')
KEY2 = _b('KEY2')
KEY3 = _b('KEY3')
VALUE = _b('VALUE')
VALUE2 = _b('VALUE2')
VALUE3 = _b('VALUE3')
key = jar[KEY] = _makeTarget(oid=KEY)
key._p_jar = jar key._p_jar = jar
kref = WeakRef(key) kref = WeakRef(key)
value = jar['value'] = _makeTarget(oid='VALUE') value = jar[VALUE] = _makeTarget(oid=VALUE)
value._p_jar = jar value._p_jar = jar
key2 = _makeTarget(oid='KEY2') key2 = _makeTarget(oid=KEY2)
key2._p_jar = jar # not findable key2._p_jar = jar # not findable
kref2 = WeakRef(key2) kref2 = WeakRef(key2)
del kref2._v_ob # force a miss del kref2._v_ob # force a miss
value2 = jar['value2'] = _makeTarget(oid='VALUE2') value2 = jar[VALUE2] = _makeTarget(oid=VALUE2)
value2._p_jar = jar value2._p_jar = jar
key3 = jar['KEY3'] = _makeTarget(oid='KEY3') # findable key3 = jar[KEY3] = _makeTarget(oid=KEY3) # findable
key3._p_jar = jar key3._p_jar = jar
kref3 = WeakRef(key3) kref3 = WeakRef(key3)
del kref3._v_ob # force a miss, but win in the lookup del kref3._v_ob # force a miss, but win in the lookup
value3 = jar['value3'] = _makeTarget(oid='VALUE3') value3 = jar[VALUE3] = _makeTarget(oid=VALUE3)
value3._p_jar = jar value3._p_jar = jar
pwkd = self._makeOne(None) pwkd = self._makeOne(None)
pwkd.__setstate__({'data': pwkd.__setstate__({'data':
...@@ -308,6 +315,7 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase): ...@@ -308,6 +315,7 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase):
def _makeTarget(oid='OID', **kw): def _makeTarget(oid='OID', **kw):
from persistent import Persistent from persistent import Persistent
from persistent._compat import _b
class Derived(Persistent): class Derived(Persistent):
def __hash__(self): def __hash__(self):
return hash(self._p_oid) return hash(self._p_oid)
...@@ -318,7 +326,7 @@ def _makeTarget(oid='OID', **kw): ...@@ -318,7 +326,7 @@ def _makeTarget(oid='OID', **kw):
derived = Derived() derived = Derived()
for k, v in kw.items(): for k, v in kw.items():
setattr(derived, k, v) setattr(derived, k, v)
derived._p_oid = oid derived._p_oid = _b(oid)
return derived return derived
def _makeJar(): def _makeJar():
......
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