diff options
Diffstat (limited to 'lib/sqlalchemy/orm/collections.py')
| -rw-r--r-- | lib/sqlalchemy/orm/collections.py | 75 |
1 files changed, 21 insertions, 54 deletions
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py index 4f988a8d4..58a69227c 100644 --- a/lib/sqlalchemy/orm/collections.py +++ b/lib/sqlalchemy/orm/collections.py @@ -111,6 +111,7 @@ from ..sql import expression from .. import util, exc as sa_exc from . import base +from sqlalchemy.util.compat import inspect_getargspec __all__ = ['collection', 'collection_adapter', 'mapped_collection', 'column_mapped_collection', @@ -573,13 +574,18 @@ class CollectionAdapter(object): """ - invalidated = False + + __slots__ = ( + 'attr', '_key', '_data', 'owner_state', '_converter', 'invalidated') def __init__(self, attr, owner_state, data): + self.attr = attr self._key = attr.key self._data = weakref.ref(data) self.owner_state = owner_state data._sa_adapter = self + self._converter = data._sa_converter + self.invalidated = False def _warn_invalidated(self): util.warn("This collection has been invalidated.") @@ -599,53 +605,8 @@ class CollectionAdapter(object): """ return self.owner_state.dict[self._key] is self._data() - @util.memoized_property - def attr(self): - return self.owner_state.manager[self._key].impl - - def adapt_like_to_iterable(self, obj): - """Converts collection-compatible objects to an iterable of values. - - Can be passed any type of object, and if the underlying collection - determines that it can be adapted into a stream of values it can - use, returns an iterable of values suitable for append()ing. - - This method may raise TypeError or any other suitable exception - if adaptation fails. - - If a converter implementation is not supplied on the collection, - a default duck-typing-based implementation is used. - - """ - converter = self._data()._sa_converter - if converter is not None: - return converter(obj) - - setting_type = util.duck_type_collection(obj) - receiving_type = util.duck_type_collection(self._data()) - - if obj is None or setting_type != receiving_type: - given = obj is None and 'None' or obj.__class__.__name__ - if receiving_type is None: - wanted = self._data().__class__.__name__ - else: - wanted = receiving_type.__name__ - - raise TypeError( - "Incompatible collection type: %s is not %s-like" % ( - given, wanted)) - - # If the object is an adapted collection, return the (iterable) - # adapter. - if getattr(obj, '_sa_adapter', None) is not None: - return obj._sa_adapter - elif setting_type == dict: - if util.py3k: - return obj.values() - else: - return getattr(obj, 'itervalues', obj.values)() - else: - return iter(obj) + def bulk_appender(self): + return self._data()._sa_appender def append_with_event(self, item, initiator=None): """Add an entity to the collection, firing mutation events.""" @@ -662,6 +623,9 @@ class CollectionAdapter(object): for item in items: appender(item, _sa_initiator=False) + def bulk_remover(self): + return self._data()._sa_remover + def remove_with_event(self, item, initiator=None): """Remove an entity from the collection, firing mutation events.""" self._data()._sa_remover(item, _sa_initiator=initiator) @@ -776,8 +740,8 @@ def bulk_replace(values, existing_adapter, new_adapter): """ - if not isinstance(values, list): - values = list(values) + + assert isinstance(values, list) idset = util.IdentitySet existing_idset = idset(existing_adapter or ()) @@ -785,15 +749,18 @@ def bulk_replace(values, existing_adapter, new_adapter): additions = idset(values or ()).difference(constants) removals = existing_idset.difference(constants) + appender = new_adapter.bulk_appender() + for member in values or (): if member in additions: - new_adapter.append_with_event(member) + appender(member) elif member in constants: - new_adapter.append_without_event(member) + appender(member, _sa_initiator=False) if existing_adapter: + remover = existing_adapter.bulk_remover() for member in removals: - existing_adapter.remove_with_event(member) + remover(member) def prepare_instrumentation(factory): @@ -982,7 +949,7 @@ def _instrument_membership_mutator(method, before, argument, after): adapter.""" # This isn't smart enough to handle @adds(1) for 'def fn(self, (a, b))' if before: - fn_args = list(util.flatten_iterator(inspect.getargspec(method)[0])) + fn_args = list(util.flatten_iterator(inspect_getargspec(method)[0])) if isinstance(argument, int): pos_arg = argument named_arg = len(fn_args) > argument and fn_args[argument] or None |
