- Fixed duplicate append event emission on repeated
instrumented set.add() operations.
+ - set-based collections |=, -=, ^= and &= are stricter about
+ their operands and only operate on sets, frozensets or
+ subclasses of the collection type. Previously, they would
+ accept any duck-typed set.
+
- declarative extension
- Joined table inheritance mappers use a slightly relaxed
function to create the "inherit condition" to the parent
the databsae state cleanup (eg. issuing a rollback()) when
connections are returned to the pool.
+-ext
+ - set-based association proxies |=, -=, ^= and &= are
+ stricter about their operands and only operate on sets,
+ frozensets or other association proxies. Previously, they
+ would accept any duck-typed set.
+
- mssql
- Added "odbc_autotranslate" parameter to engine / dburi
parameters. Any given string will be passed through to the
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):
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)
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)
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)
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)
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
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."""
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)
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)
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
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
for other in (set(['a','b','c']), set(['a','b','c','d']),
set(['a']), set(['a','b']),
set(['c','d']), set(['e', 'f', 'g']),
+ frozenset(['e', 'f', 'g']),
set()):
p = Parent('p')
p.children = base[:]
control |= values
assert_eq()
+ values = frozenset([e, creator()])
+ obj.attr |= values
+ control |= values
+ assert_eq()
+
try:
direct |= [e, creator()]
assert False
control -= values
assert_eq()
+ values = frozenset([creator()])
+ obj.attr -= values
+ control -= values
+ assert_eq()
+
try:
direct -= [e, creator()]
assert False