From c401bd1de5da215ae163224496f1328720f2b33f Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 30 May 2009 17:13:13 +0000 Subject: [PATCH] fixes to __setitem__ in the list adapter to handle some slices that usually go right to __setslice__ --- lib/sqlalchemy/orm/collections.py | 11 ++++---- test/orm/collection.py | 47 +++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py index 4b002f2a4b..6e64e9ba79 100644 --- a/lib/sqlalchemy/orm/collections.py +++ b/lib/sqlalchemy/orm/collections.py @@ -945,17 +945,18 @@ def _list_decorators(): else: # slice assignment requires __delitem__, insert, __len__ if index.stop is None: - stop = 0 + stop = len(self) elif index.stop < 0: stop = len(self) + index.stop else: stop = index.stop + start = index.start or 0 step = index.step or 1 - rng = range(index.start or 0, stop, step) + rng = range(start, stop, step) if step == 1: for i in rng: - del self[index.start] - i = index.start + del self[start] + i = start for item in value: self.insert(i, item) i += 1 @@ -985,7 +986,7 @@ def _list_decorators(): fn(self, index) _tidy(__delitem__) return __delitem__ - + # Py2K def __setslice__(fn): def __setslice__(self, start, end, values): diff --git a/test/orm/collection.py b/test/orm/collection.py index 3d48f1d762..023ed13d24 100644 --- a/test/orm/collection.py +++ b/test/orm/collection.py @@ -189,7 +189,7 @@ class CollectionsTest(_base.ORMTest): del direct[::2] del control[::2] assert_eq() - + if hasattr(direct, 'remove'): e = creator() direct.append(e) @@ -199,8 +199,7 @@ class CollectionsTest(_base.ORMTest): control.remove(e) assert_eq() - # Py2K - if hasattr(direct, '__setslice__'): + if hasattr(direct, '__setitem__') or hasattr(direct, '__setslice__'): values = [creator(), creator()] direct[0:1] = values control[0:1] = values @@ -226,7 +225,7 @@ class CollectionsTest(_base.ORMTest): control[1::2] = values assert_eq() - if hasattr(direct, '__delslice__'): + if hasattr(direct, '__delitem__') or hasattr(direct, '__delslice__'): for i in range(1, 4): e = creator() direct.append(e) @@ -243,7 +242,6 @@ class CollectionsTest(_base.ORMTest): del direct[:] del control[:] assert_eq() - # end Py2K if hasattr(direct, 'extend'): values = [creator(), creator(), creator()] @@ -343,6 +341,45 @@ class CollectionsTest(_base.ORMTest): self._test_list(list) self._test_list_bulk(list) + def test_list_setitem_with_slices(self): + + # this is a "list" that has no __setslice__ + # or __delslice__ methods. The __setitem__ + # and __delitem__ must therefore accept + # slice objects (i.e. as in py3k) + class ListLike(object): + def __init__(self): + self.data = list() + def append(self, item): + self.data.append(item) + def remove(self, item): + self.data.remove(item) + def insert(self, index, item): + self.data.insert(index, item) + def pop(self, index=-1): + return self.data.pop(index) + def extend(self): + assert False + def __len__(self): + return len(self.data) + def __setitem__(self, key, value): + self.data[key] = value + def __getitem__(self, key): + return self.data[key] + def __delitem__(self, key): + del self.data[key] + def __iter__(self): + return iter(self.data) + __hash__ = object.__hash__ + def __eq__(self, other): + return self.data == other + def __repr__(self): + return 'ListLike(%s)' % repr(self.data) + + self._test_adapter(ListLike) + self._test_list(ListLike) + self._test_list_bulk(ListLike) + def test_list_subclass(self): class MyList(list): pass -- 2.47.3