Skip to content

Commit

Permalink
Merge 0062ca9 into e1da7bf
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Apr 8, 2021
2 parents e1da7bf + 0062ca9 commit 09c1e4a
Show file tree
Hide file tree
Showing 11 changed files with 1,292 additions and 46 deletions.
14 changes: 14 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@
of each module actually provide the interfaces defined in
``BTrees.Interfaces``. Previously, they provided no interfaces.

- Make all the BTree and Bucket objects instances of
``collections.abc.MutableMapping`` (that is, ``isinstance(btree,
MutableMapping)`` is now true; no actual inheritance has changed).
As part of this, they now provide the ``popitem()`` method.

- Make all the TreeSet and Set objects instances of
``collections.abc.MutableSet`` (that is, ``isinstance(tree_set,
MutableSet)`` is now true; no actual inheritance has changed).
As part of this, they now provide several more methods, including
``isdisjoint``, ``discard``, and ``pop``, and support in-place
mutation operators such as ``tree_set |= other``, ``tree_set +=
other``, ``tree_set -= other`` and ``tree_set ^= other``. See `issue
121 <https://github.com/zopefoundation/BTrees/issues/121>`_.

- Update the definitions of ``ISized`` and ``IReadSequence`` to simply
be ``zope.interface.common.collections.ISized`` and
``zope.interface.common.sequence.IMinimalSequence`` respectively.
Expand Down
41 changes: 41 additions & 0 deletions src/BTrees/BTreeTemplate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,43 @@ BTree_pop(BTree *self, PyObject *args)
return NULL;
}


static PyObject*
BTree_popitem(BTree* self, PyObject* args)
{
PyObject* key = NULL;
PyObject* pop_args = NULL;
PyObject* result_val = NULL;
PyObject* result = NULL;

if (PyTuple_Size(args) != 0) {
PyErr_SetString(PyExc_TypeError, "popitem(): Takes no arguments.");
return NULL;
}

key = BTree_minKey(self, args); /* reuse existing empty tuple. */
if (!key) {
PyErr_Clear();
PyErr_SetString(PyExc_KeyError, "popitem(): empty BTree.");
return NULL;
}

pop_args = PyTuple_Pack(1, key);
if (pop_args) {
result_val = BTree_pop(self, pop_args);
Py_DECREF(pop_args);
if (result_val) {
result = PyTuple_Pack(2, key, result_val);
Py_DECREF(result_val);
}
}

Py_DECREF(key);
return result_val;
}



/* Search BTree self for key. This is the sq_contains slot of the
* PySequenceMethods.
*
Expand Down Expand Up @@ -2231,6 +2268,10 @@ static struct PyMethodDef BTree_methods[] = {
"If key is not found, d is returned if given, otherwise KeyError\n"
"is raised."},

{"popitem", (PyCFunction)BTree_popitem, METH_VARARGS,
"D.popitem() -> (k, v), remove and return some (key, value) pair\n"
"as a 2-tuple; but raise KeyError if D is empty."},

{"maxKey", (PyCFunction) BTree_maxKey, METH_VARARGS,
"maxKey([max]) -> key\n\n"
"Return the largest key in the BTree. If max is specified, return\n"
Expand Down
39 changes: 39 additions & 0 deletions src/BTrees/BucketTemplate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,41 @@ bucket_pop(Bucket *self, PyObject *args)
return NULL;
}

static PyObject*
bucket_popitem(Bucket* self, PyObject* args)
{
PyObject* key = NULL;
PyObject* pop_args = NULL;
PyObject* result_val = NULL;
PyObject* result = NULL;

if (PyTuple_Size(args) != 0) {
PyErr_SetString(PyExc_TypeError, "popitem(): Takes no arguments.");
return NULL;
}

key = Bucket_minKey(self, args); /* reuse existing empty tuple. */
if (!key) {
PyErr_Clear();
PyErr_SetString(PyExc_KeyError, "popitem(): empty bucket.");
return NULL;
}

pop_args = PyTuple_Pack(1, key);
if (pop_args) {
result_val = bucket_pop(self, pop_args);
Py_DECREF(pop_args);
if (result_val) {
result = PyTuple_Pack(2, key, result_val);
Py_DECREF(result_val);
}
}

Py_DECREF(key);
return result_val;
}


/* Search bucket self for key. This is the sq_contains slot of the
* PySequenceMethods.
*
Expand Down Expand Up @@ -1722,6 +1757,10 @@ static struct PyMethodDef Bucket_methods[] = {
"If key is not found, d is returned if given, otherwise KeyError\n"
"is raised."},

{"popitem", (PyCFunction)bucket_popitem, METH_VARARGS,
"D.popitem() -> (k, v), remove and return some (key, value) pair\n"
"as a 2-tuple; but raise KeyError if D is empty."},

{"iterkeys", (PyCFunction) Bucket_iterkeys, METH_VARARGS | METH_KEYWORDS,
"B.iterkeys([min[,max]]) -> an iterator over the keys of B"},

Expand Down
108 changes: 90 additions & 18 deletions src/BTrees/Interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,38 +105,102 @@ def remove(key):
def update(seq):
"""Add the items from the given sequence to the set."""

def __and__(other):
"""
Shortcut for :meth:`~BTrees.Interfaces.IMerge.intersection`
class IKeySequence(IKeyed, ISized):
.. versionadded:: 4.8.0
"""

def __getitem__(index):
"""Return the key in the given index position.
def __iand__(other):
"""
As for :meth:`set.intersection_update`: Update this object,
keeping only elements found in both it and other.
This allows iteration with for loops and use in functions,
like map and list, that read sequences.
.. versionadded:: 4.8.0
"""

def __or__(other):
"""
Shortcut for :meth:`~BTrees.Interfaces.IMerge.union`
class ISet(ISetMutable, IKeySequence):
def __and__(other):
"""Shortcut for :meth:`~BTrees.Interfaces.IMerge.intersection`"""
.. versionadded:: 4.8.0
"""

def __or__(other):
"""Shortcut for :meth:`~BTrees.Interfaces.IMerge.union`"""
def __ior__(other):
"""
As for :meth:`set.update`: Update this object, adding
elements from *other*.
.. versionadded:: 4.8.0
"""

def __sub__(other):
"""Shortcut for :meth:`~BTrees.Interfaces.IMerge.difference"""
"""
Shortcut for :meth:`~BTrees.Interfaces.IMerge.difference`
.. versionadded:: 4.8.0
"""

class ITreeSet(ISetMutable):
def __and__(other):
"""Shortcut for :meth:`~BTrees.Interfaces.IMerge.intersection`"""
def __isub__(other):
"""
As for :meth:`set.difference_update`: Update this object,
removing elements found in *other*.
def __or__(other):
"""Shortcut for :meth:`~BTrees.Interfaces.IMerge.union`"""
.. versionadded:: 4.8.0
"""

def __sub__(other):
"""Shortcut for :meth:`~BTrees.Interfaces.IMerge.difference"""
def isdisjoint(other):
"""
As for :meth:`set.isdisjoint`: Return True if the set has no
elements in common with other.
.. versionadded:: 4.8.0
"""

def discard(key):
"""
As for :meth:`set.discard`: Remove the *key* from the set,
but only if it is present.
.. versionadded:: 4.8.0
"""

def pop():
"""
As for :meth:`set.pop`: Remove and return an arbitrary element;
raise :exc:`KeyError` if the object is empty.
.. versionadded:: 4.8.0
"""

def __ixor__(other):
"""
As for :meth:`set.symmetric_difference_update`: Update this object,
keeping only elements found in either set but not in both.
.. versionadded:: 4.8.0
"""

class IKeySequence(IKeyed, ISized):

def __getitem__(index):
"""Return the key in the given index position.
This allows iteration with for loops and use in functions,
like map and list, that read sequences.
"""


class ISet(ISetMutable, IKeySequence):
"""
A set of unique items stored in a single persistent object.
"""

class ITreeSet(ISetMutable):
"""
A set of unique items stored in a tree of persistent objects.
"""


class IMinimalDictionary(IKeyed, IMapping):
Expand Down Expand Up @@ -266,6 +330,14 @@ def pop(key, d):
raised.
"""

def popitem():
"""
D.popitem() -> (k, v), remove and return some (key, value) pair
as a 2-tuple; but raise KeyError if D is empty.
.. versionadded:: 4.8.0
"""


class IBTree(IDictionaryIsh):

Expand Down
Loading

0 comments on commit 09c1e4a

Please sign in to comment.