Commit e0a3c604 authored by Tim Peters's avatar Tim Peters

Collector 1873.

update_from_seq():  If PySequence_Check(seq) returns true,
go on to check for the existence of "iteritems" when deciding
whether the input is or is not "a sequence".  Alas,
PySequence_Check() does return true for PersistentMapping and
PersistentDict instances, so that they couldn't be used as
arguments to BTree/Bucket construction or update().

This is nasty type-sniffing, but it was before too.  There's
no way to make such stuff bulletproof, so I'm settling for
incremental improvement.
parent 8ef63b5b
...@@ -183,11 +183,15 @@ FileStorage ...@@ -183,11 +183,15 @@ FileStorage
BTrees BTrees
------ ------
- (3.5.a5) Collector 1843. When a non-integer was passed to a method like - (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 ``keys()`` of a Bucket or Set with integer keys, an internal error code
was overlooked, leading to everything from "delayed errors" to segfaults. was overlooked, leading to everything from "delayed errors" to segfaults.
Such cases raise TypeError now, as intended. Such cases raise TypeError now, as intended.
- (3.5a9) Collector 1873. It wasn't possible to construct a BTree or Bucket
from, or apply their update() methods to, a PersistentMapping or
PersistentDict. This works now.
- (3.5a4) Collector 1831. The BTree ``minKey()`` and ``maxKey()`` methods - (3.5a4) Collector 1831. The BTree ``minKey()`` and ``maxKey()`` methods
gave a misleading message if no key satisfying the constraints existed in a gave a misleading message if no key satisfying the constraints existed in a
non-empty tree. non-empty tree.
......
...@@ -457,7 +457,12 @@ update_from_seq(PyObject *map, PyObject *seq) ...@@ -457,7 +457,12 @@ update_from_seq(PyObject *map, PyObject *seq)
INCREF of the seq argument. So seq must always be DECREFed on INCREF of the seq argument. So seq must always be DECREFed on
the way out. the way out.
*/ */
if (!PySequence_Check(seq)) { /* Use items() if it's not a sequence. Alas, PySequence_Check()
* returns true for a PeristentMapping or PersistentDict, and we
* want to use items() in those cases too.
*/
if (!PySequence_Check(seq) || /* or it "looks like a dict" */
PyObject_HasAttrString(seq, "iteritems")) {
PyObject *items; PyObject *items;
items = PyObject_GetAttrString(seq, "items"); items = PyObject_GetAttrString(seq, "items");
if (items == NULL) if (items == NULL)
...@@ -466,7 +471,8 @@ update_from_seq(PyObject *map, PyObject *seq) ...@@ -466,7 +471,8 @@ update_from_seq(PyObject *map, PyObject *seq)
Py_DECREF(items); Py_DECREF(items);
if (seq == NULL) if (seq == NULL)
return -1; return -1;
} else }
else
Py_INCREF(seq); Py_INCREF(seq);
iter = PyObject_GetIter(seq); iter = PyObject_GetIter(seq);
......
...@@ -345,6 +345,18 @@ class MappingBase(Base): ...@@ -345,6 +345,18 @@ class MappingBase(Base):
self.t.update(l) self.t.update(l)
self.assertEqual(list(self.t.items()), items) self.assertEqual(list(self.t.items()), items)
# Before ZODB 3.4.2, update/construction from PersistentMapping failed.
def testUpdateFromPersistentMapping(self):
from persistent.mapping import PersistentMapping
pm = PersistentMapping({1: 2})
self.t.update(pm)
self.assertEqual(list(self.t.items()), [(1, 2)])
# Construction goes thru the same internals as .update().
t = self.t.__class__(pm)
self.assertEqual(list(t.items()), [(1, 2)])
def testEmptyRangeSearches(self): def testEmptyRangeSearches(self):
t = self.t t = self.t
t.update([(1,1), (5,5), (9,9)]) t.update([(1,1), (5,5), (9,9)])
......
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