diff options
Diffstat (limited to 'lib/sqlalchemy/orm/strategies.py')
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 1144 |
1 files changed, 660 insertions, 484 deletions
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 47791f9b9..5c972b26b 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -13,22 +13,27 @@ from .. import util, log, event from ..sql import util as sql_util, visitors from .. import sql from . import ( - attributes, interfaces, exc as orm_exc, loading, - unitofwork, util as orm_util, query + attributes, + interfaces, + exc as orm_exc, + loading, + unitofwork, + util as orm_util, + query, ) from .state import InstanceState from .util import _none_set, aliased from . import properties -from .interfaces import ( - LoaderStrategy, StrategizedProperty -) +from .interfaces import LoaderStrategy, StrategizedProperty from .base import _SET_DEFERRED_EXPIRED, _DEFER_FOR_STATE from .session import _state_session import itertools def _register_attribute( - prop, mapper, useobject, + prop, + mapper, + useobject, compare_function=None, typecallable=None, callable_=None, @@ -51,8 +56,8 @@ def _register_attribute( fn, opts = prop.parent.validators[prop.key] listen_hooks.append( lambda desc, prop: orm_util._validator_events( - desc, - prop.key, fn, **opts) + desc, prop.key, fn, **opts + ) ) if useobject: @@ -65,9 +70,7 @@ def _register_attribute( if backref: listen_hooks.append( lambda desc, prop: attributes.backref_listeners( - desc, - backref, - uselist + desc, backref, uselist ) ) @@ -83,8 +86,9 @@ def _register_attribute( # on mappers not already being set up so we have to check each one. for m in mapper.self_and_descendants: - if prop is m._props.get(prop.key) and \ - not m.class_manager._attr_has_impl(prop.key): + if prop is m._props.get( + prop.key + ) and not m.class_manager._attr_has_impl(prop.key): desc = attributes.register_attribute_impl( m.class_, @@ -94,9 +98,11 @@ def _register_attribute( compare_function=compare_function, useobject=useobject, extension=attribute_ext, - trackparent=useobject and ( - prop.single_parent or - prop.direction is interfaces.ONETOMANY), + trackparent=useobject + and ( + prop.single_parent + or prop.direction is interfaces.ONETOMANY + ), typecallable=typecallable, callable_=callable_, active_history=active_history, @@ -118,23 +124,31 @@ class UninstrumentedColumnLoader(LoaderStrategy): if the argument is against the with_polymorphic selectable. """ - __slots__ = 'columns', + + __slots__ = ("columns",) def __init__(self, parent, strategy_key): super(UninstrumentedColumnLoader, self).__init__(parent, strategy_key) self.columns = self.parent_property.columns def setup_query( - self, context, entity, path, loadopt, adapter, - column_collection=None, **kwargs): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection=None, + **kwargs + ): for c in self.columns: if adapter: c = adapter.columns[c] column_collection.append(c) def create_row_processor( - self, context, path, loadopt, - mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): pass @@ -143,16 +157,24 @@ class UninstrumentedColumnLoader(LoaderStrategy): class ColumnLoader(LoaderStrategy): """Provide loading behavior for a :class:`.ColumnProperty`.""" - __slots__ = 'columns', 'is_composite' + __slots__ = "columns", "is_composite" def __init__(self, parent, strategy_key): super(ColumnLoader, self).__init__(parent, strategy_key) self.columns = self.parent_property.columns - self.is_composite = hasattr(self.parent_property, 'composite_class') + self.is_composite = hasattr(self.parent_property, "composite_class") def setup_query( - self, context, entity, path, loadopt, - adapter, column_collection, memoized_populators, **kwargs): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection, + memoized_populators, + **kwargs + ): for c in self.columns: if adapter: @@ -168,19 +190,23 @@ class ColumnLoader(LoaderStrategy): self.is_class_level = True coltype = self.columns[0].type # TODO: check all columns ? check for foreign key as well? - active_history = self.parent_property.active_history or \ - self.columns[0].primary_key or \ - mapper.version_id_col in set(self.columns) + active_history = ( + self.parent_property.active_history + or self.columns[0].primary_key + or mapper.version_id_col in set(self.columns) + ) _register_attribute( - self.parent_property, mapper, useobject=False, + self.parent_property, + mapper, + useobject=False, compare_function=coltype.compare_values, - active_history=active_history + active_history=active_history, ) def create_row_processor( - self, context, path, - loadopt, mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): # look through list of columns represented here # to see which, if any, is present in the row. for col in self.columns: @@ -201,8 +227,16 @@ class ExpressionColumnLoader(ColumnLoader): super(ExpressionColumnLoader, self).__init__(parent, strategy_key) def setup_query( - self, context, entity, path, loadopt, - adapter, column_collection, memoized_populators, **kwargs): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection, + memoized_populators, + **kwargs + ): if loadopt and "expression" in loadopt.local_opts: columns = [loadopt.local_opts["expression"]] @@ -218,8 +252,8 @@ class ExpressionColumnLoader(ColumnLoader): memoized_populators[self.parent_property] = fetch def create_row_processor( - self, context, path, - loadopt, mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): # look through list of columns represented here # to see which, if any, is present in the row. if loadopt and "expression" in loadopt.local_opts: @@ -239,9 +273,11 @@ class ExpressionColumnLoader(ColumnLoader): self.is_class_level = True _register_attribute( - self.parent_property, mapper, useobject=False, + self.parent_property, + mapper, + useobject=False, compare_function=self.columns[0].type.compare_values, - accepts_scalar_loader=False + accepts_scalar_loader=False, ) @@ -251,27 +287,29 @@ class ExpressionColumnLoader(ColumnLoader): class DeferredColumnLoader(LoaderStrategy): """Provide loading behavior for a deferred :class:`.ColumnProperty`.""" - __slots__ = 'columns', 'group' + __slots__ = "columns", "group" def __init__(self, parent, strategy_key): super(DeferredColumnLoader, self).__init__(parent, strategy_key) - if hasattr(self.parent_property, 'composite_class'): - raise NotImplementedError("Deferred loading for composite " - "types not implemented yet") + if hasattr(self.parent_property, "composite_class"): + raise NotImplementedError( + "Deferred loading for composite " "types not implemented yet" + ) self.columns = self.parent_property.columns self.group = self.parent_property.group def create_row_processor( - self, context, path, loadopt, - mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): # this path currently does not check the result # for the column; this is because in most cases we are # working just with the setup_query() directive which does # not support this, and the behavior here should be consistent. if not self.is_class_level: - set_deferred_for_local_state = \ + set_deferred_for_local_state = ( self.parent_property._deferred_column_loader + ) populators["new"].append((self.key, set_deferred_for_local_state)) else: populators["expire"].append((self.key, False)) @@ -280,41 +318,56 @@ class DeferredColumnLoader(LoaderStrategy): self.is_class_level = True _register_attribute( - self.parent_property, mapper, useobject=False, + self.parent_property, + mapper, + useobject=False, compare_function=self.columns[0].type.compare_values, callable_=self._load_for_state, - expire_missing=False + expire_missing=False, ) def setup_query( - self, context, entity, path, loadopt, - adapter, column_collection, memoized_populators, - only_load_props=None, **kw): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection, + memoized_populators, + only_load_props=None, + **kw + ): if ( ( - loadopt and - 'undefer_pks' in loadopt.local_opts and - set(self.columns).intersection( - self.parent._should_undefer_in_wildcard) - ) - or - ( - loadopt and - self.group and - loadopt.local_opts.get('undefer_group_%s' % self.group, False) + loadopt + and "undefer_pks" in loadopt.local_opts + and set(self.columns).intersection( + self.parent._should_undefer_in_wildcard + ) ) - or - ( - only_load_props and self.key in only_load_props + or ( + loadopt + and self.group + and loadopt.local_opts.get( + "undefer_group_%s" % self.group, False + ) ) + or (only_load_props and self.key in only_load_props) ): self.parent_property._get_strategy( (("deferred", False), ("instrument", True)) ).setup_query( - context, entity, - path, loadopt, adapter, - column_collection, memoized_populators, **kw) + context, + entity, + path, + loadopt, + adapter, + column_collection, + memoized_populators, + **kw + ) elif self.is_class_level: memoized_populators[self.parent_property] = _SET_DEFERRED_EXPIRED else: @@ -331,11 +384,11 @@ class DeferredColumnLoader(LoaderStrategy): if self.group: toload = [ - p.key for p in - localparent.iterate_properties - if isinstance(p, StrategizedProperty) and - isinstance(p.strategy, DeferredColumnLoader) and - p.group == self.group + p.key + for p in localparent.iterate_properties + if isinstance(p, StrategizedProperty) + and isinstance(p.strategy, DeferredColumnLoader) + and p.group == self.group ] else: toload = [self.key] @@ -347,14 +400,17 @@ class DeferredColumnLoader(LoaderStrategy): if session is None: raise orm_exc.DetachedInstanceError( "Parent instance %s is not bound to a Session; " - "deferred load operation of attribute '%s' cannot proceed" % - (orm_util.state_str(state), self.key) + "deferred load operation of attribute '%s' cannot proceed" + % (orm_util.state_str(state), self.key) ) query = session.query(localparent) - if loading.load_on_ident( - query, state.key, - only_load_props=group, refresh_state=state) is None: + if ( + loading.load_on_ident( + query, state.key, only_load_props=group, refresh_state=state + ) + is None + ): raise orm_exc.ObjectDeletedError(state) return attributes.ATTR_WAS_SET @@ -378,7 +434,7 @@ class LoadDeferredColumns(object): class AbstractRelationshipLoader(LoaderStrategy): """LoaderStratgies which deal with related objects.""" - __slots__ = 'mapper', 'target', 'uselist' + __slots__ = "mapper", "target", "uselist" def __init__(self, parent, strategy_key): super(AbstractRelationshipLoader, self).__init__(parent, strategy_key) @@ -414,19 +470,21 @@ class NoLoader(AbstractRelationshipLoader): self.is_class_level = True _register_attribute( - self.parent_property, mapper, + self.parent_property, + mapper, useobject=True, typecallable=self.parent_property.collection_class, ) def create_row_processor( - self, context, path, loadopt, mapper, - result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): def invoke_no_load(state, dict_, row): if self.uselist: state.manager.get_impl(self.key).initialize(state, dict_) else: dict_[self.key] = None + populators["new"].append((self.key, invoke_no_load)) @@ -443,10 +501,18 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): """ __slots__ = ( - '_lazywhere', '_rev_lazywhere', 'use_get', '_bind_to_col', - '_equated_columns', '_rev_bind_to_col', '_rev_equated_columns', - '_simple_lazy_clause', '_raise_always', '_raise_on_sql', - '_bakery') + "_lazywhere", + "_rev_lazywhere", + "use_get", + "_bind_to_col", + "_equated_columns", + "_rev_bind_to_col", + "_rev_equated_columns", + "_simple_lazy_clause", + "_raise_always", + "_raise_on_sql", + "_bakery", + ) def __init__(self, parent, strategy_key): super(LazyLoader, self).__init__(parent, strategy_key) @@ -454,25 +520,23 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): self._raise_on_sql = self.strategy_opts["lazy"] == "raise_on_sql" join_condition = self.parent_property._join_condition - self._lazywhere, \ - self._bind_to_col, \ - self._equated_columns = join_condition.create_lazy_clause() + self._lazywhere, self._bind_to_col, self._equated_columns = ( + join_condition.create_lazy_clause() + ) - self._rev_lazywhere, \ - self._rev_bind_to_col, \ - self._rev_equated_columns = join_condition.create_lazy_clause( - reverse_direction=True) + self._rev_lazywhere, self._rev_bind_to_col, self._rev_equated_columns = join_condition.create_lazy_clause( + reverse_direction=True + ) self.logger.info("%s lazy loading clause %s", self, self._lazywhere) # determine if our "lazywhere" clause is the same as the mapper's # get() clause. then we can just use mapper.get() - self.use_get = not self.uselist and \ - self.mapper._get_clause[0].compare( - self._lazywhere, - use_proxies=True, - equivalents=self.mapper._equivalent_columns - ) + self.use_get = not self.uselist and self.mapper._get_clause[0].compare( + self._lazywhere, + use_proxies=True, + equivalents=self.mapper._equivalent_columns, + ) if self.use_get: for col in list(self._equated_columns): @@ -480,16 +544,17 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): for c in self.mapper._equivalent_columns[col]: self._equated_columns[c] = self._equated_columns[col] - self.logger.info("%s will use query.get() to " - "optimize instance loads", self) + self.logger.info( + "%s will use query.get() to " "optimize instance loads", self + ) def init_class_attribute(self, mapper): self.is_class_level = True active_history = ( - self.parent_property.active_history or - self.parent_property.direction is not interfaces.MANYTOONE or - not self.use_get + self.parent_property.active_history + or self.parent_property.direction is not interfaces.MANYTOONE + or not self.use_get ) # MANYTOONE currently only needs the @@ -504,28 +569,29 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): useobject=True, callable_=self._load_for_state, typecallable=self.parent_property.collection_class, - active_history=active_history + active_history=active_history, ) def _memoized_attr__simple_lazy_clause(self): - criterion, bind_to_col = ( - self._lazywhere, - self._bind_to_col - ) + criterion, bind_to_col = (self._lazywhere, self._bind_to_col) params = [] def visit_bindparam(bindparam): bindparam.unique = False if bindparam._identifying_key in bind_to_col: - params.append(( - bindparam.key, bind_to_col[bindparam._identifying_key], - None)) + params.append( + ( + bindparam.key, + bind_to_col[bindparam._identifying_key], + None, + ) + ) elif bindparam.callable is None: params.append((bindparam.key, None, bindparam.value)) criterion = visitors.cloned_traverse( - criterion, {}, {'bindparam': visit_bindparam} + criterion, {}, {"bindparam": visit_bindparam} ) return criterion, params @@ -535,7 +601,8 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): if state is None: return sql_util.adapt_criterion_to_null( - criterion, [key for key, ident, value in param_keys]) + criterion, [key for key, ident, value in param_keys] + ) mapper = self.parent_property.parent @@ -550,10 +617,12 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): if ident is not None: if passive and passive & attributes.LOAD_AGAINST_COMMITTED: value = mapper._get_committed_state_attr_by_column( - state, dict_, ident, passive) + state, dict_, ident, passive + ) else: value = mapper._get_state_attr_by_column( - state, dict_, ident, passive) + state, dict_, ident, passive + ) params[key] = value @@ -567,21 +636,19 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): def _load_for_state(self, state, passive): if not state.key and ( - ( - not self.parent_property.load_on_pending - and not state._load_pending - ) - or not state.session_id + ( + not self.parent_property.load_on_pending + and not state._load_pending + ) + or not state.session_id ): return attributes.ATTR_EMPTY pending = not state.key primary_key_identity = None - if ( - (not passive & attributes.SQL_OK and not self.use_get) - or - (not passive & attributes.NON_PERSISTENT_OK and pending) + if (not passive & attributes.SQL_OK and not self.use_get) or ( + not passive & attributes.NON_PERSISTENT_OK and pending ): return attributes.PASSIVE_NO_RESULT @@ -595,17 +662,15 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): raise orm_exc.DetachedInstanceError( "Parent instance %s is not bound to a Session; " - "lazy load operation of attribute '%s' cannot proceed" % - (orm_util.state_str(state), self.key) + "lazy load operation of attribute '%s' cannot proceed" + % (orm_util.state_str(state), self.key) ) # if we have a simple primary key load, check the # identity map without generating a Query at all if self.use_get: primary_key_identity = self._get_ident_for_use_get( - session, - state, - passive + session, state, passive ) if attributes.PASSIVE_NO_RESULT in primary_key_identity: return attributes.PASSIVE_NO_RESULT @@ -620,18 +685,23 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): # does this, including how it decides what the correct # identity_token would be for this identity. instance = session.query()._identity_lookup( - self.mapper, primary_key_identity, passive=passive, - lazy_loaded_from=state + self.mapper, + primary_key_identity, + passive=passive, + lazy_loaded_from=state, ) if instance is not None: return instance - elif not passive & attributes.SQL_OK or \ - not passive & attributes.RELATED_OBJECT_OK: + elif ( + not passive & attributes.SQL_OK + or not passive & attributes.RELATED_OBJECT_OK + ): return attributes.PASSIVE_NO_RESULT return self._emit_lazyload( - session, state, primary_key_identity, passive) + session, state, primary_key_identity, passive + ) def _get_ident_for_use_get(self, session, state, passive): instance_mapper = state.manager.mapper @@ -644,11 +714,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): dict_ = state.dict return [ - get_attr( - state, - dict_, - self._equated_columns[pk], - passive=passive) + get_attr(state, dict_, self._equated_columns[pk], passive=passive) for pk in self.mapper.primary_key ] @@ -656,11 +722,10 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): def _memoized_attr__bakery(self, baked): return baked.bakery(size=50) - @util.dependencies( - "sqlalchemy.orm.strategy_options") + @util.dependencies("sqlalchemy.orm.strategy_options") def _emit_lazyload( - self, strategy_options, session, state, - primary_key_identity, passive): + self, strategy_options, session, state, primary_key_identity, passive + ): # emit lazy load now using BakedQuery, to cut way down on the overhead # of generating queries. # there are two big things we are trying to guard against here: @@ -688,15 +753,18 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): q.add_criteria( lambda q: q._adapt_all_clauses()._with_invoke_all_eagers(False), - self.parent_property) + self.parent_property, + ) if not self.parent_property.bake_queries: q.spoil(full=True) if self.parent_property.secondary is not None: q.add_criteria( - lambda q: - q.select_from(self.mapper, self.parent_property.secondary)) + lambda q: q.select_from( + self.mapper, self.parent_property.secondary + ) + ) pending = not state.key @@ -712,35 +780,38 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): # is usually a throwaway object. effective_path = state.load_path[self.parent_property] - q._add_lazyload_options( - state.load_options, effective_path - ) + q._add_lazyload_options(state.load_options, effective_path) if self.use_get: if self._raise_on_sql: self._invoke_raise_load(state, passive, "raise_on_sql") - return q(session).\ - with_post_criteria(lambda q: q._set_lazyload_from(state)).\ - _load_on_pk_identity( - session.query(self.mapper), - primary_key_identity) + return ( + q(session) + .with_post_criteria(lambda q: q._set_lazyload_from(state)) + ._load_on_pk_identity( + session.query(self.mapper), primary_key_identity + ) + ) if self.parent_property.order_by: q.add_criteria( - lambda q: - q.order_by(*util.to_list(self.parent_property.order_by))) + lambda q: q.order_by( + *util.to_list(self.parent_property.order_by) + ) + ) for rev in self.parent_property._reverse_property: # reverse props that are MANYTOONE are loading *this* # object from get(), so don't need to eager out to those. - if rev.direction is interfaces.MANYTOONE and \ - rev._use_get and \ - not isinstance(rev.strategy, LazyLoader): + if ( + rev.direction is interfaces.MANYTOONE + and rev._use_get + and not isinstance(rev.strategy, LazyLoader) + ): q.add_criteria( - lambda q: - q.options( + lambda q: q.options( strategy_options.Load.for_existing_path( q._current_path[rev.parent] ).lazyload(rev.key) @@ -750,8 +821,7 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): lazy_clause, params = self._generate_lazy_clause(state, passive) if pending: - if util.has_intersection( - orm_util._none_set, params.values()): + if util.has_intersection(orm_util._none_set, params.values()): return None elif util.has_intersection(orm_util._never_set, params.values()): @@ -769,9 +839,12 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): q._params = params return q - result = q(session).\ - with_post_criteria(lambda q: q._set_lazyload_from(state)).\ - with_post_criteria(set_default_params).all() + result = ( + q(session) + .with_post_criteria(lambda q: q._set_lazyload_from(state)) + .with_post_criteria(set_default_params) + .all() + ) if self.uselist: return result else: @@ -781,15 +854,16 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): util.warn( "Multiple rows returned with " "uselist=False for lazily-loaded attribute '%s' " - % self.parent_property) + % self.parent_property + ) return result[0] else: return None def create_row_processor( - self, context, path, loadopt, - mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): key = self.key if not self.is_class_level: @@ -802,11 +876,12 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots): # attribute - "eager" attributes always have a # class-level lazyloader installed. set_lazy_callable = InstanceState._instance_level_callable_processor( - mapper.class_manager, - LoadLazyAttribute(key, self), key) + mapper.class_manager, LoadLazyAttribute(key, self), key + ) populators["new"].append((self.key, set_lazy_callable)) elif context.populate_existing or mapper.always_refresh: + def reset_for_lazy_callable(state, dict_, row): # we are the primary manager for this attribute on # this class - reset its @@ -842,19 +917,26 @@ class ImmediateLoader(AbstractRelationshipLoader): __slots__ = () def init_class_attribute(self, mapper): - self.parent_property.\ - _get_strategy((("lazy", "select"),)).\ - init_class_attribute(mapper) + self.parent_property._get_strategy( + (("lazy", "select"),) + ).init_class_attribute(mapper) def setup_query( - self, context, entity, - path, loadopt, adapter, column_collection=None, - parentmapper=None, **kwargs): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection=None, + parentmapper=None, + **kwargs + ): pass def create_row_processor( - self, context, path, loadopt, - mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): def load_immediate(state, dict_, row): state.get_impl(self.key).get(state, dict_) @@ -864,22 +946,28 @@ class ImmediateLoader(AbstractRelationshipLoader): @log.class_logger @properties.RelationshipProperty.strategy_for(lazy="subquery") class SubqueryLoader(AbstractRelationshipLoader): - __slots__ = 'join_depth', + __slots__ = ("join_depth",) def __init__(self, parent, strategy_key): super(SubqueryLoader, self).__init__(parent, strategy_key) self.join_depth = self.parent_property.join_depth def init_class_attribute(self, mapper): - self.parent_property.\ - _get_strategy((("lazy", "select"),)).\ - init_class_attribute(mapper) + self.parent_property._get_strategy( + (("lazy", "select"),) + ).init_class_attribute(mapper) def setup_query( - self, context, entity, - path, loadopt, adapter, - column_collection=None, - parentmapper=None, **kwargs): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection=None, + parentmapper=None, + **kwargs + ): if not context.query._enable_eagerloads: return @@ -891,16 +979,16 @@ class SubqueryLoader(AbstractRelationshipLoader): # build up a path indicating the path from the leftmost # entity to the thing we're subquery loading. with_poly_info = path.get( - context.attributes, - "path_with_polymorphic", None) + context.attributes, "path_with_polymorphic", None + ) if with_poly_info is not None: effective_entity = with_poly_info.entity else: effective_entity = self.mapper subq_path = context.attributes.get( - ('subquery_path', None), - orm_util.PathRegistry.root) + ("subquery_path", None), orm_util.PathRegistry.root + ) subq_path = subq_path + path @@ -909,27 +997,33 @@ class SubqueryLoader(AbstractRelationshipLoader): if not path.contains(context.attributes, "loader"): if self.join_depth: if ( - (context.query._current_path.length - if context.query._current_path else 0) + - path.length + ( + context.query._current_path.length + if context.query._current_path + else 0 + ) + + path.length ) / 2 > self.join_depth: return elif subq_path.contains_mapper(self.mapper): return - leftmost_mapper, leftmost_attr, leftmost_relationship = \ - self._get_leftmost(subq_path) + leftmost_mapper, leftmost_attr, leftmost_relationship = self._get_leftmost( + subq_path + ) orig_query = context.attributes.get( - ("orig_query", SubqueryLoader), - context.query) + ("orig_query", SubqueryLoader), context.query + ) # generate a new Query from the original, then # produce a subquery from it. left_alias = self._generate_from_original_query( - orig_query, leftmost_mapper, - leftmost_attr, leftmost_relationship, - entity.entity_zero + orig_query, + leftmost_mapper, + leftmost_attr, + leftmost_relationship, + entity.entity_zero, ) # generate another Query that will join the @@ -940,17 +1034,18 @@ class SubqueryLoader(AbstractRelationshipLoader): q = orig_query.session.query(effective_entity) q._attributes = { ("orig_query", SubqueryLoader): orig_query, - ('subquery_path', None): subq_path + ("subquery_path", None): subq_path, } q = q._set_enable_single_crit(False) - to_join, local_attr, parent_alias = \ - self._prep_for_joins(left_alias, subq_path) + to_join, local_attr, parent_alias = self._prep_for_joins( + left_alias, subq_path + ) q = q.order_by(*local_attr) q = q.add_columns(*local_attr) q = self._apply_joins( - q, to_join, left_alias, - parent_alias, effective_entity) + q, to_join, left_alias, parent_alias, effective_entity + ) q = self._setup_options(q, subq_path, orig_query, effective_entity) q = self._setup_outermost_orderby(q) @@ -964,21 +1059,20 @@ class SubqueryLoader(AbstractRelationshipLoader): subq_mapper = orm_util._class_to_mapper(subq_path[0]) # determine attributes of the leftmost mapper - if self.parent.isa(subq_mapper) and \ - self.parent_property is subq_path[1]: - leftmost_mapper, leftmost_prop = \ - self.parent, self.parent_property + if ( + self.parent.isa(subq_mapper) + and self.parent_property is subq_path[1] + ): + leftmost_mapper, leftmost_prop = self.parent, self.parent_property else: - leftmost_mapper, leftmost_prop = \ - subq_mapper, \ - subq_path[1] + leftmost_mapper, leftmost_prop = subq_mapper, subq_path[1] leftmost_cols = leftmost_prop.local_columns leftmost_attr = [ getattr( - subq_path[0].entity, - leftmost_mapper._columntoproperty[c].key) + subq_path[0].entity, leftmost_mapper._columntoproperty[c].key + ) for c in leftmost_cols ] @@ -986,8 +1080,11 @@ class SubqueryLoader(AbstractRelationshipLoader): def _generate_from_original_query( self, - orig_query, leftmost_mapper, - leftmost_attr, leftmost_relationship, orig_entity + orig_query, + leftmost_mapper, + leftmost_attr, + leftmost_relationship, + orig_entity, ): # reformat the original query # to look only for significant columns @@ -999,11 +1096,16 @@ class SubqueryLoader(AbstractRelationshipLoader): # all entities mentioned in things like WHERE, JOIN, etc. if not q._from_obj: q._set_select_from( - list(set([ - ent['entity'] for ent in orig_query.column_descriptions - if ent['entity'] is not None - ])), - False + list( + set( + [ + ent["entity"] + for ent in orig_query.column_descriptions + if ent["entity"] is not None + ] + ) + ), + False, ) # select from the identity columns of the outer (specifically, these @@ -1037,8 +1139,8 @@ class SubqueryLoader(AbstractRelationshipLoader): embed_q = q.with_labels().subquery() left_alias = orm_util.AliasedClass( - leftmost_mapper, embed_q, - use_mapper_path=True) + leftmost_mapper, embed_q, use_mapper_path=True + ) return left_alias def _prep_for_joins(self, left_alias, subq_path): @@ -1077,8 +1179,8 @@ class SubqueryLoader(AbstractRelationshipLoader): # alias a plain mapper as we may be # joining multiple times parent_alias = orm_util.AliasedClass( - info.entity, - use_mapper_path=True) + info.entity, use_mapper_path=True + ) local_cols = self.parent_property.local_columns @@ -1089,8 +1191,8 @@ class SubqueryLoader(AbstractRelationshipLoader): return to_join, local_attr, parent_alias def _apply_joins( - self, q, to_join, left_alias, parent_alias, - effective_entity): + self, q, to_join, left_alias, parent_alias, effective_entity + ): ltj = len(to_join) if ltj == 1: @@ -1100,7 +1202,9 @@ class SubqueryLoader(AbstractRelationshipLoader): elif ltj == 2: to_join = [ getattr(left_alias, to_join[0][1]).of_type(parent_alias), - getattr(parent_alias, to_join[-1][1]).of_type(effective_entity) + getattr(parent_alias, to_join[-1][1]).of_type( + effective_entity + ), ] elif ltj > 2: middle = [ @@ -1108,8 +1212,9 @@ class SubqueryLoader(AbstractRelationshipLoader): orm_util.AliasedClass(item[0]) if not inspect(item[0]).is_aliased_class else item[0].entity, - item[1] - ) for item in to_join[1:-1] + item[1], + ) + for item in to_join[1:-1] ] inner = [] @@ -1123,11 +1228,15 @@ class SubqueryLoader(AbstractRelationshipLoader): inner.append(attr) - to_join = [ - getattr(left_alias, to_join[0][1]).of_type(inner[0].parent) - ] + inner + [ - getattr(parent_alias, to_join[-1][1]).of_type(effective_entity) - ] + to_join = ( + [getattr(left_alias, to_join[0][1]).of_type(inner[0].parent)] + + inner + + [ + getattr(parent_alias, to_join[-1][1]).of_type( + effective_entity + ) + ] + ) for attr in to_join: q = q.join(attr, from_joinpoint=True) @@ -1151,13 +1260,9 @@ class SubqueryLoader(AbstractRelationshipLoader): # this really only picks up the "secondary" table # right now. eagerjoin = q._from_obj[0] - eager_order_by = \ - eagerjoin._target_adapter.\ - copy_and_process( - util.to_list( - self.parent_property.order_by - ) - ) + eager_order_by = eagerjoin._target_adapter.copy_and_process( + util.to_list(self.parent_property.order_by) + ) q = q.order_by(*eager_order_by) return q @@ -1167,6 +1272,7 @@ class SubqueryLoader(AbstractRelationshipLoader): first moment a value is needed. """ + _data = None def __init__(self, subq): @@ -1180,10 +1286,7 @@ class SubqueryLoader(AbstractRelationshipLoader): def _load(self): self._data = dict( (k, [vv[0] for vv in v]) - for k, v in itertools.groupby( - self.subq, - lambda x: x[1:] - ) + for k, v in itertools.groupby(self.subq, lambda x: x[1:]) ) def loader(self, state, dict_, row): @@ -1191,17 +1294,17 @@ class SubqueryLoader(AbstractRelationshipLoader): self._load() def create_row_processor( - self, context, path, loadopt, - mapper, result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): if not self.parent.class_manager[self.key].impl.supports_population: raise sa_exc.InvalidRequestError( "'%s' does not support object " - "population - eager loading cannot be applied." % - self) + "population - eager loading cannot be applied." % self + ) path = path[self.parent_property] - subq = path.get(context.attributes, 'subquery') + subq = path.get(context.attributes, "subquery") if subq is None: return @@ -1220,65 +1323,67 @@ class SubqueryLoader(AbstractRelationshipLoader): collections = path.get(context.attributes, "collections") if collections is None: collections = self._SubqCollections(subq) - path.set(context.attributes, 'collections', collections) + path.set(context.attributes, "collections", collections) if adapter: local_cols = [adapter.columns[c] for c in local_cols] if self.uselist: self._create_collection_loader( - context, collections, local_cols, populators) + context, collections, local_cols, populators + ) else: self._create_scalar_loader( - context, collections, local_cols, populators) + context, collections, local_cols, populators + ) def _create_collection_loader( - self, context, collections, local_cols, populators): + self, context, collections, local_cols, populators + ): def load_collection_from_subq(state, dict_, row): collection = collections.get( - tuple([row[col] for col in local_cols]), - () + tuple([row[col] for col in local_cols]), () + ) + state.get_impl(self.key).set_committed_value( + state, dict_, collection ) - state.get_impl(self.key).\ - set_committed_value(state, dict_, collection) def load_collection_from_subq_existing_row(state, dict_, row): if self.key not in dict_: load_collection_from_subq(state, dict_, row) - populators["new"].append( - (self.key, load_collection_from_subq)) + populators["new"].append((self.key, load_collection_from_subq)) populators["existing"].append( - (self.key, load_collection_from_subq_existing_row)) + (self.key, load_collection_from_subq_existing_row) + ) if context.invoke_all_eagers: populators["eager"].append((self.key, collections.loader)) def _create_scalar_loader( - self, context, collections, local_cols, populators): + self, context, collections, local_cols, populators + ): def load_scalar_from_subq(state, dict_, row): collection = collections.get( - tuple([row[col] for col in local_cols]), - (None,) + tuple([row[col] for col in local_cols]), (None,) ) if len(collection) > 1: util.warn( "Multiple rows returned with " - "uselist=False for eagerly-loaded attribute '%s' " - % self) + "uselist=False for eagerly-loaded attribute '%s' " % self + ) scalar = collection[0] - state.get_impl(self.key).\ - set_committed_value(state, dict_, scalar) + state.get_impl(self.key).set_committed_value(state, dict_, scalar) def load_scalar_from_subq_existing_row(state, dict_, row): if self.key not in dict_: load_scalar_from_subq(state, dict_, row) - populators["new"].append( - (self.key, load_scalar_from_subq)) + populators["new"].append((self.key, load_scalar_from_subq)) populators["existing"].append( - (self.key, load_scalar_from_subq_existing_row)) + (self.key, load_scalar_from_subq_existing_row) + ) if context.invoke_all_eagers: populators["eager"].append((self.key, collections.loader)) @@ -1292,7 +1397,7 @@ class JoinedLoader(AbstractRelationshipLoader): """ - __slots__ = 'join_depth', '_aliased_class_pool' + __slots__ = "join_depth", "_aliased_class_pool" def __init__(self, parent, strategy_key): super(JoinedLoader, self).__init__(parent, strategy_key) @@ -1300,14 +1405,22 @@ class JoinedLoader(AbstractRelationshipLoader): self._aliased_class_pool = [] def init_class_attribute(self, mapper): - self.parent_property.\ - _get_strategy((("lazy", "select"),)).init_class_attribute(mapper) + self.parent_property._get_strategy( + (("lazy", "select"),) + ).init_class_attribute(mapper) def setup_query( - self, context, entity, path, loadopt, adapter, - column_collection=None, parentmapper=None, - chained_from_outerjoin=False, - **kwargs): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection=None, + parentmapper=None, + chained_from_outerjoin=False, + **kwargs + ): """Add a left outer join to the statement that's being constructed.""" if not context.query._enable_eagerloads: @@ -1319,15 +1432,16 @@ class JoinedLoader(AbstractRelationshipLoader): with_polymorphic = None - user_defined_adapter = self._init_user_defined_eager_proc( - loadopt, context) if loadopt else False + user_defined_adapter = ( + self._init_user_defined_eager_proc(loadopt, context) + if loadopt + else False + ) if user_defined_adapter is not False: - clauses, adapter, add_to_collection = \ - self._setup_query_on_user_defined_adapter( - context, entity, path, adapter, - user_defined_adapter - ) + clauses, adapter, add_to_collection = self._setup_query_on_user_defined_adapter( + context, entity, path, adapter, user_defined_adapter + ) else: # if not via query option, check for # a cycle @@ -1338,16 +1452,19 @@ class JoinedLoader(AbstractRelationshipLoader): elif path.contains_mapper(self.mapper): return - clauses, adapter, add_to_collection, chained_from_outerjoin = \ - self._generate_row_adapter( - context, entity, path, loadopt, adapter, - column_collection, parentmapper, chained_from_outerjoin - ) + clauses, adapter, add_to_collection, chained_from_outerjoin = self._generate_row_adapter( + context, + entity, + path, + loadopt, + adapter, + column_collection, + parentmapper, + chained_from_outerjoin, + ) with_poly_info = path.get( - context.attributes, - "path_with_polymorphic", - None + context.attributes, "path_with_polymorphic", None ) if with_poly_info is not None: with_polymorphic = with_poly_info.with_polymorphic_mappers @@ -1357,14 +1474,20 @@ class JoinedLoader(AbstractRelationshipLoader): path = path[self.mapper] loading._setup_entity_query( - context, self.mapper, entity, - path, clauses, add_to_collection, + context, + self.mapper, + entity, + path, + clauses, + add_to_collection, with_polymorphic=with_polymorphic, parentmapper=self.mapper, - chained_from_outerjoin=chained_from_outerjoin) + chained_from_outerjoin=chained_from_outerjoin, + ) - if with_poly_info is not None and \ - None in set(context.secondary_columns): + if with_poly_info is not None and None in set( + context.secondary_columns + ): raise sa_exc.InvalidRequestError( "Detected unaliased columns when generating joined " "load. Make sure to use aliased=True or flat=True " @@ -1383,8 +1506,8 @@ class JoinedLoader(AbstractRelationshipLoader): # the option applies. check if the "user_defined_eager_row_processor" # has been built up. adapter = path.get( - context.attributes, - "user_defined_eager_row_processor", False) + context.attributes, "user_defined_eager_row_processor", False + ) if adapter is not False: # just return it return adapter @@ -1394,38 +1517,39 @@ class JoinedLoader(AbstractRelationshipLoader): root_mapper, prop = path[-2:] - #from .mapper import Mapper - #from .interfaces import MapperProperty - #assert isinstance(root_mapper, Mapper) - #assert isinstance(prop, MapperProperty) + # from .mapper import Mapper + # from .interfaces import MapperProperty + # assert isinstance(root_mapper, Mapper) + # assert isinstance(prop, MapperProperty) if alias is not None: if isinstance(alias, str): alias = prop.target.alias(alias) adapter = sql_util.ColumnAdapter( - alias, - equivalents=prop.mapper._equivalent_columns) + alias, equivalents=prop.mapper._equivalent_columns + ) else: if path.contains(context.attributes, "path_with_polymorphic"): with_poly_info = path.get( - context.attributes, - "path_with_polymorphic") + context.attributes, "path_with_polymorphic" + ) adapter = orm_util.ORMAdapter( with_poly_info.entity, - equivalents=prop.mapper._equivalent_columns) + equivalents=prop.mapper._equivalent_columns, + ) else: adapter = context.query._polymorphic_adapters.get( - prop.mapper, None) + prop.mapper, None + ) path.set( - context.attributes, - "user_defined_eager_row_processor", - adapter) + context.attributes, "user_defined_eager_row_processor", adapter + ) return adapter def _setup_query_on_user_defined_adapter( - self, context, entity, - path, adapter, user_defined_adapter): + self, context, entity, path, adapter, user_defined_adapter + ): # apply some more wrapping to the "user defined adapter" # if we are setting up the query for SQL render. @@ -1434,13 +1558,17 @@ class JoinedLoader(AbstractRelationshipLoader): if adapter and user_defined_adapter: user_defined_adapter = user_defined_adapter.wrap(adapter) path.set( - context.attributes, "user_defined_eager_row_processor", - user_defined_adapter) + context.attributes, + "user_defined_eager_row_processor", + user_defined_adapter, + ) elif adapter: user_defined_adapter = adapter path.set( - context.attributes, "user_defined_eager_row_processor", - user_defined_adapter) + context.attributes, + "user_defined_eager_row_processor", + user_defined_adapter, + ) add_to_collection = context.primary_columns return user_defined_adapter, adapter, add_to_collection @@ -1450,7 +1578,7 @@ class JoinedLoader(AbstractRelationshipLoader): # we need one unique AliasedClass per query per appearance of our # entity in the query. - key = ('joinedloader_ac', self) + key = ("joinedloader_ac", self) if key not in context.attributes: context.attributes[key] = idx = 0 else: @@ -1458,9 +1586,8 @@ class JoinedLoader(AbstractRelationshipLoader): if idx >= len(self._aliased_class_pool): to_adapt = orm_util.AliasedClass( - self.mapper, - flat=True, - use_mapper_path=True) + self.mapper, flat=True, use_mapper_path=True + ) # load up the .columns collection on the Alias() before # the object becomes shared among threads. this prevents # races for column identities. @@ -1471,13 +1598,18 @@ class JoinedLoader(AbstractRelationshipLoader): return self._aliased_class_pool[idx] def _generate_row_adapter( - self, - context, entity, path, loadopt, adapter, - column_collection, parentmapper, chained_from_outerjoin): + self, + context, + entity, + path, + loadopt, + adapter, + column_collection, + parentmapper, + chained_from_outerjoin, + ): with_poly_info = path.get( - context.attributes, - "path_with_polymorphic", - None + context.attributes, "path_with_polymorphic", None ) if with_poly_info: to_adapt = with_poly_info.entity @@ -1489,8 +1621,9 @@ class JoinedLoader(AbstractRelationshipLoader): orm_util.ORMAdapter, to_adapt, equivalents=self.mapper._equivalent_columns, - adapt_required=True, allow_label_resolve=False, - anonymize_labels=True + adapt_required=True, + allow_label_resolve=False, + anonymize_labels=True, ) assert clauses.aliased_class is not None @@ -1499,8 +1632,7 @@ class JoinedLoader(AbstractRelationshipLoader): context.multi_row_eager_loaders = True innerjoin = ( - loadopt.local_opts.get( - 'innerjoin', self.parent_property.innerjoin) + loadopt.local_opts.get("innerjoin", self.parent_property.innerjoin) if loadopt is not None else self.parent_property.innerjoin ) @@ -1512,9 +1644,15 @@ class JoinedLoader(AbstractRelationshipLoader): context.create_eager_joins.append( ( - self._create_eager_join, context, - entity, path, adapter, - parentmapper, clauses, innerjoin, chained_from_outerjoin + self._create_eager_join, + context, + entity, + path, + adapter, + parentmapper, + clauses, + innerjoin, + chained_from_outerjoin, ) ) @@ -1524,9 +1662,16 @@ class JoinedLoader(AbstractRelationshipLoader): return clauses, adapter, add_to_collection, chained_from_outerjoin def _create_eager_join( - self, context, entity, - path, adapter, parentmapper, - clauses, innerjoin, chained_from_outerjoin): + self, + context, + entity, + path, + adapter, + parentmapper, + clauses, + innerjoin, + chained_from_outerjoin, + ): if parentmapper is None: localparent = entity.mapper @@ -1536,16 +1681,21 @@ class JoinedLoader(AbstractRelationshipLoader): # whether or not the Query will wrap the selectable in a subquery, # and then attach eager load joins to that (i.e., in the case of # LIMIT/OFFSET etc.) - should_nest_selectable = context.multi_row_eager_loaders and \ - context.query._should_nest_selectable + should_nest_selectable = ( + context.multi_row_eager_loaders + and context.query._should_nest_selectable + ) entity_key = None - if entity not in context.eager_joins and \ - not should_nest_selectable and \ - context.from_clause: + if ( + entity not in context.eager_joins + and not should_nest_selectable + and context.from_clause + ): indexes = sql_util.find_left_clause_that_matches_given( - context.from_clause, entity.selectable) + context.from_clause, entity.selectable + ) if len(indexes) > 1: # for the eager load case, I can't reproduce this right @@ -1553,7 +1703,8 @@ class JoinedLoader(AbstractRelationshipLoader): raise sa_exc.InvalidRequestError( "Can't identify which entity in which to joined eager " "load from. Please use an exact match when specifying " - "the join path.") + "the join path." + ) if indexes: clause = context.from_clause[indexes[0]] @@ -1569,29 +1720,27 @@ class JoinedLoader(AbstractRelationshipLoader): towrap = context.eager_joins.setdefault(entity_key, default_towrap) if adapter: - if getattr(adapter, 'aliased_class', None): + if getattr(adapter, "aliased_class", None): # joining from an adapted entity. The adapted entity # might be a "with_polymorphic", so resolve that to our # specific mapper's entity before looking for our attribute # name on it. - efm = inspect(adapter.aliased_class).\ - _entity_for_mapper( - localparent - if localparent.isa(self.parent) else self.parent) + efm = inspect(adapter.aliased_class)._entity_for_mapper( + localparent + if localparent.isa(self.parent) + else self.parent + ) # look for our attribute on the adapted entity, else fall back # to our straight property - onclause = getattr( - efm.entity, self.key, - self.parent_property) + onclause = getattr(efm.entity, self.key, self.parent_property) else: onclause = getattr( orm_util.AliasedClass( - self.parent, - adapter.selectable, - use_mapper_path=True + self.parent, adapter.selectable, use_mapper_path=True ), - self.key, self.parent_property + self.key, + self.parent_property, ) else: @@ -1600,9 +1749,10 @@ class JoinedLoader(AbstractRelationshipLoader): assert clauses.aliased_class is not None attach_on_outside = ( - not chained_from_outerjoin or - not innerjoin or innerjoin == 'unnested' or - entity.entity_zero.represents_outer_join + not chained_from_outerjoin + or not innerjoin + or innerjoin == "unnested" + or entity.entity_zero.represents_outer_join ) if attach_on_outside: @@ -1611,16 +1761,17 @@ class JoinedLoader(AbstractRelationshipLoader): towrap, clauses.aliased_class, onclause, - isouter=not innerjoin or - entity.entity_zero.represents_outer_join or - ( - chained_from_outerjoin and isinstance(towrap, sql.Join) - ), _left_memo=self.parent, _right_memo=self.mapper + isouter=not innerjoin + or entity.entity_zero.represents_outer_join + or (chained_from_outerjoin and isinstance(towrap, sql.Join)), + _left_memo=self.parent, + _right_memo=self.mapper, ) else: # all other cases are innerjoin=='nested' approach eagerjoin = self._splice_nested_inner_join( - path, towrap, clauses, onclause) + path, towrap, clauses, onclause + ) context.eager_joins[entity_key] = eagerjoin @@ -1636,22 +1787,21 @@ class JoinedLoader(AbstractRelationshipLoader): # This has the effect # of "undefering" those columns. for col in sql_util._find_columns( - self.parent_property.primaryjoin): + self.parent_property.primaryjoin + ): if localparent.mapped_table.c.contains_column(col): if adapter: col = adapter.columns[col] context.primary_columns.append(col) if self.parent_property.order_by: - context.eager_order_by += eagerjoin._target_adapter.\ - copy_and_process( - util.to_list( - self.parent_property.order_by - ) - ) + context.eager_order_by += eagerjoin._target_adapter.copy_and_process( + util.to_list(self.parent_property.order_by) + ) def _splice_nested_inner_join( - self, path, join_obj, clauses, onclause, splicing=False): + self, path, join_obj, clauses, onclause, splicing=False + ): if splicing is False: # first call is always handed a join object @@ -1664,28 +1814,31 @@ class JoinedLoader(AbstractRelationshipLoader): elif not isinstance(join_obj, orm_util._ORMJoin): if path[-2] is splicing: return orm_util._ORMJoin( - join_obj, clauses.aliased_class, - onclause, isouter=False, + join_obj, + clauses.aliased_class, + onclause, + isouter=False, _left_memo=splicing, - _right_memo=path[-1].mapper + _right_memo=path[-1].mapper, ) else: # only here if splicing == True return None target_join = self._splice_nested_inner_join( - path, join_obj.right, clauses, - onclause, join_obj._right_memo) + path, join_obj.right, clauses, onclause, join_obj._right_memo + ) if target_join is None: right_splice = False target_join = self._splice_nested_inner_join( - path, join_obj.left, clauses, - onclause, join_obj._left_memo) + path, join_obj.left, clauses, onclause, join_obj._left_memo + ) if target_join is None: # should only return None when recursively called, # e.g. splicing==True - assert splicing is not False, \ - "assertion failed attempting to produce joined eager loads" + assert ( + splicing is not False + ), "assertion failed attempting to produce joined eager loads" return None else: right_splice = True @@ -1698,21 +1851,30 @@ class JoinedLoader(AbstractRelationshipLoader): eagerjoin = join_obj._splice_into_center(target_join) else: eagerjoin = orm_util._ORMJoin( - join_obj.left, target_join, - join_obj.onclause, isouter=join_obj.isouter, - _left_memo=join_obj._left_memo) + join_obj.left, + target_join, + join_obj.onclause, + isouter=join_obj.isouter, + _left_memo=join_obj._left_memo, + ) else: eagerjoin = orm_util._ORMJoin( - target_join, join_obj.right, - join_obj.onclause, isouter=join_obj.isouter, - _right_memo=join_obj._right_memo) + target_join, + join_obj.right, + join_obj.onclause, + isouter=join_obj.isouter, + _right_memo=join_obj._right_memo, + ) eagerjoin._target_adapter = target_join._target_adapter return eagerjoin def _create_eager_adapter(self, context, result, adapter, path, loadopt): - user_defined_adapter = self._init_user_defined_eager_proc( - loadopt, context) if loadopt else False + user_defined_adapter = ( + self._init_user_defined_eager_proc(loadopt, context) + if loadopt + else False + ) if user_defined_adapter is not False: decorator = user_defined_adapter @@ -1736,21 +1898,19 @@ class JoinedLoader(AbstractRelationshipLoader): return False def create_row_processor( - self, context, path, loadopt, mapper, - result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): if not self.parent.class_manager[self.key].impl.supports_population: raise sa_exc.InvalidRequestError( "'%s' does not support object " - "population - eager loading cannot be applied." % - self + "population - eager loading cannot be applied." % self ) our_path = path[self.parent_property] eager_adapter = self._create_eager_adapter( - context, - result, - adapter, our_path, loadopt) + context, result, adapter, our_path, loadopt + ) if eager_adapter is not False: key = self.key @@ -1760,25 +1920,28 @@ class JoinedLoader(AbstractRelationshipLoader): context, result, our_path[self.mapper], - eager_adapter) + eager_adapter, + ) if not self.uselist: self._create_scalar_loader(context, key, _instance, populators) else: self._create_collection_loader( - context, key, _instance, populators) + context, key, _instance, populators + ) else: - self.parent_property._get_strategy((("lazy", "select"),)).\ - create_row_processor( - context, path, loadopt, - mapper, result, adapter, populators) + self.parent_property._get_strategy( + (("lazy", "select"),) + ).create_row_processor( + context, path, loadopt, mapper, result, adapter, populators + ) def _create_collection_loader(self, context, key, _instance, populators): def load_collection_from_joined_new_row(state, dict_, row): - collection = attributes.init_state_collection( - state, dict_, key) - result_list = util.UniqueAppender(collection, - 'append_without_event') + collection = attributes.init_state_collection(state, dict_, key) + result_list = util.UniqueAppender( + collection, "append_without_event" + ) context.attributes[(state, key)] = result_list inst = _instance(row) if inst is not None: @@ -1793,10 +1956,11 @@ class JoinedLoader(AbstractRelationshipLoader): # is used; the same instance may be present in two # distinct sets of result columns collection = attributes.init_state_collection( - state, dict_, key) + state, dict_, key + ) result_list = util.UniqueAppender( - collection, - 'append_without_event') + collection, "append_without_event" + ) context.attributes[(state, key)] = result_list inst = _instance(row) if inst is not None: @@ -1805,12 +1969,16 @@ class JoinedLoader(AbstractRelationshipLoader): def load_collection_from_joined_exec(state, dict_, row): _instance(row) - populators["new"].append((self.key, load_collection_from_joined_new_row)) + populators["new"].append( + (self.key, load_collection_from_joined_new_row) + ) populators["existing"].append( - (self.key, load_collection_from_joined_existing_row)) + (self.key, load_collection_from_joined_existing_row) + ) if context.invoke_all_eagers: populators["eager"].append( - (self.key, load_collection_from_joined_exec)) + (self.key, load_collection_from_joined_exec) + ) def _create_scalar_loader(self, context, key, _instance, populators): def load_scalar_from_joined_new_row(state, dict_, row): @@ -1829,7 +1997,8 @@ class JoinedLoader(AbstractRelationshipLoader): util.warn( "Multiple rows returned with " "uselist=False for eagerly-loaded attribute '%s' " - % self) + % self + ) else: # this case is when one row has multiple loads of the # same entity (e.g. via aliasing), one has an attribute @@ -1841,17 +2010,25 @@ class JoinedLoader(AbstractRelationshipLoader): populators["new"].append((self.key, load_scalar_from_joined_new_row)) populators["existing"].append( - (self.key, load_scalar_from_joined_existing_row)) + (self.key, load_scalar_from_joined_existing_row) + ) if context.invoke_all_eagers: - populators["eager"].append((self.key, load_scalar_from_joined_exec)) + populators["eager"].append( + (self.key, load_scalar_from_joined_exec) + ) @log.class_logger @properties.RelationshipProperty.strategy_for(lazy="selectin") class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): __slots__ = ( - 'join_depth', 'omit_join', '_parent_alias', '_in_expr', - '_pk_cols', '_zero_idx', '_bakery' + "join_depth", + "omit_join", + "_parent_alias", + "_in_expr", + "_pk_cols", + "_zero_idx", + "_bakery", ) _chunksize = 500 @@ -1864,11 +2041,12 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): self.omit_join = self.parent_property.omit_join else: lazyloader = self.parent_property._get_strategy( - (("lazy", "select"),)) + (("lazy", "select"),) + ) self.omit_join = self.parent._get_clause[0].compare( lazyloader._rev_lazywhere, use_proxies=True, - equivalents=self.parent._equivalent_columns + equivalents=self.parent._equivalent_columns, ) if self.omit_join: self._init_for_omit_join() @@ -1886,8 +2064,8 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): ) self._pk_cols = fk_cols = [ - pk_to_fk[col] - for col in self.parent.primary_key if col in pk_to_fk] + pk_to_fk[col] for col in self.parent.primary_key if col in pk_to_fk + ] if len(fk_cols) > 1: self._in_expr = sql.tuple_(*fk_cols) self._zero_idx = False @@ -1899,7 +2077,8 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): self._parent_alias = aliased(self.parent.class_) pa_insp = inspect(self._parent_alias) self._pk_cols = pk_cols = [ - pa_insp._adapt_element(col) for col in self.parent.primary_key] + pa_insp._adapt_element(col) for col in self.parent.primary_key + ] if len(pk_cols) > 1: self._in_expr = sql.tuple_(*pk_cols) self._zero_idx = False @@ -1908,26 +2087,26 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): self._zero_idx = True def init_class_attribute(self, mapper): - self.parent_property.\ - _get_strategy((("lazy", "select"),)).\ - init_class_attribute(mapper) + self.parent_property._get_strategy( + (("lazy", "select"),) + ).init_class_attribute(mapper) @util.dependencies("sqlalchemy.ext.baked") def _memoized_attr__bakery(self, baked): return baked.bakery(size=50) def create_row_processor( - self, context, path, loadopt, mapper, - result, adapter, populators): + self, context, path, loadopt, mapper, result, adapter, populators + ): if not self.parent.class_manager[self.key].impl.supports_population: raise sa_exc.InvalidRequestError( "'%s' does not support object " - "population - eager loading cannot be applied." % - self + "population - eager loading cannot be applied." % self ) selectin_path = ( - context.query._current_path or orm_util.PathRegistry.root) + path + context.query._current_path or orm_util.PathRegistry.root + ) + path if not orm_util._entity_isa(path[-1], self.parent): return @@ -1941,8 +2120,8 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): # build up a path indicating the path from the leftmost # entity to the thing we're subquery loading. with_poly_info = path_w_prop.get( - context.attributes, - "path_with_polymorphic", None) + context.attributes, "path_with_polymorphic", None + ) if with_poly_info is not None: effective_entity = with_poly_info.entity @@ -1957,19 +2136,24 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): return loading.PostLoad.callable_for_path( - context, selectin_path, self.parent, self.key, - self._load_for_path, effective_entity) + context, + selectin_path, + self.parent, + self.key, + self._load_for_path, + effective_entity, + ) @util.dependencies("sqlalchemy.ext.baked") def _load_for_path( - self, baked, context, path, states, load_only, effective_entity): + self, baked, context, path, states, load_only, effective_entity + ): if load_only and self.key not in load_only: return our_states = [ - (state.key[1], state, overwrite) - for state, overwrite in states + (state.key[1], state, overwrite) for state, overwrite in states ] pk_cols = self._pk_cols @@ -1984,17 +2168,15 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): # parent entity and do not need adaption. insp = inspect(effective_entity) if insp.is_aliased_class: - pk_cols = [ - insp._adapt_element(col) - for col in pk_cols - ] + pk_cols = [insp._adapt_element(col) for col in pk_cols] in_expr = insp._adapt_element(in_expr) pk_cols = [insp._adapt_element(col) for col in pk_cols] q = self._bakery( lambda session: session.query( - query.Bundle("pk", *pk_cols), effective_entity, - ), self + query.Bundle("pk", *pk_cols), effective_entity + ), + self, ) if self.omit_join: @@ -2012,60 +2194,53 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): q.add_criteria( lambda q: q.select_from(pa).join( getattr(pa, self.parent_property.key).of_type( - effective_entity) + effective_entity + ) ) ) q.add_criteria( lambda q: q.filter( - in_expr.in_( - sql.bindparam("primary_keys", expanding=True)) - ).order_by(*pk_cols)) + in_expr.in_(sql.bindparam("primary_keys", expanding=True)) + ).order_by(*pk_cols) + ) orig_query = context.query q._add_lazyload_options( - orig_query._with_options, - path[self.parent_property] + orig_query._with_options, path[self.parent_property] ) if orig_query._populate_existing: - q.add_criteria( - lambda q: q.populate_existing() - ) + q.add_criteria(lambda q: q.populate_existing()) if self.parent_property.order_by: if self.omit_join: eager_order_by = self.parent_property.order_by if insp.is_aliased_class: eager_order_by = [ - insp._adapt_element(elem) for elem in - eager_order_by + insp._adapt_element(elem) for elem in eager_order_by ] - q.add_criteria( - lambda q: q.order_by(*eager_order_by) - ) + q.add_criteria(lambda q: q.order_by(*eager_order_by)) else: + def _setup_outermost_orderby(q): # imitate the same method that subquery eager loading uses, # looking for the adapted "secondary" table eagerjoin = q._from_obj[0] - eager_order_by = \ - eagerjoin._target_adapter.\ - copy_and_process( - util.to_list(self.parent_property.order_by) - ) + eager_order_by = eagerjoin._target_adapter.copy_and_process( + util.to_list(self.parent_property.order_by) + ) return q.order_by(*eager_order_by) - q.add_criteria( - _setup_outermost_orderby - ) + + q.add_criteria(_setup_outermost_orderby) uselist = self.uselist _empty_result = () if uselist else None while our_states: - chunk = our_states[0:self._chunksize] - our_states = our_states[self._chunksize:] + chunk = our_states[0 : self._chunksize] + our_states = our_states[self._chunksize :] data = { k: [vv[1] for vv in v] @@ -2073,9 +2248,10 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): q(context.session).params( primary_keys=[ key[0] if self._zero_idx else key - for key, state, overwrite in chunk] + for key, state, overwrite in chunk + ] ), - lambda x: x[0] + lambda x: x[0], ) } @@ -2091,13 +2267,15 @@ class SelectInLoader(AbstractRelationshipLoader, util.MemoizedSlots): util.warn( "Multiple rows returned with " "uselist=False for eagerly-loaded " - "attribute '%s' " - % self) + "attribute '%s' " % self + ) state.get_impl(self.key).set_committed_value( - state, state.dict, collection[0]) + state, state.dict, collection[0] + ) else: state.get_impl(self.key).set_committed_value( - state, state.dict, collection) + state, state.dict, collection + ) def single_parent_validator(desc, prop): @@ -2108,8 +2286,8 @@ def single_parent_validator(desc, prop): raise sa_exc.InvalidRequestError( "Instance %s is already associated with an instance " "of %s via its %s attribute, and is only allowed a " - "single parent." % - (orm_util.instance_str(value), state.class_, prop) + "single parent." + % (orm_util.instance_str(value), state.class_, prop) ) return value @@ -2120,8 +2298,6 @@ def single_parent_validator(desc, prop): return _do_check(state, value, oldvalue, initiator) event.listen( - desc, 'append', append, raw=True, retval=True, - active_history=True) - event.listen( - desc, 'set', set_, raw=True, retval=True, - active_history=True) + desc, "append", append, raw=True, retval=True, active_history=True + ) + event.listen(desc, "set", set_, raw=True, retval=True, active_history=True) |
