summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/strategies.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/strategies.py')
-rw-r--r--lib/sqlalchemy/orm/strategies.py1144
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)