summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/attributes.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r--lib/sqlalchemy/orm/attributes.py781
1 files changed, 507 insertions, 274 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index b08c46741..1648c9ae1 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -20,19 +20,37 @@ from . import interfaces, collections, exc as orm_exc
from .base import instance_state, instance_dict, manager_of_class
-from .base import PASSIVE_NO_RESULT, ATTR_WAS_SET, ATTR_EMPTY, NO_VALUE,\
- NEVER_SET, NO_CHANGE, CALLABLES_OK, SQL_OK, RELATED_OBJECT_OK,\
- INIT_OK, NON_PERSISTENT_OK, LOAD_AGAINST_COMMITTED, PASSIVE_OFF,\
- PASSIVE_RETURN_NEVER_SET, PASSIVE_NO_INITIALIZE, PASSIVE_NO_FETCH,\
- PASSIVE_NO_FETCH_RELATED, PASSIVE_ONLY_PERSISTENT, NO_AUTOFLUSH, \
- NO_RAISE
+from .base import (
+ PASSIVE_NO_RESULT,
+ ATTR_WAS_SET,
+ ATTR_EMPTY,
+ NO_VALUE,
+ NEVER_SET,
+ NO_CHANGE,
+ CALLABLES_OK,
+ SQL_OK,
+ RELATED_OBJECT_OK,
+ INIT_OK,
+ NON_PERSISTENT_OK,
+ LOAD_AGAINST_COMMITTED,
+ PASSIVE_OFF,
+ PASSIVE_RETURN_NEVER_SET,
+ PASSIVE_NO_INITIALIZE,
+ PASSIVE_NO_FETCH,
+ PASSIVE_NO_FETCH_RELATED,
+ PASSIVE_ONLY_PERSISTENT,
+ NO_AUTOFLUSH,
+ NO_RAISE,
+)
from .base import state_str, instance_str
@inspection._self_inspects
-class QueryableAttribute(interfaces._MappedAttribute,
- interfaces.InspectionAttr,
- interfaces.PropComparator):
+class QueryableAttribute(
+ interfaces._MappedAttribute,
+ interfaces.InspectionAttr,
+ interfaces.PropComparator,
+):
"""Base class for :term:`descriptor` objects that intercept
attribute events on behalf of a :class:`.MapperProperty`
object. The actual :class:`.MapperProperty` is accessible
@@ -53,9 +71,15 @@ class QueryableAttribute(interfaces._MappedAttribute,
is_attribute = True
- def __init__(self, class_, key, impl=None,
- comparator=None, parententity=None,
- of_type=None):
+ def __init__(
+ self,
+ class_,
+ key,
+ impl=None,
+ comparator=None,
+ parententity=None,
+ of_type=None,
+ ):
self.class_ = class_
self.key = key
self.impl = impl
@@ -77,8 +101,9 @@ class QueryableAttribute(interfaces._MappedAttribute,
return self.impl.supports_population
def get_history(self, instance, passive=PASSIVE_OFF):
- return self.impl.get_history(instance_state(instance),
- instance_dict(instance), passive)
+ return self.impl.get_history(
+ instance_state(instance), instance_dict(instance), passive
+ )
def __selectable__(self):
# TODO: conditionally attach this method based on clause_element ?
@@ -159,11 +184,13 @@ class QueryableAttribute(interfaces._MappedAttribute,
def adapt_to_entity(self, adapt_to_entity):
assert not self._of_type
- return self.__class__(adapt_to_entity.entity,
- self.key, impl=self.impl,
- comparator=self.comparator.adapt_to_entity(
- adapt_to_entity),
- parententity=adapt_to_entity)
+ return self.__class__(
+ adapt_to_entity.entity,
+ self.key,
+ impl=self.impl,
+ comparator=self.comparator.adapt_to_entity(adapt_to_entity),
+ parententity=adapt_to_entity,
+ )
def of_type(self, cls):
return QueryableAttribute(
@@ -172,7 +199,8 @@ class QueryableAttribute(interfaces._MappedAttribute,
self.impl,
self.comparator.of_type(cls),
self._parententity,
- of_type=cls)
+ of_type=cls,
+ )
def label(self, name):
return self._query_clause_element().label(name)
@@ -191,12 +219,14 @@ class QueryableAttribute(interfaces._MappedAttribute,
return getattr(self.comparator, key)
except AttributeError:
raise AttributeError(
- 'Neither %r object nor %r object associated with %s '
- 'has an attribute %r' % (
+ "Neither %r object nor %r object associated with %s "
+ "has an attribute %r"
+ % (
type(self).__name__,
type(self.comparator).__name__,
self,
- key)
+ key,
+ )
)
def __str__(self):
@@ -226,8 +256,9 @@ class InstrumentedAttribute(QueryableAttribute):
"""
def __set__(self, instance, value):
- self.impl.set(instance_state(instance),
- instance_dict(instance), value, None)
+ self.impl.set(
+ instance_state(instance), instance_dict(instance), value, None
+ )
def __delete__(self, instance):
self.impl.delete(instance_state(instance), instance_dict(instance))
@@ -260,10 +291,16 @@ def create_proxied_attribute(descriptor):
"""
- def __init__(self, class_, key, descriptor,
- comparator,
- adapt_to_entity=None, doc=None,
- original_property=None):
+ def __init__(
+ self,
+ class_,
+ key,
+ descriptor,
+ comparator,
+ adapt_to_entity=None,
+ doc=None,
+ original_property=None,
+ ):
self.class_ = class_
self.key = key
self.descriptor = descriptor
@@ -284,15 +321,18 @@ def create_proxied_attribute(descriptor):
self._comparator = self._comparator()
if self._adapt_to_entity:
self._comparator = self._comparator.adapt_to_entity(
- self._adapt_to_entity)
+ self._adapt_to_entity
+ )
return self._comparator
def adapt_to_entity(self, adapt_to_entity):
- return self.__class__(adapt_to_entity.entity,
- self.key,
- self.descriptor,
- self._comparator,
- adapt_to_entity)
+ return self.__class__(
+ adapt_to_entity.entity,
+ self.key,
+ self.descriptor,
+ self._comparator,
+ adapt_to_entity,
+ )
def __get__(self, instance, owner):
if instance is None:
@@ -314,21 +354,24 @@ def create_proxied_attribute(descriptor):
return getattr(self.comparator, attribute)
except AttributeError:
raise AttributeError(
- 'Neither %r object nor %r object associated with %s '
- 'has an attribute %r' % (
+ "Neither %r object nor %r object associated with %s "
+ "has an attribute %r"
+ % (
type(descriptor).__name__,
type(self.comparator).__name__,
self,
- attribute)
+ attribute,
+ )
)
- Proxy.__name__ = type(descriptor).__name__ + 'Proxy'
+ Proxy.__name__ = type(descriptor).__name__ + "Proxy"
- util.monkeypatch_proxied_specials(Proxy, type(descriptor),
- name='descriptor',
- from_instance=descriptor)
+ util.monkeypatch_proxied_specials(
+ Proxy, type(descriptor), name="descriptor", from_instance=descriptor
+ )
return Proxy
+
OP_REMOVE = util.symbol("REMOVE")
OP_APPEND = util.symbol("APPEND")
OP_REPLACE = util.symbol("REPLACE")
@@ -364,7 +407,7 @@ class Event(object):
"""
- __slots__ = 'impl', 'op', 'parent_token'
+ __slots__ = "impl", "op", "parent_token"
def __init__(self, attribute_impl, op):
self.impl = attribute_impl
@@ -372,9 +415,11 @@ class Event(object):
self.parent_token = self.impl.parent_token
def __eq__(self, other):
- return isinstance(other, Event) and \
- other.impl is self.impl and \
- other.op == self.op
+ return (
+ isinstance(other, Event)
+ and other.impl is self.impl
+ and other.op == self.op
+ )
@property
def key(self):
@@ -387,12 +432,22 @@ class Event(object):
class AttributeImpl(object):
"""internal implementation for instrumented attributes."""
- def __init__(self, class_, key,
- callable_, dispatch, trackparent=False, extension=None,
- compare_function=None, active_history=False,
- parent_token=None, expire_missing=True,
- send_modified_events=True, accepts_scalar_loader=None,
- **kwargs):
+ def __init__(
+ self,
+ class_,
+ key,
+ callable_,
+ dispatch,
+ trackparent=False,
+ extension=None,
+ compare_function=None,
+ active_history=False,
+ parent_token=None,
+ expire_missing=True,
+ send_modified_events=True,
+ accepts_scalar_loader=None,
+ **kwargs
+ ):
r"""Construct an AttributeImpl.
\class_
@@ -471,9 +526,17 @@ class AttributeImpl(object):
self._modified_token = Event(self, OP_MODIFIED)
__slots__ = (
- 'class_', 'key', 'callable_', 'dispatch', 'trackparent',
- 'parent_token', 'send_modified_events', 'is_equal', 'expire_missing',
- '_modified_token', 'accepts_scalar_loader'
+ "class_",
+ "key",
+ "callable_",
+ "dispatch",
+ "trackparent",
+ "parent_token",
+ "send_modified_events",
+ "is_equal",
+ "expire_missing",
+ "_modified_token",
+ "accepts_scalar_loader",
)
def __str__(self):
@@ -508,8 +571,9 @@ class AttributeImpl(object):
msg = "This AttributeImpl is not configured to track parents."
assert self.trackparent, msg
- return state.parents.get(id(self.parent_token), optimistic) \
- is not False
+ return (
+ state.parents.get(id(self.parent_token), optimistic) is not False
+ )
def sethasparent(self, state, parent_state, value):
"""Set a boolean flag on the given item corresponding to
@@ -527,8 +591,10 @@ class AttributeImpl(object):
if id_ in state.parents:
last_parent = state.parents[id_]
- if last_parent is not False and \
- last_parent.key != parent_state.key:
+ if (
+ last_parent is not False
+ and last_parent.key != parent_state.key
+ ):
if last_parent.obj() is None:
raise orm_exc.StaleDataError(
@@ -536,10 +602,13 @@ class AttributeImpl(object):
"state %s along attribute '%s', "
"but the parent record "
"has gone stale, can't be sure this "
- "is the most recent parent." %
- (state_str(state),
- state_str(parent_state),
- self.key))
+ "is the most recent parent."
+ % (
+ state_str(state),
+ state_str(parent_state),
+ self.key,
+ )
+ )
return
@@ -588,8 +657,10 @@ class AttributeImpl(object):
else:
# if history present, don't load
key = self.key
- if key not in state.committed_state or \
- state.committed_state[key] is NEVER_SET:
+ if (
+ key not in state.committed_state
+ or state.committed_state[key] is NEVER_SET
+ ):
if not passive & CALLABLES_OK:
return PASSIVE_NO_RESULT
@@ -613,7 +684,8 @@ class AttributeImpl(object):
raise KeyError(
"Deferred loader for attribute "
"%r failed to populate "
- "correctly" % key)
+ "correctly" % key
+ )
elif value is not ATTR_EMPTY:
return self.set_committed_value(state, dict_, value)
@@ -627,15 +699,31 @@ class AttributeImpl(object):
self.set(state, dict_, value, initiator, passive=passive)
def remove(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
- self.set(state, dict_, None, initiator,
- passive=passive, check_old=value)
+ self.set(
+ state, dict_, None, initiator, passive=passive, check_old=value
+ )
def pop(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
- self.set(state, dict_, None, initiator,
- passive=passive, check_old=value, pop=True)
+ self.set(
+ state,
+ dict_,
+ None,
+ initiator,
+ passive=passive,
+ check_old=value,
+ pop=True,
+ )
- def set(self, state, dict_, value, initiator,
- passive=PASSIVE_OFF, check_old=None, pop=False):
+ def set(
+ self,
+ state,
+ dict_,
+ value,
+ initiator,
+ passive=PASSIVE_OFF,
+ check_old=None,
+ pop=False,
+ ):
raise NotImplementedError()
def get_committed_value(self, state, dict_, passive=PASSIVE_OFF):
@@ -667,7 +755,7 @@ class ScalarAttributeImpl(AttributeImpl):
collection = False
dynamic = False
- __slots__ = '_replace_token', '_append_token', '_remove_token'
+ __slots__ = "_replace_token", "_append_token", "_remove_token"
def __init__(self, *arg, **kw):
super(ScalarAttributeImpl, self).__init__(*arg, **kw)
@@ -685,10 +773,13 @@ class ScalarAttributeImpl(AttributeImpl):
state._modified_event(dict_, self, old)
existing = dict_.pop(self.key, NO_VALUE)
- if existing is NO_VALUE and old is NO_VALUE and \
- not state.expired and \
- self.key not in state.expired_attributes:
- raise AttributeError("%s object does not have a value" % self)
+ if (
+ existing is NO_VALUE
+ and old is NO_VALUE
+ and not state.expired
+ and self.key not in state.expired_attributes
+ ):
+ raise AttributeError("%s object does not have a value" % self)
def get_history(self, state, dict_, passive=PASSIVE_OFF):
if self.key in dict_:
@@ -702,23 +793,33 @@ class ScalarAttributeImpl(AttributeImpl):
else:
return History.from_scalar_attribute(self, state, current)
- def set(self, state, dict_, value, initiator,
- passive=PASSIVE_OFF, check_old=None, pop=False):
+ def set(
+ self,
+ state,
+ dict_,
+ value,
+ initiator,
+ passive=PASSIVE_OFF,
+ check_old=None,
+ pop=False,
+ ):
if self.dispatch._active_history:
old = self.get(state, dict_, PASSIVE_RETURN_NEVER_SET)
else:
old = dict_.get(self.key, NO_VALUE)
if self.dispatch.set:
- value = self.fire_replace_event(state, dict_,
- value, old, initiator)
+ value = self.fire_replace_event(
+ state, dict_, value, old, initiator
+ )
state._modified_event(dict_, self, old)
dict_[self.key] = value
def fire_replace_event(self, state, dict_, value, previous, initiator):
for fn in self.dispatch.set:
value = fn(
- state, value, previous, initiator or self._replace_token)
+ state, value, previous, initiator or self._replace_token
+ )
return value
def fire_remove_event(self, state, dict_, value, initiator):
@@ -748,13 +849,20 @@ class ScalarObjectAttributeImpl(ScalarAttributeImpl):
def delete(self, state, dict_):
if self.dispatch._active_history:
old = self.get(
- state, dict_,
- passive=PASSIVE_ONLY_PERSISTENT |
- NO_AUTOFLUSH | LOAD_AGAINST_COMMITTED)
+ state,
+ dict_,
+ passive=PASSIVE_ONLY_PERSISTENT
+ | NO_AUTOFLUSH
+ | LOAD_AGAINST_COMMITTED,
+ )
else:
old = self.get(
- state, dict_, passive=PASSIVE_NO_FETCH ^ INIT_OK |
- LOAD_AGAINST_COMMITTED | NO_RAISE)
+ state,
+ dict_,
+ passive=PASSIVE_NO_FETCH ^ INIT_OK
+ | LOAD_AGAINST_COMMITTED
+ | NO_RAISE,
+ )
self.fire_remove_event(state, dict_, old, self._remove_token)
@@ -763,8 +871,11 @@ class ScalarObjectAttributeImpl(ScalarAttributeImpl):
# if the attribute is expired, we currently have no way to tell
# that an object-attribute was expired vs. not loaded. So
# for this test, we look to see if the object has a DB identity.
- if existing is NO_VALUE and old is not PASSIVE_NO_RESULT and \
- state.key is None:
+ if (
+ existing is NO_VALUE
+ and old is not PASSIVE_NO_RESULT
+ and state.key is None
+ ):
raise AttributeError("%s object does not have a value" % self)
def get_history(self, state, dict_, passive=PASSIVE_OFF):
@@ -788,50 +899,69 @@ class ScalarObjectAttributeImpl(ScalarAttributeImpl):
return []
# can't use __hash__(), can't use __eq__() here
- if current is not None and \
- current is not PASSIVE_NO_RESULT and \
- current is not NEVER_SET:
+ if (
+ current is not None
+ and current is not PASSIVE_NO_RESULT
+ and current is not NEVER_SET
+ ):
ret = [(instance_state(current), current)]
else:
ret = [(None, None)]
if self.key in state.committed_state:
original = state.committed_state[self.key]
- if original is not None and \
- original is not PASSIVE_NO_RESULT and \
- original is not NEVER_SET and \
- original is not current:
+ if (
+ original is not None
+ and original is not PASSIVE_NO_RESULT
+ and original is not NEVER_SET
+ and original is not current
+ ):
ret.append((instance_state(original), original))
return ret
- def set(self, state, dict_, value, initiator,
- passive=PASSIVE_OFF, check_old=None, pop=False):
+ def set(
+ self,
+ state,
+ dict_,
+ value,
+ initiator,
+ passive=PASSIVE_OFF,
+ check_old=None,
+ pop=False,
+ ):
"""Set a value on the given InstanceState.
"""
if self.dispatch._active_history:
old = self.get(
- state, dict_,
- passive=PASSIVE_ONLY_PERSISTENT |
- NO_AUTOFLUSH | LOAD_AGAINST_COMMITTED)
+ state,
+ dict_,
+ passive=PASSIVE_ONLY_PERSISTENT
+ | NO_AUTOFLUSH
+ | LOAD_AGAINST_COMMITTED,
+ )
else:
old = self.get(
- state, dict_, passive=PASSIVE_NO_FETCH ^ INIT_OK |
- LOAD_AGAINST_COMMITTED | NO_RAISE)
+ state,
+ dict_,
+ passive=PASSIVE_NO_FETCH ^ INIT_OK
+ | LOAD_AGAINST_COMMITTED
+ | NO_RAISE,
+ )
- if check_old is not None and \
- old is not PASSIVE_NO_RESULT and \
- check_old is not old:
+ if (
+ check_old is not None
+ and old is not PASSIVE_NO_RESULT
+ and check_old is not old
+ ):
if pop:
return
else:
raise ValueError(
- "Object %s not associated with %s on attribute '%s'" % (
- instance_str(check_old),
- state_str(state),
- self.key
- ))
+ "Object %s not associated with %s on attribute '%s'"
+ % (instance_str(check_old), state_str(state), self.key)
+ )
value = self.fire_replace_event(state, dict_, value, old, initiator)
dict_[self.key] = value
@@ -847,13 +977,17 @@ class ScalarObjectAttributeImpl(ScalarAttributeImpl):
def fire_replace_event(self, state, dict_, value, previous, initiator):
if self.trackparent:
- if (previous is not value and
- previous not in (None, PASSIVE_NO_RESULT, NEVER_SET)):
+ if previous is not value and previous not in (
+ None,
+ PASSIVE_NO_RESULT,
+ NEVER_SET,
+ ):
self.sethasparent(instance_state(previous), state, False)
for fn in self.dispatch.set:
value = fn(
- state, value, previous, initiator or self._replace_token)
+ state, value, previous, initiator or self._replace_token
+ )
state._modified_event(dict_, self, previous)
@@ -875,6 +1009,7 @@ class CollectionAttributeImpl(AttributeImpl):
semantics to the orm layer independent of the user data implementation.
"""
+
default_accepts_scalar_loader = False
uses_objects = True
supports_population = True
@@ -882,21 +1017,37 @@ class CollectionAttributeImpl(AttributeImpl):
dynamic = False
__slots__ = (
- 'copy', 'collection_factory', '_append_token', '_remove_token',
- '_bulk_replace_token', '_duck_typed_as'
+ "copy",
+ "collection_factory",
+ "_append_token",
+ "_remove_token",
+ "_bulk_replace_token",
+ "_duck_typed_as",
)
- def __init__(self, class_, key, callable_, dispatch,
- typecallable=None, trackparent=False, extension=None,
- copy_function=None, compare_function=None, **kwargs):
+ def __init__(
+ self,
+ class_,
+ key,
+ callable_,
+ dispatch,
+ typecallable=None,
+ trackparent=False,
+ extension=None,
+ copy_function=None,
+ compare_function=None,
+ **kwargs
+ ):
super(CollectionAttributeImpl, self).__init__(
class_,
key,
- callable_, dispatch,
+ callable_,
+ dispatch,
trackparent=trackparent,
extension=extension,
compare_function=compare_function,
- **kwargs)
+ **kwargs
+ )
if copy_function is None:
copy_function = self.__copy
@@ -906,7 +1057,8 @@ class CollectionAttributeImpl(AttributeImpl):
self._remove_token = Event(self, OP_REMOVE)
self._bulk_replace_token = Event(self, OP_BULK_REPLACE)
self._duck_typed_as = util.duck_type_collection(
- self.collection_factory())
+ self.collection_factory()
+ )
if getattr(self.collection_factory, "_sa_linker", None):
@@ -935,35 +1087,42 @@ class CollectionAttributeImpl(AttributeImpl):
return []
current = dict_[self.key]
- current = getattr(current, '_sa_adapter')
+ current = getattr(current, "_sa_adapter")
if self.key in state.committed_state:
original = state.committed_state[self.key]
if original not in (NO_VALUE, NEVER_SET):
- current_states = [((c is not None) and
- instance_state(c) or None, c)
- for c in current]
- original_states = [((c is not None) and
- instance_state(c) or None, c)
- for c in original]
+ current_states = [
+ ((c is not None) and instance_state(c) or None, c)
+ for c in current
+ ]
+ original_states = [
+ ((c is not None) and instance_state(c) or None, c)
+ for c in original
+ ]
current_set = dict(current_states)
original_set = dict(original_states)
- return \
- [(s, o) for s, o in current_states
- if s not in original_set] + \
- [(s, o) for s, o in current_states
- if s in original_set] + \
- [(s, o) for s, o in original_states
- if s not in current_set]
+ return (
+ [
+ (s, o)
+ for s, o in current_states
+ if s not in original_set
+ ]
+ + [(s, o) for s, o in current_states if s in original_set]
+ + [
+ (s, o)
+ for s, o in original_states
+ if s not in current_set
+ ]
+ )
return [(instance_state(o), o) for o in current]
def fire_append_event(self, state, dict_, value, initiator):
for fn in self.dispatch.append:
- value = fn(
- state, value, initiator or self._append_token)
+ value = fn(state, value, initiator or self._append_token)
state._modified_event(dict_, self, NEVER_SET, True)
@@ -1015,7 +1174,8 @@ class CollectionAttributeImpl(AttributeImpl):
def _initialize_collection(self, state):
adapter, collection = state.manager.initialize_collection(
- self.key, state, self.collection_factory)
+ self.key, state, self.collection_factory
+ )
self.dispatch.init_collection(state, collection, adapter)
@@ -1025,8 +1185,9 @@ class CollectionAttributeImpl(AttributeImpl):
collection = self.get_collection(state, dict_, passive=passive)
if collection is PASSIVE_NO_RESULT:
value = self.fire_append_event(state, dict_, value, initiator)
- assert self.key not in dict_, \
- "Collection was loaded during event handling."
+ assert (
+ self.key not in dict_
+ ), "Collection was loaded during event handling."
state._get_pending_mutation(self.key).append(value)
else:
collection.append_with_event(value, initiator)
@@ -1035,8 +1196,9 @@ class CollectionAttributeImpl(AttributeImpl):
collection = self.get_collection(state, state.dict, passive=passive)
if collection is PASSIVE_NO_RESULT:
self.fire_remove_event(state, dict_, value, initiator)
- assert self.key not in dict_, \
- "Collection was loaded during event handling."
+ assert (
+ self.key not in dict_
+ ), "Collection was loaded during event handling."
state._get_pending_mutation(self.key).remove(value)
else:
collection.remove_with_event(value, initiator)
@@ -1050,8 +1212,16 @@ class CollectionAttributeImpl(AttributeImpl):
except (ValueError, KeyError, IndexError):
pass
- def set(self, state, dict_, value, initiator=None,
- passive=PASSIVE_OFF, pop=False, _adapt=True):
+ def set(
+ self,
+ state,
+ dict_,
+ value,
+ initiator=None,
+ passive=PASSIVE_OFF,
+ pop=False,
+ _adapt=True,
+ ):
iterable = orig_iterable = value
# pulling a new collection first so that an adaptation exception does
@@ -1065,23 +1235,28 @@ class CollectionAttributeImpl(AttributeImpl):
receiving_type = self._duck_typed_as
if setting_type is not receiving_type:
- given = iterable is None and 'None' or \
- iterable.__class__.__name__
+ given = (
+ iterable is None
+ and "None"
+ or iterable.__class__.__name__
+ )
wanted = self._duck_typed_as.__name__
raise TypeError(
- "Incompatible collection type: %s is not %s-like" % (
- given, wanted))
+ "Incompatible collection type: %s is not %s-like"
+ % (given, wanted)
+ )
# If the object is an adapted collection, return the (iterable)
# adapter.
- if hasattr(iterable, '_sa_iterator'):
+ if hasattr(iterable, "_sa_iterator"):
iterable = iterable._sa_iterator()
elif setting_type is dict:
if util.py3k:
iterable = iterable.values()
else:
iterable = getattr(
- iterable, 'itervalues', iterable.values)()
+ iterable, "itervalues", iterable.values
+ )()
else:
iterable = iter(iterable)
new_values = list(iterable)
@@ -1106,14 +1281,14 @@ class CollectionAttributeImpl(AttributeImpl):
dict_[self.key] = user_data
collections.bulk_replace(
- new_values, old_collection, new_collection,
- initiator=evt)
+ new_values, old_collection, new_collection, initiator=evt
+ )
del old._sa_adapter
self.dispatch.dispose_collection(state, old, old_collection)
def _invalidate_collection(self, collection):
- adapter = getattr(collection, '_sa_adapter')
+ adapter = getattr(collection, "_sa_adapter")
adapter.invalidated = True
def set_committed_value(self, state, dict_, value):
@@ -1143,8 +1318,9 @@ class CollectionAttributeImpl(AttributeImpl):
return user_data
- def get_collection(self, state, dict_,
- user_data=None, passive=PASSIVE_OFF):
+ def get_collection(
+ self, state, dict_, user_data=None, passive=PASSIVE_OFF
+ ):
"""Retrieve the CollectionAdapter associated with the given state.
Creates a new CollectionAdapter if one does not exist.
@@ -1155,7 +1331,7 @@ class CollectionAttributeImpl(AttributeImpl):
if user_data is PASSIVE_NO_RESULT:
return user_data
- return getattr(user_data, '_sa_adapter')
+ return getattr(user_data, "_sa_adapter")
def backref_listeners(attribute, key, uselist):
@@ -1177,24 +1353,29 @@ def backref_listeners(attribute, key, uselist):
"Bidirectional attribute conflict detected: "
'Passing object %s to attribute "%s" '
'triggers a modify event on attribute "%s" '
- 'via the backref "%s".' % (
+ 'via the backref "%s".'
+ % (
state_str(child_state),
initiator.parent_token,
child_impl.parent_token,
- attribute.impl.parent_token
+ attribute.impl.parent_token,
)
)
def emit_backref_from_scalar_set_event(state, child, oldchild, initiator):
if oldchild is child:
return child
- if oldchild is not None and \
- oldchild is not PASSIVE_NO_RESULT and \
- oldchild is not NEVER_SET:
+ if (
+ oldchild is not None
+ and oldchild is not PASSIVE_NO_RESULT
+ and oldchild is not NEVER_SET
+ ):
# With lazy=None, there's no guarantee that the full collection is
# present when updating via a backref.
- old_state, old_dict = instance_state(oldchild),\
- instance_dict(oldchild)
+ old_state, old_dict = (
+ instance_state(oldchild),
+ instance_dict(oldchild),
+ )
impl = old_state.manager[key].impl
# tokens to test for a recursive loop.
@@ -1204,69 +1385,90 @@ def backref_listeners(attribute, key, uselist):
check_recursive_token = impl._remove_token
if initiator is not check_recursive_token:
- impl.pop(old_state,
- old_dict,
- state.obj(),
- parent_impl._append_token,
- passive=PASSIVE_NO_FETCH)
+ impl.pop(
+ old_state,
+ old_dict,
+ state.obj(),
+ parent_impl._append_token,
+ passive=PASSIVE_NO_FETCH,
+ )
if child is not None:
- child_state, child_dict = instance_state(child),\
- instance_dict(child)
+ child_state, child_dict = (
+ instance_state(child),
+ instance_dict(child),
+ )
child_impl = child_state.manager[key].impl
- if initiator.parent_token is not parent_token and \
- initiator.parent_token is not child_impl.parent_token:
+ if (
+ initiator.parent_token is not parent_token
+ and initiator.parent_token is not child_impl.parent_token
+ ):
_acceptable_key_err(state, initiator, child_impl)
# tokens to test for a recursive loop.
check_append_token = child_impl._append_token
- check_bulk_replace_token = child_impl._bulk_replace_token \
- if child_impl.collection else None
+ check_bulk_replace_token = (
+ child_impl._bulk_replace_token
+ if child_impl.collection
+ else None
+ )
- if initiator is not check_append_token and \
- initiator is not check_bulk_replace_token:
+ if (
+ initiator is not check_append_token
+ and initiator is not check_bulk_replace_token
+ ):
child_impl.append(
child_state,
child_dict,
state.obj(),
initiator,
- passive=PASSIVE_NO_FETCH)
+ passive=PASSIVE_NO_FETCH,
+ )
return child
def emit_backref_from_collection_append_event(state, child, initiator):
if child is None:
return
- child_state, child_dict = instance_state(child), \
- instance_dict(child)
+ child_state, child_dict = instance_state(child), instance_dict(child)
child_impl = child_state.manager[key].impl
- if initiator.parent_token is not parent_token and \
- initiator.parent_token is not child_impl.parent_token:
+ if (
+ initiator.parent_token is not parent_token
+ and initiator.parent_token is not child_impl.parent_token
+ ):
_acceptable_key_err(state, initiator, child_impl)
# tokens to test for a recursive loop.
check_append_token = child_impl._append_token
- check_bulk_replace_token = child_impl._bulk_replace_token \
- if child_impl.collection else None
+ check_bulk_replace_token = (
+ child_impl._bulk_replace_token if child_impl.collection else None
+ )
- if initiator is not check_append_token and \
- initiator is not check_bulk_replace_token:
+ if (
+ initiator is not check_append_token
+ and initiator is not check_bulk_replace_token
+ ):
child_impl.append(
child_state,
child_dict,
state.obj(),
initiator,
- passive=PASSIVE_NO_FETCH)
+ passive=PASSIVE_NO_FETCH,
+ )
return child
def emit_backref_from_collection_remove_event(state, child, initiator):
- if child is not None and \
- child is not PASSIVE_NO_RESULT and \
- child is not NEVER_SET:
- child_state, child_dict = instance_state(child),\
- instance_dict(child)
+ if (
+ child is not None
+ and child is not PASSIVE_NO_RESULT
+ and child is not NEVER_SET
+ ):
+ child_state, child_dict = (
+ instance_state(child),
+ instance_dict(child),
+ )
child_impl = child_state.manager[key].impl
# tokens to test for a recursive loop.
@@ -1276,47 +1478,64 @@ def backref_listeners(attribute, key, uselist):
check_for_dupes_on_remove = uselist and not parent_impl.dynamic
else:
check_remove_token = child_impl._remove_token
- check_replace_token = child_impl._bulk_replace_token \
- if child_impl.collection else None
+ check_replace_token = (
+ child_impl._bulk_replace_token
+ if child_impl.collection
+ else None
+ )
check_for_dupes_on_remove = False
- if initiator is not check_remove_token and \
- initiator is not check_replace_token:
-
- if not check_for_dupes_on_remove or \
- not util.has_dupes(
- # when this event is called, the item is usually
- # present in the list, except for a pop() operation.
- state.dict[parent_impl.key], child):
+ if (
+ initiator is not check_remove_token
+ and initiator is not check_replace_token
+ ):
+
+ if not check_for_dupes_on_remove or not util.has_dupes(
+ # when this event is called, the item is usually
+ # present in the list, except for a pop() operation.
+ state.dict[parent_impl.key],
+ child,
+ ):
child_impl.pop(
child_state,
child_dict,
state.obj(),
initiator,
- passive=PASSIVE_NO_FETCH)
+ passive=PASSIVE_NO_FETCH,
+ )
if uselist:
- event.listen(attribute, "append",
- emit_backref_from_collection_append_event,
- retval=True, raw=True)
+ event.listen(
+ attribute,
+ "append",
+ emit_backref_from_collection_append_event,
+ retval=True,
+ raw=True,
+ )
else:
- event.listen(attribute, "set",
- emit_backref_from_scalar_set_event,
- retval=True, raw=True)
+ event.listen(
+ attribute,
+ "set",
+ emit_backref_from_scalar_set_event,
+ retval=True,
+ raw=True,
+ )
# TODO: need coverage in test/orm/ of remove event
- event.listen(attribute, "remove",
- emit_backref_from_collection_remove_event,
- retval=True, raw=True)
+ event.listen(
+ attribute,
+ "remove",
+ emit_backref_from_collection_remove_event,
+ retval=True,
+ raw=True,
+ )
-_NO_HISTORY = util.symbol('NO_HISTORY')
-_NO_STATE_SYMBOLS = frozenset([
- id(PASSIVE_NO_RESULT),
- id(NO_VALUE),
- id(NEVER_SET)])
-History = util.namedtuple("History", [
- "added", "unchanged", "deleted"
-])
+_NO_HISTORY = util.symbol("NO_HISTORY")
+_NO_STATE_SYMBOLS = frozenset(
+ [id(PASSIVE_NO_RESULT), id(NO_VALUE), id(NEVER_SET)]
+)
+
+History = util.namedtuple("History", ["added", "unchanged", "deleted"])
class History(History):
@@ -1346,6 +1565,7 @@ class History(History):
def __bool__(self):
return self != HISTORY_BLANK
+
__nonzero__ = __bool__
def empty(self):
@@ -1354,29 +1574,24 @@ class History(History):
"""
- return not bool(
- (self.added or self.deleted)
- or self.unchanged
- )
+ return not bool((self.added or self.deleted) or self.unchanged)
def sum(self):
"""Return a collection of added + unchanged + deleted."""
- return (self.added or []) +\
- (self.unchanged or []) +\
- (self.deleted or [])
+ return (
+ (self.added or []) + (self.unchanged or []) + (self.deleted or [])
+ )
def non_deleted(self):
"""Return a collection of added + unchanged."""
- return (self.added or []) +\
- (self.unchanged or [])
+ return (self.added or []) + (self.unchanged or [])
def non_added(self):
"""Return a collection of unchanged + deleted."""
- return (self.unchanged or []) +\
- (self.deleted or [])
+ return (self.unchanged or []) + (self.deleted or [])
def has_changes(self):
"""Return True if this :class:`.History` has changes."""
@@ -1385,15 +1600,18 @@ class History(History):
def as_state(self):
return History(
- [(c is not None)
- and instance_state(c) or None
- for c in self.added],
- [(c is not None)
- and instance_state(c) or None
- for c in self.unchanged],
- [(c is not None)
- and instance_state(c) or None
- for c in self.deleted],
+ [
+ (c is not None) and instance_state(c) or None
+ for c in self.added
+ ],
+ [
+ (c is not None) and instance_state(c) or None
+ for c in self.unchanged
+ ],
+ [
+ (c is not None) and instance_state(c) or None
+ for c in self.deleted
+ ],
)
@classmethod
@@ -1464,21 +1682,21 @@ class History(History):
if current is NO_VALUE or current is NEVER_SET:
return cls((), (), ())
- current = getattr(current, '_sa_adapter')
+ current = getattr(current, "_sa_adapter")
if original in (NO_VALUE, NEVER_SET):
return cls(list(current), (), ())
elif original is _NO_HISTORY:
return cls((), list(current), ())
else:
- current_states = [((c is not None) and instance_state(c)
- or None, c)
- for c in current
- ]
- original_states = [((c is not None) and instance_state(c)
- or None, c)
- for c in original
- ]
+ current_states = [
+ ((c is not None) and instance_state(c) or None, c)
+ for c in current
+ ]
+ original_states = [
+ ((c is not None) and instance_state(c) or None, c)
+ for c in original
+ ]
current_set = dict(current_states)
original_set = dict(original_states)
@@ -1486,9 +1704,10 @@ class History(History):
return cls(
[o for s, o in current_states if s not in original_set],
[o for s, o in current_states if s in original_set],
- [o for s, o in original_states if s not in current_set]
+ [o for s, o in original_states if s not in current_set],
)
+
HISTORY_BLANK = History(None, None, None)
@@ -1509,12 +1728,16 @@ def get_history(obj, key, passive=PASSIVE_OFF):
"""
if passive is True:
- util.warn_deprecated("Passing True for 'passive' is deprecated. "
- "Use attributes.PASSIVE_NO_INITIALIZE")
+ util.warn_deprecated(
+ "Passing True for 'passive' is deprecated. "
+ "Use attributes.PASSIVE_NO_INITIALIZE"
+ )
passive = PASSIVE_NO_INITIALIZE
elif passive is False:
- util.warn_deprecated("Passing False for 'passive' is "
- "deprecated. Use attributes.PASSIVE_OFF")
+ util.warn_deprecated(
+ "Passing False for 'passive' is "
+ "deprecated. Use attributes.PASSIVE_OFF"
+ )
passive = PASSIVE_OFF
return get_state_history(instance_state(obj), key, passive)
@@ -1532,38 +1755,46 @@ def has_parent(cls, obj, key, optimistic=False):
def register_attribute(class_, key, **kw):
- comparator = kw.pop('comparator', None)
- parententity = kw.pop('parententity', None)
- doc = kw.pop('doc', None)
- desc = register_descriptor(class_, key,
- comparator, parententity, doc=doc)
+ comparator = kw.pop("comparator", None)
+ parententity = kw.pop("parententity", None)
+ doc = kw.pop("doc", None)
+ desc = register_descriptor(class_, key, comparator, parententity, doc=doc)
register_attribute_impl(class_, key, **kw)
return desc
-def register_attribute_impl(class_, key,
- uselist=False, callable_=None,
- useobject=False,
- impl_class=None, backref=None, **kw):
+def register_attribute_impl(
+ class_,
+ key,
+ uselist=False,
+ callable_=None,
+ useobject=False,
+ impl_class=None,
+ backref=None,
+ **kw
+):
manager = manager_of_class(class_)
if uselist:
- factory = kw.pop('typecallable', None)
+ factory = kw.pop("typecallable", None)
typecallable = manager.instrument_collection_class(
- key, factory or list)
+ key, factory or list
+ )
else:
- typecallable = kw.pop('typecallable', None)
+ typecallable = kw.pop("typecallable", None)
dispatch = manager[key].dispatch
if impl_class:
impl = impl_class(class_, key, typecallable, dispatch, **kw)
elif uselist:
- impl = CollectionAttributeImpl(class_, key, callable_, dispatch,
- typecallable=typecallable, **kw)
+ impl = CollectionAttributeImpl(
+ class_, key, callable_, dispatch, typecallable=typecallable, **kw
+ )
elif useobject:
- impl = ScalarObjectAttributeImpl(class_, key, callable_,
- dispatch, **kw)
+ impl = ScalarObjectAttributeImpl(
+ class_, key, callable_, dispatch, **kw
+ )
else:
impl = ScalarAttributeImpl(class_, key, callable_, dispatch, **kw)
@@ -1576,12 +1807,14 @@ def register_attribute_impl(class_, key,
return manager[key]
-def register_descriptor(class_, key, comparator=None,
- parententity=None, doc=None):
+def register_descriptor(
+ class_, key, comparator=None, parententity=None, doc=None
+):
manager = manager_of_class(class_)
- descriptor = InstrumentedAttribute(class_, key, comparator=comparator,
- parententity=parententity)
+ descriptor = InstrumentedAttribute(
+ class_, key, comparator=comparator, parententity=parententity
+ )
descriptor.__doc__ = doc