diff options
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 781 |
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 |