Commit 7b48768a authored by Jason Madden's avatar Jason Madden

Make the Python trees and sets accept an explicit None argument to indicate an...

Make the Python trees and sets accept an explicit None argument to indicate an open range in keys(), values() and min/maxKey(), as per the interface documentation and the C implementation. Except actually, the C implementation didn't accept a None for mim/maxKey, so make it actually do that.
parent db8c553b
...@@ -1506,7 +1506,7 @@ BTree_maxminKey(BTree *self, PyObject *args, int min) ...@@ -1506,7 +1506,7 @@ BTree_maxminKey(BTree *self, PyObject *args, int min)
/* Find the range */ /* Find the range */
if (key) if (key && key != Py_None)
{ {
if ((rc = BTree_findRangeEnd(self, key, min, 0, &bucket, &offset)) <= 0) if ((rc = BTree_findRangeEnd(self, key, min, 0, &bucket, &offset)) <= 0)
{ {
......
...@@ -741,7 +741,7 @@ Bucket_maxminKey(Bucket *self, PyObject *args, int min) ...@@ -741,7 +741,7 @@ Bucket_maxminKey(Bucket *self, PyObject *args, int min)
goto empty; goto empty;
/* Find the low range */ /* Find the low range */
if (key) if (key && key != Py_None)
{ {
if ((rc = Bucket_findRangeEnd(self, key, min, 0, &offset)) <= 0) if ((rc = Bucket_findRangeEnd(self, key, min, 0, &offset)) <= 0)
{ {
...@@ -1662,7 +1662,7 @@ static struct PyMethodDef Bucket_methods[] = { ...@@ -1662,7 +1662,7 @@ static struct PyMethodDef Bucket_methods[] = {
{"iterkeys", (PyCFunction) Bucket_iterkeys, METH_VARARGS | METH_KEYWORDS, {"iterkeys", (PyCFunction) Bucket_iterkeys, METH_VARARGS | METH_KEYWORDS,
"B.iterkeys([min[,max]]) -> an iterator over the keys of B"}, "B.iterkeys([min[,max]]) -> an iterator over the keys of B"},
{"itervalues", {"itervalues",
(PyCFunction) Bucket_itervalues, METH_VARARGS | METH_KEYWORDS, (PyCFunction) Bucket_itervalues, METH_VARARGS | METH_KEYWORDS,
"B.itervalues([min[,max]]) -> an iterator over the values of B"}, "B.itervalues([min[,max]]) -> an iterator over the values of B"},
......
...@@ -82,7 +82,7 @@ class _BucketBase(_Base): ...@@ -82,7 +82,7 @@ class _BucketBase(_Base):
return -1 - low return -1 - low
def minKey(self, key=_marker): def minKey(self, key=_marker):
if key is _marker: if key is _marker or key is None:
return self._keys[0] return self._keys[0]
key = self._to_key(key) key = self._to_key(key)
index = self._search(key) index = self._search(key)
...@@ -95,7 +95,7 @@ class _BucketBase(_Base): ...@@ -95,7 +95,7 @@ class _BucketBase(_Base):
raise ValueError("no key satisfies the conditions") raise ValueError("no key satisfies the conditions")
def maxKey(self, key=_marker): def maxKey(self, key=_marker):
if key is _marker: if key is _marker or key is None:
return self._keys[-1] return self._keys[-1]
key = self._to_key(key) key = self._to_key(key)
index = self._search(key) index = self._search(key)
...@@ -110,7 +110,7 @@ class _BucketBase(_Base): ...@@ -110,7 +110,7 @@ class _BucketBase(_Base):
def _range(self, min=_marker, max=_marker, def _range(self, min=_marker, max=_marker,
excludemin=False, excludemax=False): excludemin=False, excludemax=False):
if min is _marker: if min is _marker or min is None:
start = 0 start = 0
if excludemin: if excludemin:
start = 1 start = 1
...@@ -122,7 +122,7 @@ class _BucketBase(_Base): ...@@ -122,7 +122,7 @@ class _BucketBase(_Base):
start += 1 start += 1
else: else:
start = -start - 1 start = -start - 1
if max is _marker: if max is _marker or max is None:
end = len(self._keys) end = len(self._keys)
if excludemax: if excludemax:
end -= 1 end -= 1
...@@ -808,7 +808,7 @@ class _Tree(_Base): ...@@ -808,7 +808,7 @@ class _Tree(_Base):
if not self._data: if not self._data:
return () return ()
if min != _marker: if min is not _marker and min is not None:
min = self._to_key(min) min = self._to_key(min)
bucket = self._findbucket(min) bucket = self._findbucket(min)
else: else:
...@@ -826,7 +826,7 @@ class _Tree(_Base): ...@@ -826,7 +826,7 @@ class _Tree(_Base):
return iter(self.keys()) return iter(self.keys())
def minKey(self, min=_marker): def minKey(self, min=_marker):
if min is _marker: if min is _marker or min is None:
bucket = self._firstbucket bucket = self._firstbucket
else: else:
min = self._to_key(min) min = self._to_key(min)
...@@ -839,7 +839,7 @@ class _Tree(_Base): ...@@ -839,7 +839,7 @@ class _Tree(_Base):
data = self._data data = self._data
if not data: if not data:
raise ValueError('empty tree') raise ValueError('empty tree')
if max is _marker: if max is _marker or max is None:
return data[-1].child.maxKey() return data[-1].child.maxKey()
max = self._to_key(max) max = self._to_key(max)
......
...@@ -34,7 +34,7 @@ def _skip_under_Py3k(test_method): #pragma NO COVER ...@@ -34,7 +34,7 @@ def _skip_under_Py3k(test_method): #pragma NO COVER
class Base(object): class Base(object):
# Tests common to all types: sets, buckets, and BTrees # Tests common to all types: sets, buckets, and BTrees
db = None db = None
...@@ -195,7 +195,7 @@ class Base(object): ...@@ -195,7 +195,7 @@ class Base(object):
class MappingBase(Base): class MappingBase(Base):
# Tests common to mappings (buckets, btrees) # Tests common to mappings (buckets, btrees)
def _populate(self, t, l): def _populate(self, t, l):
# Make some data # Make some data
...@@ -393,9 +393,11 @@ class MappingBase(Base): ...@@ -393,9 +393,11 @@ class MappingBase(Base):
t[4] = 150 t[4] = 150
del t[7] del t[7]
self.assertEqual(t.maxKey(), 10) self.assertEqual(t.maxKey(), 10)
self.assertEqual(t.maxKey(None), 10)
self.assertEqual(t.maxKey(6), 6) self.assertEqual(t.maxKey(6), 6)
self.assertEqual(t.maxKey(9), 8) self.assertEqual(t.maxKey(9), 8)
self.assertEqual(t.minKey(), 1) self.assertEqual(t.minKey(), 1)
self.assertEqual(t.minKey(None), 1)
self.assertEqual(t.minKey(3), 3) self.assertEqual(t.minKey(3), 3)
self.assertEqual(t.minKey(9), 10) self.assertEqual(t.minKey(9), 10)
...@@ -758,7 +760,7 @@ class MappingBase(Base): ...@@ -758,7 +760,7 @@ class MappingBase(Base):
class BTreeTests(MappingBase): class BTreeTests(MappingBase):
# Tests common to all BTrees # Tests common to all BTrees
def _checkIt(self, t): def _checkIt(self, t):
from BTrees.check import check from BTrees.check import check
...@@ -989,6 +991,15 @@ class BTreeTests(MappingBase): ...@@ -989,6 +991,15 @@ class BTreeTests(MappingBase):
t[x] = 0 t[x] = 0
diff = lsubtract(list(t.keys(0, 100)), r) diff = lsubtract(list(t.keys(0, 100)), r)
self.assertEqual(diff , [], diff) self.assertEqual(diff , [], diff)
# The same thing with no bounds
diff = lsubtract(list(t.keys(0, 100)), r)
self.assertEqual(diff , [], diff)
# The same thing with each bound set and the other
# explicitly None
diff = lsubtract(list(t.keys(0, None)), r)
self.assertEqual(diff , [], diff)
diff = lsubtract(list(t.keys(None,100)), r)
self.assertEqual(diff , [], diff)
self._checkIt(t) self._checkIt(t)
def testRangeSearchAfterRandomInsert(self): def testRangeSearchAfterRandomInsert(self):
...@@ -1072,7 +1083,7 @@ class BTreeTests(MappingBase): ...@@ -1072,7 +1083,7 @@ class BTreeTests(MappingBase):
class NormalSetTests(Base): class NormalSetTests(Base):
# Test common to all set types # Test common to all set types
def _populate(self, t, l): def _populate(self, t, l):
# Make some data # Make some data
...@@ -1160,9 +1171,11 @@ class NormalSetTests(Base): ...@@ -1160,9 +1171,11 @@ class NormalSetTests(Base):
t.insert(6) t.insert(6)
t.insert(4) t.insert(4)
self.assertEqual(t.maxKey() , 10) self.assertEqual(t.maxKey() , 10)
self.assertEqual(t.maxKey(None) , 10)
self.assertEqual(t.maxKey(6) , 6) self.assertEqual(t.maxKey(6) , 6)
self.assertEqual(t.maxKey(9) , 8) self.assertEqual(t.maxKey(9) , 8)
self.assertEqual(t.minKey() , 1) self.assertEqual(t.minKey() , 1)
self.assertEqual(t.minKey(None) , 1)
self.assertEqual(t.minKey(3) , 3) self.assertEqual(t.minKey(3) , 3)
self.assertEqual(t.minKey(9) , 10) self.assertEqual(t.minKey(9) , 10)
self.assertTrue(t.minKey() in t) self.assertTrue(t.minKey() in t)
...@@ -1481,6 +1494,7 @@ class TestLongIntKeys(TestLongIntSupport): ...@@ -1481,6 +1494,7 @@ class TestLongIntKeys(TestLongIntSupport):
t[0] = o2 t[0] = o2
self.assertEqual(t[zero_long], o2) self.assertEqual(t[zero_long], o2)
self.assertEqual(list(t.keys()), [0]) self.assertEqual(list(t.keys()), [0])
self.assertEqual(list(t.keys(None,None)), [0])
# Test some large key values too: # Test some large key values too:
k1 = SMALLEST_POSITIVE_33_BITS k1 = SMALLEST_POSITIVE_33_BITS
...@@ -1493,6 +1507,8 @@ class TestLongIntKeys(TestLongIntSupport): ...@@ -1493,6 +1507,8 @@ class TestLongIntKeys(TestLongIntSupport):
self.assertEqual(t[k2], o2) self.assertEqual(t[k2], o2)
self.assertEqual(t[k3], o1) self.assertEqual(t[k3], o1)
self.assertEqual(list(t.keys()), [k3, 0, k1, k2]) self.assertEqual(list(t.keys()), [k3, 0, k1, k2])
self.assertEqual(list(t.keys(k3,None)), [k3, 0, k1, k2])
self.assertEqual(list(t.keys(None,k2)), [k3, 0, k1, k2])
def testLongIntKeysOutOfRange(self): def testLongIntKeysOutOfRange(self):
from BTrees.IIBTree import using64bits from BTrees.IIBTree import using64bits
...@@ -1526,6 +1542,7 @@ class TestLongIntValues(TestLongIntSupport): ...@@ -1526,6 +1542,7 @@ class TestLongIntValues(TestLongIntSupport):
self.assertEqual(t[k1], v1) self.assertEqual(t[k1], v1)
self.assertEqual(t[k2], v2) self.assertEqual(t[k2], v2)
self.assertEqual(list(t.values()), [v1, v2]) self.assertEqual(list(t.values()), [v1, v2])
self.assertEqual(list(t.values(None,None)), [v1, v2])
def testLongIntValuesOutOfRange(self): def testLongIntValuesOutOfRange(self):
from BTrees.IIBTree import using64bits from BTrees.IIBTree import using64bits
......
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