diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2019-11-20 19:50:35 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2019-11-20 19:50:35 +0000 |
| commit | d933ddd503a1ca0a7c562c51c503139c541e707e (patch) | |
| tree | 8c376dfc1ef8237f8e95020cd1910b3253459612 | |
| parent | 3ceb87da1a66f455444e69ba25ac18ea26d8751e (diff) | |
| parent | 560044748a8ff5488769f8ebfa8a353a8d0115fa (diff) | |
| download | sqlalchemy-d933ddd503a1ca0a7c562c51c503139c541e707e.tar.gz | |
Merge "Skip on slice assignment to self"
| -rw-r--r-- | doc/build/changelog/unreleased_13/4990.rst | 11 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/collections.py | 2 | ||||
| -rw-r--r-- | test/orm/test_collection.py | 36 |
3 files changed, 45 insertions, 4 deletions
diff --git a/doc/build/changelog/unreleased_13/4990.rst b/doc/build/changelog/unreleased_13/4990.rst new file mode 100644 index 000000000..702403dd5 --- /dev/null +++ b/doc/build/changelog/unreleased_13/4990.rst @@ -0,0 +1,11 @@ +.. change:: + :tags: bug, orm, py3k + :tickets: 4990 + + Fixed issue where when assigning a collection to itself as a slice, the + mutation operation would fail as it would first erase the assigned + collection inadvertently. As an assignment that does not change the + contents should not generate events, the operation is now a no-op. Note + that the fix only applies to Python 3; in Python 2, the ``__setitem__`` + hook isn't called in this case; ``__setslice__`` is used instead which + recreates the list item-by-item in all cases.
\ No newline at end of file diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py index 4b096c152..5008f5727 100644 --- a/lib/sqlalchemy/orm/collections.py +++ b/lib/sqlalchemy/orm/collections.py @@ -1201,6 +1201,8 @@ def _list_decorators(): stop += len(self) if step == 1: + if value is self: + return for i in range(start, stop, step): if len(self) > start: del self[start] diff --git a/test/orm/test_collection.py b/test/orm/test_collection.py index 34b7fc5fe..03b6c8758 100644 --- a/test/orm/test_collection.py +++ b/test/orm/test_collection.py @@ -1,3 +1,4 @@ +import contextlib from operator import and_ from sqlalchemy import event @@ -30,6 +31,15 @@ class Canary(object): self.data = set() self.added = set() self.removed = set() + self.dupe_check = True + + @contextlib.contextmanager + def defer_dupe_check(self): + self.dupe_check = False + try: + yield + finally: + self.dupe_check = True def listen(self, attr): event.listen(attr, "append", self.append) @@ -37,15 +47,17 @@ class Canary(object): event.listen(attr, "set", self.set) def append(self, obj, value, initiator): - assert value not in self.added + if self.dupe_check: + assert value not in self.added + self.added.add(value) self.data.add(value) - self.added.add(value) return value def remove(self, obj, value, initiator): - assert value not in self.removed + if self.dupe_check: + assert value not in self.removed + self.removed.add(value) self.data.remove(value) - self.removed.add(value) def set(self, obj, value, oldvalue, initiator): if isinstance(value, str): @@ -299,6 +311,22 @@ class CollectionsTest(fixtures.ORMTest): control[:] = values assert_eq() + # test slice assignment where we slice assign to self, + # currently a no-op, issue #4990 + # note that in py2k, the bug does not exist but it recreates + # the collection which breaks our fixtures here + with canary.defer_dupe_check(): + direct[:] = direct + control[:] = control + assert_eq() + + # we dont handle assignment of self to slices, as this + # implies duplicate entries. behavior here is not well defined + # and perhaps should emit a warning + # direct[0:1] = list(direct) + # control[0:1] = list(control) + # assert_eq() + # test slice assignment where # slice size goes over the number of items values = [creator(), creator()] |
