Commit 5f4f6d4f authored by Tres Seaver's avatar Tres Seaver

Begin Py3k compatiility.

parent 90fc145a
...@@ -6,3 +6,4 @@ nosetests.xml ...@@ -6,3 +6,4 @@ nosetests.xml
coverage.xml coverage.xml
*.egg *.egg
docs/_build docs/_build
__pycache__
...@@ -21,6 +21,9 @@ from struct import error as struct_error ...@@ -21,6 +21,9 @@ from struct import error as struct_error
from persistent import Persistent from persistent import Persistent
from .Interfaces import BTreesConflictError from .Interfaces import BTreesConflictError
from ._compat import cmp
from ._compat import int_types
from ._compat import xrange
_marker = object() _marker = object()
...@@ -298,7 +301,7 @@ class Bucket(_BucketBase): ...@@ -298,7 +301,7 @@ class Bucket(_BucketBase):
def _split(self, index=-1): def _split(self, index=-1):
if index < 0 or index >= len(self._keys): if index < 0 or index >= len(self._keys):
index = len(self._keys) / 2 index = len(self._keys) // 2
new_instance = self.__class__() new_instance = self.__class__()
new_instance._keys = self._keys[index:] new_instance._keys = self._keys[index:]
new_instance._values = self._values[index:] new_instance._values = self._values[index:]
...@@ -553,7 +556,7 @@ class Set(_BucketBase): ...@@ -553,7 +556,7 @@ class Set(_BucketBase):
def _split(self, index=-1): def _split(self, index=-1):
if index < 0 or index >= len(self._keys): if index < 0 or index >= len(self._keys):
index = len(self._keys) / 2 index = len(self._keys) // 2
new_instance = self.__class__() new_instance = self.__class__()
new_instance._keys = self._keys[index:] new_instance._keys = self._keys[index:]
del self._keys[index:] del self._keys[index:]
...@@ -760,7 +763,7 @@ class _Tree(_Base): ...@@ -760,7 +763,7 @@ class _Tree(_Base):
if data: if data:
lo = 0 lo = 0
hi = len(data) hi = len(data)
i = hi//2 i = hi // 2
while i > lo: while i > lo:
cmp_ = cmp(data[i].key, key) cmp_ = cmp(data[i].key, key)
if cmp_ < 0: if cmp_ < 0:
...@@ -769,7 +772,7 @@ class _Tree(_Base): ...@@ -769,7 +772,7 @@ class _Tree(_Base):
hi = i hi = i
else: else:
break break
i = (lo+hi)//2 i = (lo + hi) // 2
return i return i
return -1 return -1
...@@ -882,7 +885,7 @@ class _Tree(_Base): ...@@ -882,7 +885,7 @@ class _Tree(_Base):
def _split(self, index=None): def _split(self, index=None):
data = self._data data = self._data
if index is None: if index is None:
index = len(data)//2 index = len(data) // 2
next = self.__class__() next = self.__class__()
next._data = data[index:] next._data = data[index:]
...@@ -1384,7 +1387,6 @@ def multiunion(set_type, seqs): ...@@ -1384,7 +1387,6 @@ def multiunion(set_type, seqs):
def to_ob(self, v): def to_ob(self, v):
return v return v
int_types = int, long
def to_int(self, v): def to_int(self, v):
try: try:
# XXX Python 2.6 doesn't truncate, it spews a warning. # XXX Python 2.6 doesn't truncate, it spews a warning.
......
##############################################################################
#
# Copyright (c) 2001-2012 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import sys
if sys.version_info[0] < 3: #pragma NO COVER Python2
from StringIO import StringIO
BytesIO = StringIO
int_types = int, long
xrange = xrange
cmp = cmp
_bytes = str
def _u(s, encoding='unicode_escape'):
return unicode(s, encoding)
else: #pragma NO COVER Python3
from io import StringIO
from io import BytesIO
int_types = int,
xrange = range
def cmp(x, y):
return (x > y) - (y > x)
_bytes = bytes
def _u(s, encoding=None):
if encoding is None:
return s
return str(s, encoding)
...@@ -378,30 +378,30 @@ class Printer(Walker): #pragma NO COVER ...@@ -378,30 +378,30 @@ class Printer(Walker): #pragma NO COVER
def visit_btree(self, obj, path, parent, is_mapping, def visit_btree(self, obj, path, parent, is_mapping,
keys, kids, lo, hi): keys, kids, lo, hi):
indent = " " * len(path) indent = " " * len(path)
print "%s%s %s with %d children" % ( print("%s%s %s with %d children" % (
indent, indent,
".".join(map(str, path)), ".".join(map(str, path)),
type_and_adr(obj), type_and_adr(obj),
len(kids)) len(kids)))
indent += " " indent += " "
n = len(keys) n = len(keys)
for i in range(n): for i in range(n):
print "%skey %d: %r" % (indent, i, keys[i]) print("%skey %d: %r" % (indent, i, keys[i]))
def visit_bucket(self, obj, path, parent, is_mapping, def visit_bucket(self, obj, path, parent, is_mapping,
keys, values, lo, hi): keys, values, lo, hi):
indent = " " * len(path) indent = " " * len(path)
print "%s%s %s with %d keys" % ( print("%s%s %s with %d keys" % (
indent, indent,
".".join(map(str, path)), ".".join(map(str, path)),
type_and_adr(obj), type_and_adr(obj),
len(keys)) len(keys)))
indent += " " indent += " "
n = len(keys) n = len(keys)
for i in range(n): for i in range(n):
print "%skey %d: %r" % (indent, i, keys[i]), print("%skey %d: %r" % (indent, i, keys[i]),)
if is_mapping: if is_mapping:
print "value %r" % (values[i],) print("value %r" % (values[i],))
def check(btree): def check(btree):
"""Check internal value-based invariants in a BTree or TreeSet. """Check internal value-based invariants in a BTree or TreeSet.
......
...@@ -22,6 +22,16 @@ def _skip_wo_ZODB(test_method): #pragma NO COVER ...@@ -22,6 +22,16 @@ def _skip_wo_ZODB(test_method): #pragma NO COVER
else: else:
return test_method return test_method
def _skip_under_Py3k(test_method): #pragma NO COVER
try:
unicode
except NameError: # skip this test
def _dummy(*args):
pass
return _dummy
else:
return test_method
class Base(object): class Base(object):
# Tests common to all types: sets, buckets, and BTrees # Tests common to all types: sets, buckets, and BTrees
...@@ -75,7 +85,7 @@ class Base(object): ...@@ -75,7 +85,7 @@ class Base(object):
def testSetstateArgumentChecking(self): def testSetstateArgumentChecking(self):
try: try:
self._makeOne().__setstate__(('',)) self._makeOne().__setstate__(('',))
except TypeError, v: except TypeError as v:
self.assertEqual(str(v), 'tuple required for first state element') self.assertEqual(str(v), 'tuple required for first state element')
else: else:
raise AssertionError("Expected exception") raise AssertionError("Expected exception")
...@@ -219,7 +229,7 @@ class MappingBase(Base): ...@@ -219,7 +229,7 @@ class MappingBase(Base):
t = self._makeOne() t = self._makeOne()
t[1] = 1 t[1] = 1
a = t[1] a = t[1]
self.assertEqual(a , 1, `a`) self.assertEqual(a , 1, repr(a))
def testReplaceWorks(self): def testReplaceWorks(self):
t = self._makeOne() t = self._makeOne()
...@@ -378,14 +388,14 @@ class MappingBase(Base): ...@@ -378,14 +388,14 @@ class MappingBase(Base):
try: try:
t.maxKey(t.minKey() - 1) t.maxKey(t.minKey() - 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
try: try:
t.minKey(t.maxKey() + 1) t.minKey(t.maxKey() + 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
...@@ -1037,11 +1047,11 @@ class BTreeTests(MappingBase): ...@@ -1037,11 +1047,11 @@ class BTreeTests(MappingBase):
for dummy in range(20): for dummy in range(20):
try: try:
del t[k[0]] del t[k[0]]
except RuntimeError, detail: except RuntimeError as detail:
self.assertEqual(str(detail), "the bucket being iterated " self.assertEqual(str(detail), "the bucket being iterated "
"changed size") "changed size")
break break
except KeyError, v: except KeyError as v:
# The Python implementation behaves very differently and # The Python implementation behaves very differently and
# gives a key error in this situation. It can't mess up # gives a key error in this situation. It can't mess up
# memory and can't readily detect changes to underlying buckets # memory and can't readily detect changes to underlying buckets
...@@ -1141,14 +1151,14 @@ class NormalSetTests(Base): ...@@ -1141,14 +1151,14 @@ class NormalSetTests(Base):
try: try:
t.maxKey(t.minKey() - 1) t.maxKey(t.minKey() - 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
try: try:
t.minKey(t.maxKey() + 1) t.minKey(t.maxKey() + 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
...@@ -1423,6 +1433,12 @@ class TestLongIntSupport: ...@@ -1423,6 +1433,12 @@ class TestLongIntSupport:
class TestLongIntKeys(TestLongIntSupport): class TestLongIntKeys(TestLongIntSupport):
def _makeLong(self, v):
try:
return long(v)
except NameError: #pragma NO COVER Py3k
return int(v)
def testLongIntKeysWork(self): def testLongIntKeysWork(self):
from BTrees.IIBTree import using64bits from BTrees.IIBTree import using64bits
if not using64bits: if not using64bits:
...@@ -1432,10 +1448,11 @@ class TestLongIntKeys(TestLongIntSupport): ...@@ -1432,10 +1448,11 @@ class TestLongIntKeys(TestLongIntSupport):
assert o1 != o2 assert o1 != o2
# Test some small key values first: # Test some small key values first:
t[0L] = o1 zero_long = self._makeLong(0)
t[zero_long] = o1
self.assertEqual(t[0], o1) self.assertEqual(t[0], o1)
t[0] = o2 t[0] = o2
self.assertEqual(t[0L], o2) self.assertEqual(t[zero_long], o2)
self.assertEqual(list(t.keys()), [0]) self.assertEqual(list(t.keys()), [0])
# Test some large key values too: # Test some large key values too:
...@@ -1890,7 +1907,7 @@ def _test_merge(o1, o2, o3, expect, message='failed to merge', should_fail=0): ...@@ -1890,7 +1907,7 @@ def _test_merge(o1, o2, o3, expect, message='failed to merge', should_fail=0):
if should_fail: if should_fail:
try: try:
merged = o1._p_resolveConflict(s1, s2, s3) merged = o1._p_resolveConflict(s1, s2, s3)
except BTreesConflictError, err: except BTreesConflictError as err:
pass pass
else: else:
assert 0, message assert 0, message
......
...@@ -206,6 +206,24 @@ class ToBeDeleted(object): ...@@ -206,6 +206,24 @@ class ToBeDeleted(object):
def __cmp__(self, other): def __cmp__(self, other):
return cmp(self.id, other.id) return cmp(self.id, other.id)
def __le__(self, other):
return self.id <= other.id
def __lt__(self, other):
return self.id < other.id
def __eq__(self, other):
return self.id == other.id
def __ne__(self, other):
return self.id != other.id
def __gt__(self, other):
return self.id > other.id
def __ge__(self, other):
return self.id >= other.id
def __hash__(self): def __hash__(self):
return hash(self.id) return hash(self.id)
...@@ -236,6 +254,8 @@ class BugFixes(unittest.TestCase): ...@@ -236,6 +254,8 @@ class BugFixes(unittest.TestCase):
import gc import gc
import random import random
from BTrees.OOBTree import OOBTree from BTrees.OOBTree import OOBTree
from .._compat import _u
from .._compat import xrange
t = OOBTree() t = OOBTree()
...@@ -257,12 +277,12 @@ class BugFixes(unittest.TestCase): ...@@ -257,12 +277,12 @@ class BugFixes(unittest.TestCase):
t[id] = ToBeDeleted(id) t[id] = ToBeDeleted(id)
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del t[id] del t[id]
del ids[id] del ids[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
ids = None ids = None
...@@ -287,15 +307,15 @@ class BugFixes(unittest.TestCase): ...@@ -287,15 +307,15 @@ class BugFixes(unittest.TestCase):
id = trandom.randint(0,1000000) id = trandom.randint(0,1000000)
ids[id] = 1 ids[id] = 1
t[id] = (id, ToBeDeleted(id), u'somename') t[id] = (id, ToBeDeleted(id), _u('somename'))
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del t[id] del t[id]
del ids[id] del ids[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
ids = None ids = None
...@@ -325,12 +345,12 @@ class BugFixes(unittest.TestCase): ...@@ -325,12 +345,12 @@ class BugFixes(unittest.TestCase):
t[id] = 1 t[id] = 1
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del ids[id] del ids[id]
del t[id] del t[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
#release all refs #release all refs
...@@ -354,18 +374,18 @@ class BugFixes(unittest.TestCase): ...@@ -354,18 +374,18 @@ class BugFixes(unittest.TestCase):
id = None id = None
while id is None or id in ids: while id is None or id in ids:
id = trandom.randint(0,1000000) id = trandom.randint(0,1000000)
id = (id, ToBeDeleted(id), u'somename') id = (id, ToBeDeleted(id), _u('somename'))
ids[id] = 1 ids[id] = 1
t[id] = 1 t[id] = 1
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del ids[id] del ids[id]
del t[id] del t[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
#release all refs #release all refs
...@@ -387,7 +407,7 @@ class DoesntLikeBeingCompared: ...@@ -387,7 +407,7 @@ class DoesntLikeBeingCompared:
def __cmp__(self,other): def __cmp__(self,other):
raise ValueError('incomparable') raise ValueError('incomparable')
__lt__ = __le__ = __eq__ = __ne__ = __ge__ = __gt__ = __cmp__
class TestCmpError(unittest.TestCase): class TestCmpError(unittest.TestCase):
...@@ -397,7 +417,7 @@ class TestCmpError(unittest.TestCase): ...@@ -397,7 +417,7 @@ class TestCmpError(unittest.TestCase):
t['hello world'] = None t['hello world'] = None
try: try:
t[DoesntLikeBeingCompared()] = None t[DoesntLikeBeingCompared()] = None
except ValueError,e: except ValueError as e:
self.assertEqual(str(e), 'incomparable') self.assertEqual(str(e), 'incomparable')
else: else:
self.fail('incomarable objects should not be allowed into ' self.fail('incomarable objects should not be allowed into '
...@@ -468,7 +488,7 @@ class FamilyTest(unittest.TestCase): ...@@ -468,7 +488,7 @@ class FamilyTest(unittest.TestCase):
# unpickling, whether from the same unpickler or different # unpickling, whether from the same unpickler or different
# unpicklers. # unpicklers.
import pickle import pickle
import StringIO from .._compat import BytesIO
s = pickle.dumps((family, family)) s = pickle.dumps((family, family))
(f1, f2) = pickle.loads(s) (f1, f2) = pickle.loads(s)
...@@ -476,23 +496,23 @@ class FamilyTest(unittest.TestCase): ...@@ -476,23 +496,23 @@ class FamilyTest(unittest.TestCase):
self.failUnless(f2 is family) self.failUnless(f2 is family)
# Using a single memo across multiple pickles: # Using a single memo across multiple pickles:
sio = StringIO.StringIO() sio = BytesIO()
p = pickle.Pickler(sio) p = pickle.Pickler(sio)
p.dump(family) p.dump(family)
p.dump([family]) p.dump([family])
u = pickle.Unpickler(StringIO.StringIO(sio.getvalue())) u = pickle.Unpickler(BytesIO(sio.getvalue()))
f1 = u.load() f1 = u.load()
f2, = u.load() f2, = u.load()
self.failUnless(f1 is family) self.failUnless(f1 is family)
self.failUnless(f2 is family) self.failUnless(f2 is family)
# Using separate memos for each pickle: # Using separate memos for each pickle:
sio = StringIO.StringIO() sio = BytesIO()
p = pickle.Pickler(sio) p = pickle.Pickler(sio)
p.dump(family) p.dump(family)
p.clear_memo() p.clear_memo()
p.dump([family]) p.dump([family])
u = pickle.Unpickler(StringIO.StringIO(sio.getvalue())) u = pickle.Unpickler(BytesIO(sio.getvalue()))
f1 = u.load() f1 = u.load()
f2, = u.load() f2, = u.load()
self.failUnless(f1 is family) self.failUnless(f1 is family)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
############################################################################## ##############################################################################
import unittest import unittest
from BTrees.OOBTree import OOBTree from .common import _skip_under_Py3k
# When an OOBtree contains unicode strings as keys, # When an OOBtree contains unicode strings as keys,
# it is neccessary accessing non-unicode strings are # it is neccessary accessing non-unicode strings are
...@@ -26,7 +26,8 @@ class TestBTreesUnicode(unittest.TestCase): ...@@ -26,7 +26,8 @@ class TestBTreesUnicode(unittest.TestCase):
""" test unicode""" """ test unicode"""
def setUp(self): def setUp(self):
"""setup an OOBTree with some unicode strings""" #setup an OOBTree with some unicode strings
from BTrees.OOBTree import OOBTree
self.s = unicode('dreit\xe4gigen', 'latin1') self.s = unicode('dreit\xe4gigen', 'latin1')
...@@ -45,6 +46,7 @@ class TestBTreesUnicode(unittest.TestCase): ...@@ -45,6 +46,7 @@ class TestBTreesUnicode(unittest.TestCase):
k = unicode(k, 'latin1') k = unicode(k, 'latin1')
self.tree[k] = v self.tree[k] = v
@_skip_under_Py3k
def testAllKeys(self): def testAllKeys(self):
# check every item of the tree # check every item of the tree
for k, v in self.data: for k, v in self.data:
...@@ -53,6 +55,7 @@ class TestBTreesUnicode(unittest.TestCase): ...@@ -53,6 +55,7 @@ class TestBTreesUnicode(unittest.TestCase):
self.assert_(self.tree.has_key(k)) self.assert_(self.tree.has_key(k))
self.assertEqual(self.tree[k], v) self.assertEqual(self.tree[k], v)
@_skip_under_Py3k
def testUnicodeKeys(self): def testUnicodeKeys(self):
# try to access unicode keys in tree # try to access unicode keys in tree
k, v = self.data[-1] k, v = self.data[-1]
...@@ -60,6 +63,7 @@ class TestBTreesUnicode(unittest.TestCase): ...@@ -60,6 +63,7 @@ class TestBTreesUnicode(unittest.TestCase):
self.assertEqual(self.tree[k], v) self.assertEqual(self.tree[k], v)
self.assertEqual(self.tree[self.s], v) self.assertEqual(self.tree[self.s], v)
@_skip_under_Py3k
def testAsciiKeys(self): def testAsciiKeys(self):
# try to access some "plain ASCII" keys in the tree # try to access some "plain ASCII" keys in the tree
for k, v in self.data[0], self.data[2]: for k, v in self.data[0], self.data[2]:
......
...@@ -15,9 +15,10 @@ ...@@ -15,9 +15,10 @@
import unittest import unittest
from .._compat import _u
STR = "A string with hi-bit-set characters: \700\701" STR = "A string with hi-bit-set characters: \700\701"
UNICODE = u"A unicode string" UNICODE = _u("A unicode string")
class CompareTest(unittest.TestCase): class CompareTest(unittest.TestCase):
......
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