[Zodb-checkins] SVN: ZODB/trunk/ Merge the
alienoid-btrees_setdefault branch.
Tim Peters
tim.one at comcast.net
Tue Aug 30 15:07:48 EDT 2005
Log message for revision 38160:
Merge the alienoid-btrees_setdefault branch.
This adds .setdefault() methods to BTrees and Buckets.
Changed:
U ZODB/trunk/NEWS.txt
U ZODB/trunk/src/BTrees/BTreeTemplate.c
U ZODB/trunk/src/BTrees/BucketTemplate.c
U ZODB/trunk/src/BTrees/Interfaces.py
U ZODB/trunk/src/BTrees/tests/testBTrees.py
-=-
Modified: ZODB/trunk/NEWS.txt
===================================================================
--- ZODB/trunk/NEWS.txt 2005-08-30 16:48:57 UTC (rev 38159)
+++ ZODB/trunk/NEWS.txt 2005-08-30 19:07:47 UTC (rev 38160)
@@ -183,6 +183,13 @@
BTrees
------
+- (3.5a9) BTrees and Buckets now implement the ``setdefault()`` method.
+ This is exactly list Python's ``setdefault()`` method for dictionaries,
+ except that both arguments are required (and Python is likely to change
+ to require both arguments too -- defaulting the ``default`` argument to
+ ``None`` has no viable use cases). Thanks to Ruslan Spivak for
+ contributing code, tests, and documentation.
+
- (3.5a5) Collector 1843. When a non-integer was passed to a method like
``keys()`` of a Bucket or Set with integer keys, an internal error code
was overlooked, leading to everything from "delayed errors" to segfaults.
Modified: ZODB/trunk/src/BTrees/BTreeTemplate.c
===================================================================
--- ZODB/trunk/src/BTrees/BTreeTemplate.c 2005-08-30 16:48:57 UTC (rev 38159)
+++ ZODB/trunk/src/BTrees/BTreeTemplate.c 2005-08-30 19:07:47 UTC (rev 38160)
@@ -1700,6 +1700,36 @@
return _BTree_get(self, key, 1);
}
+static PyObject *
+BTree_setdefault(BTree *self, PyObject *args)
+{
+ PyObject *key;
+ PyObject *failobj; /* default */
+ PyObject *value; /* return value */
+
+ if (! PyArg_UnpackTuple(args, "setdefault", 2, 2, &key, &failobj))
+ return NULL;
+
+ value = _BTree_get(self, key, 0);
+ if (value != NULL)
+ return value;
+
+ /* The key isn't in the tree. If that's not due to a KeyError exception,
+ * pass back the unexpected exception.
+ */
+ if (! PyErr_ExceptionMatches(PyExc_KeyError))
+ return NULL;
+ PyErr_Clear();
+
+ /* Associate `key` with `failobj` in the tree, and return `failobj`. */
+ value = failobj;
+ if (_BTree_set(self, key, failobj, 0, 0) < 0)
+ value = NULL;
+ Py_XINCREF(value);
+ return value;
+}
+
+
/* Search BTree self for key. This is the sq_contains slot of the
* PySequenceMethods.
*
@@ -1838,6 +1868,11 @@
"get(key[, default=None]) -> Value for key or default\n\n"
"Return the value or the default if the key is not found."},
+ {"setdefault", (PyCFunction) BTree_setdefault, METH_VARARGS,
+ "D.setdefault(k, d) -> D.get(k, d), also set D[k]=d if k not in D.\n\n"
+ "Return the value like get() except that if key is missing, d is both\n"
+ "returned and inserted into the BTree as the value of k."},
+
{"maxKey", (PyCFunction) BTree_maxKey, METH_VARARGS,
"maxKey([max]) -> key\n\n"
"Return the largest key in the BTree. If max is specified, return\n"
Modified: ZODB/trunk/src/BTrees/BucketTemplate.c
===================================================================
--- ZODB/trunk/src/BTrees/BucketTemplate.c 2005-08-30 16:48:57 UTC (rev 38159)
+++ ZODB/trunk/src/BTrees/BucketTemplate.c 2005-08-30 19:07:47 UTC (rev 38160)
@@ -1257,7 +1257,36 @@
return _bucket_get(self, key, 1);
}
+static PyObject *
+bucket_setdefault(Bucket *self, PyObject *args)
+{
+ PyObject *key;
+ PyObject *failobj; /* default */
+ PyObject *value; /* return value */
+ int dummy_changed; /* in order to call _bucket_set */
+ if (! PyArg_UnpackTuple(args, "setdefault", 2, 2, &key, &failobj))
+ return NULL;
+
+ value = _bucket_get(self, key, 0);
+ if (value != NULL)
+ return value;
+
+ /* The key isn't in the bucket. If that's not due to a KeyError exception,
+ * pass back the unexpected exception.
+ */
+ if (! PyErr_ExceptionMatches(PyExc_KeyError))
+ return NULL;
+ PyErr_Clear();
+
+ /* Associate `key` with `failobj` in the bucket, and return `failobj`. */
+ value = failobj;
+ if (_bucket_set(self, key, failobj, 0, 0, &dummy_changed) < 0)
+ value = NULL;
+ Py_XINCREF(value);
+ return value;
+}
+
/* Search bucket self for key. This is the sq_contains slot of the
* PySequenceMethods.
*
@@ -1481,6 +1510,11 @@
"get(key[,default]) -- Look up a value\n\n"
"Return the default (or None) if the key is not found."},
+ {"setdefault", (PyCFunction) bucket_setdefault, METH_VARARGS,
+ "D.setdefault(k, d) -> D.get(k, d), also set D[k]=d if k not in D.\n\n"
+ "Return the value like get() except that if key is missing, d is both\n"
+ "returned and inserted into the bucket as the value of k."},
+
{"iterkeys", (PyCFunction) Bucket_iterkeys, METH_KEYWORDS,
"B.iterkeys([min[,max]]) -> an iterator over the keys of B"},
Modified: ZODB/trunk/src/BTrees/Interfaces.py
===================================================================
--- ZODB/trunk/src/BTrees/Interfaces.py 2005-08-30 16:48:57 UTC (rev 38159)
+++ ZODB/trunk/src/BTrees/Interfaces.py 2005-08-30 19:07:47 UTC (rev 38160)
@@ -214,6 +214,18 @@
integer values, the normalization is division.
"""
+ def setdefault(key, d):
+ """D.setdefault(k, d) -> D.get(k, d), also set D[k]=d if k not in D.
+
+ Return the value like get() except that if key is missing, d is both
+ returned and inserted into the dictionary as the value of k.
+
+ Note that, unlike as for Python's dict.setdefault(), d is not
+ optional. Python defaults d to None, but that doesn't make sense
+ for mappings that can't have None as a value (for example, an
+ IIBTree can have only integers as values).
+ """
+
class IBTree(IDictionaryIsh):
def insert(key, value):
Modified: ZODB/trunk/src/BTrees/tests/testBTrees.py
===================================================================
--- ZODB/trunk/src/BTrees/tests/testBTrees.py 2005-08-30 16:48:57 UTC (rev 38159)
+++ ZODB/trunk/src/BTrees/tests/testBTrees.py 2005-08-30 19:07:47 UTC (rev 38160)
@@ -611,6 +611,23 @@
excludemax=True)),
f([1]))
+ def testSetdefault(self):
+ t = self.t
+
+ self.assertEqual(t.setdefault(1, 2), 2)
+ # That should also have associated 1 with 2 in the tree.
+ self.assert_(1 in t)
+ self.assertEqual(t[1], 2)
+ # And trying to change it again should have no effect.
+ self.assertEqual(t.setdefault(1, 666), 2)
+ self.assertEqual(t[1], 2)
+
+ # Not enough arguments.
+ self.assertRaises(TypeError, t.setdefault)
+ self.assertRaises(TypeError, t.setdefault, 1)
+ # Too many arguments.
+ self.assertRaises(TypeError, t.setdefault, 1, 2, 3)
+
class NormalSetTests(Base):
""" Test common to all set types """
More information about the Zodb-checkins
mailing list