summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJason Kirtland <jek@discorporate.us>2008-05-05 21:33:29 +0000
committerJason Kirtland <jek@discorporate.us>2008-05-05 21:33:29 +0000
commit586e5be1bb2bedb69802312925ca84f81199f2ff (patch)
tree5a7376820c871dc1a2b6c51f7df847ddab7b3187 /lib
parenta566964ac8a0f08d6dbbb2f541c805d828428411 (diff)
downloadsqlalchemy-586e5be1bb2bedb69802312925ca84f81199f2ff.tar.gz
Adjusted inplace-binops on set-based collections and association proxies to
more closely follow builtin (2.4+) set semantics. Formerly any set duck-type was accepted, now only types or subtypes of set, frozenset or the collection type itself are accepted.
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/ext/associationproxy.py18
-rw-r--r--lib/sqlalchemy/orm/collections.py30
2 files changed, 35 insertions, 13 deletions
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py
index bcbfb4780..d878f7b9b 100644
--- a/lib/sqlalchemy/ext/associationproxy.py
+++ b/lib/sqlalchemy/ext/associationproxy.py
@@ -6,10 +6,12 @@ transparent proxied access to the endpoint of an association object.
See the example ``examples/association/proxied_association.py``.
"""
-import weakref, itertools
-import sqlalchemy.exceptions as exceptions
-import sqlalchemy.orm as orm
-import sqlalchemy.util as util
+import itertools
+import weakref
+from sqlalchemy import exceptions
+from sqlalchemy import orm
+from sqlalchemy import util
+from sqlalchemy.orm import collections
def association_proxy(targetcollection, attr, **kw):
@@ -702,7 +704,7 @@ class _AssociationSet(object):
self.add(value)
def __ior__(self, other):
- if util.duck_type_collection(other) is not util.Set:
+ if not collections._set_binops_check_strict(self, other):
return NotImplemented
for value in other:
self.add(value)
@@ -726,7 +728,7 @@ class _AssociationSet(object):
self.discard(value)
def __isub__(self, other):
- if util.duck_type_collection(other) is not util.Set:
+ if not collections._set_binops_check_strict(self, other):
return NotImplemented
for value in other:
self.discard(value)
@@ -748,7 +750,7 @@ class _AssociationSet(object):
self.add(value)
def __iand__(self, other):
- if util.duck_type_collection(other) is not util.Set:
+ if not collections._set_binops_check_strict(self, other):
return NotImplemented
want, have = self.intersection(other), util.Set(self)
@@ -776,7 +778,7 @@ class _AssociationSet(object):
self.add(value)
def __ixor__(self, other):
- if util.duck_type_collection(other) is not util.Set:
+ if not collections._set_binops_check_strict(self, other):
return NotImplemented
want, have = self.symmetric_difference(other), util.Set(self)
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index 8067a030f..c8fc2f189 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -95,7 +95,11 @@ The owning object and InstrumentedCollectionAttribute are also reachable
through the adapter, allowing for some very sophisticated behavior.
"""
-import copy, inspect, sys, weakref
+import copy
+import inspect
+import sets
+import sys
+import weakref
from sqlalchemy import exceptions, schema, util as sautil
from sqlalchemy.util import attrgetter, Set
@@ -1136,6 +1140,22 @@ def _dict_decorators():
l.pop('Unspecified')
return l
+
+try:
+ _set_binop_bases = (set, frozenset, sets.BaseSet)
+except NameError:
+ _set_binop_bases = (sets.BaseSet,)
+
+def _set_binops_check_strict(self, obj):
+ """Allow only set, frozenset and self.__class__-derived objects in binops."""
+ return isinstance(obj, _set_binop_bases + (self.__class__,))
+
+def _set_binops_check_loose(self, obj):
+ """Allow anything set-like to participate in set binops."""
+ return (isinstance(obj, _set_binop_bases + (self.__class__,)) or
+ sautil.duck_type_collection(obj) == sautil.Set)
+
+
def _set_decorators():
"""Hand-turned instrumentation wrappers that can decorate any set-like
sequence class."""
@@ -1208,7 +1228,7 @@ def _set_decorators():
def __ior__(fn):
def __ior__(self, value):
- if sautil.duck_type_collection(value) is not Set:
+ if not _set_binops_check_strict(self, value):
return NotImplemented
for item in value:
self.add(item)
@@ -1225,7 +1245,7 @@ def _set_decorators():
def __isub__(fn):
def __isub__(self, value):
- if sautil.duck_type_collection(value) is not Set:
+ if not _set_binops_check_strict(self, value):
return NotImplemented
for item in value:
self.discard(item)
@@ -1247,7 +1267,7 @@ def _set_decorators():
def __iand__(fn):
def __iand__(self, other):
- if sautil.duck_type_collection(other) is not Set:
+ if not _set_binops_check_strict(self, other):
return NotImplemented
want, have = self.intersection(other), Set(self)
remove, add = have - want, want - have
@@ -1274,7 +1294,7 @@ def _set_decorators():
def __ixor__(fn):
def __ixor__(self, other):
- if sautil.duck_type_collection(other) is not Set:
+ if not _set_binops_check_strict(self, other):
return NotImplemented
want, have = self.symmetric_difference(other), Set(self)
remove, add = have - want, want - have