modernize adapt_like_to_iterable

Issue #3457 resolved
Mike Bayer repo owner created an issue

a lot of time is wasted here duck typing the object's current collection, when this is a fixed value. this is run on every list assignment so this should be fixed up. there is also the notion that if the target collection falls under the category of list or set, the incoming object would be checked only that it is an iterable, that is #3456, however that is a more controversial change.

Comments (4)

  1. Mike Bayer reporter
    diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
    index a45c223..4692cca 100644
    --- a/lib/sqlalchemy/orm/attributes.py
    +++ b/lib/sqlalchemy/orm/attributes.py
    @@ -1017,8 +1017,12 @@ class CollectionAttributeImpl(AttributeImpl):
    
             """
    
    +        # the fact that we are calling a new method here, _set_iterable
    +        # is not called from anywhere else: expensive
             self._set_iterable(
                 state, dict_, value,
    +            # lambda: expensive
    +            # adapt_like_to_iterable doesn't even need to be on the CollectionAdapter
                 lambda adapter, i: adapter.adapt_like_to_iterable(i))
    
         def _set_iterable(self, state, dict_, iterable, adapter=None):
    diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
    index 4f988a8..b07aa16 100644
    --- a/lib/sqlalchemy/orm/collections.py
    +++ b/lib/sqlalchemy/orm/collections.py
    @@ -617,11 +617,21 @@ class CollectionAdapter(object):
             a default duck-typing-based implementation is used.
    
             """
    +
    +        # the whole method here should be moved to the attribute.
    +        # for backwards comapt here, we say:
    +        # return self.attr._adapt_like_to_iterable(obj)
    +
    +        # checking this every time when we already know from collection_class
    +        # if it's there: expensive
             converter = self._data()._sa_converter
             if converter is not None:
                 return converter(obj)
    
             setting_type = util.duck_type_collection(obj)
    +
    +        # checking this every time when we already know from collection_class
    +        # what it is: expensive
             receiving_type = util.duck_type_collection(self._data())
    
             if obj is None or setting_type != receiving_type:
    
  2. Mike Bayer reporter

    additionally look into getting rid of MappedCollection._convert in its current form; we should take the keys as given and work just like a __setitem__ operation does, and not spend all the time re-fetching keys from the values. Validation of keys should be only an optional thing that one does with events.

  3. Mike Bayer reporter
    • refactor of adapt_like_to_iterable(), fixes #3457. Includes removal of adapt_like_to_iterable() as well as _set_iterable(), uses slots for collectionadapter, does much less duck typing of collections.

    → <<cset b606e47ddc54>>

  4. Log in to comment