From: Diana Clarke Date: Mon, 19 Nov 2012 22:19:24 +0000 (-0500) Subject: just a pep8 pass of lib/sqlalchemy/orm/ X-Git-Tag: rel_0_8_0b2~33^2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aba75454d064b157b546dbc379043f58c83a2b6d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git just a pep8 pass of lib/sqlalchemy/orm/ --- diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py index b58aa14a61..e5a2dbb871 100644 --- a/lib/sqlalchemy/orm/identity.py +++ b/lib/sqlalchemy/orm/identity.py @@ -39,8 +39,10 @@ class IdentityMap(dict): return self._modified def check_modified(self): - """return True if any InstanceStates present have been marked as 'modified'.""" + """return True if any InstanceStates present have been marked + as 'modified'. + """ return bool(self._modified) def has_key(self, key): @@ -64,6 +66,7 @@ class IdentityMap(dict): def __delitem__(self, key): raise NotImplementedError("IdentityMap uses remove() to remove data") + class WeakInstanceDict(IdentityMap): def __init__(self): IdentityMap.__init__(self) @@ -110,9 +113,10 @@ class WeakInstanceDict(IdentityMap): if existing_state is not state: o = existing_state.obj() if o is not None: - raise AssertionError("A conflicting state is already " - "present in the identity map for key %r" - % (key, )) + raise AssertionError( + "A conflicting state is already " + "present in the identity map for key %r" + % (key, )) else: return except KeyError: @@ -156,10 +160,12 @@ class WeakInstanceDict(IdentityMap): # return iter(self._values()) # Py2K items = _items + def iteritems(self): return iter(self.items()) values = _values + def itervalues(self): return iter(self.values()) # end Py2K @@ -180,12 +186,15 @@ class WeakInstanceDict(IdentityMap): def prune(self): return 0 + class StrongInstanceDict(IdentityMap): def all_states(self): return [attributes.instance_state(o) for o in self.itervalues()] def contains_state(self, state): - return state.key in self and attributes.instance_state(self[state.key]) is state + return ( + state.key in self and + attributes.instance_state(self[state.key]) is state) def replace(self, state): if dict.__contains__(self, state.key): @@ -232,4 +241,3 @@ class StrongInstanceDict(IdentityMap): dict.update(self, keepers) self.modified = bool(dirty) return ref_count - len(self) - diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py index 0e828ce876..5a4fc20934 100644 --- a/lib/sqlalchemy/orm/instrumentation.py +++ b/lib/sqlalchemy/orm/instrumentation.py @@ -32,9 +32,9 @@ alternate instrumentation forms. from . import exc, collections, events from operator import attrgetter from .. import event, util -import weakref state = util.importlater("sqlalchemy.orm", "state") + class ClassManager(dict): """tracks state information at the class level.""" @@ -308,6 +308,7 @@ class ClassManager(dict): return '<%s of %r at %x>' % ( self.__class__.__name__, self.class_, id(self)) + class InstrumentationFactory(object): """Factory for new ClassManager instances.""" @@ -352,6 +353,7 @@ class InstrumentationFactory(object): # when importred. _instrumentation_factory = InstrumentationFactory() + def register_class(class_): """Register class instrumentation. @@ -364,6 +366,7 @@ def register_class(class_): manager = _instrumentation_factory.create_manager_for_cls(class_) return manager + def unregister_class(class_): """Unregister class instrumentation.""" @@ -390,6 +393,7 @@ instance_dict = _default_dict_getter = ClassManager.dict_getter() manager_of_class = _default_manager_getter = ClassManager.manager_getter() + def _generate_init(class_, class_manager): """Build an __init__ decorator that triggers ClassManager events.""" @@ -433,4 +437,3 @@ def __init__(%(apply_pos)s): #if func_kw_defaults: # __init__.__kwdefaults__ = func_kw_defaults return __init__ - diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index b30630434d..c91746da0e 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -16,7 +16,6 @@ classes within should be considered mostly private. """ from __future__ import absolute_import -from itertools import chain from .. import exc as sa_exc, util, inspect from ..sql import operators @@ -53,6 +52,7 @@ from .deprecated_interfaces import AttributeExtension, \ SessionExtension, \ MapperExtension + class _InspectionAttr(object): """Define a series of attributes that all ORM inspection targets need to have.""" @@ -65,11 +65,14 @@ class _InspectionAttr(object): is_attribute = False is_clause_element = False + class _MappedAttribute(object): """Mixin for attributes which should be replaced by mapper-assigned attributes. """ + + class MapperProperty(_MappedAttribute, _InspectionAttr): """Manage the relationship of a ``Mapper`` to a single class attribute, as well as that attribute as it appears on individual @@ -80,7 +83,8 @@ class MapperProperty(_MappedAttribute, _InspectionAttr): mapped :class:`.Column`, which is represented in a mapping as an instance of :class:`.ColumnProperty`, and a reference to another class produced by :func:`.relationship`, - represented in the mapping as an instance of :class:`.RelationshipProperty`. + represented in the mapping as an instance of + :class:`.RelationshipProperty`. """ @@ -185,7 +189,6 @@ class MapperProperty(_MappedAttribute, _InspectionAttr): """ pass - def is_primary(self): """Return True if this ``MapperProperty``'s mapper is the primary mapper for its class. @@ -216,6 +219,7 @@ class MapperProperty(_MappedAttribute, _InspectionAttr): return operator(self.comparator, value) + class PropComparator(operators.ColumnOperators): """Defines boolean, comparison, and other operators for :class:`.MapperProperty` objects. @@ -223,8 +227,8 @@ class PropComparator(operators.ColumnOperators): SQLAlchemy allows for operators to be redefined at both the Core and ORM level. :class:`.PropComparator` is the base class of operator redefinition for ORM-level operations, - including those of :class:`.ColumnProperty`, :class:`.RelationshipProperty`, - and :class:`.CompositeProperty`. + including those of :class:`.ColumnProperty`, + :class:`.RelationshipProperty`, and :class:`.CompositeProperty`. .. note:: With the advent of Hybrid properties introduced in SQLAlchemy 0.7, as well as Core-level operator redefinition in @@ -274,10 +278,10 @@ class PropComparator(operators.ColumnOperators): class SomeMappedClass(Base): some_column = column_property(Column("some_column", String), - comparator_factory=MyColumnComparator) + comparator_factory=MyColumnComparator) some_relationship = relationship(SomeOtherClass, - comparator_factory=MyRelationshipComparator) + comparator_factory=MyRelationshipComparator) some_composite = composite( Column("a", String), Column("b", String), @@ -310,7 +314,6 @@ class PropComparator(operators.ColumnOperators): self._parentmapper = parentmapper self.adapter = adapter - def __clause_element__(self): raise NotImplementedError("%r" % self) @@ -345,8 +348,8 @@ class PropComparator(operators.ColumnOperators): query.join(Company.employees.of_type(Engineer)).\\ filter(Engineer.name=='foo') - :param \class_: a class or mapper indicating that criterion will be against - this specific subclass. + :param \class_: a class or mapper indicating that criterion will be + against this specific subclass. """ @@ -363,9 +366,9 @@ class PropComparator(operators.ColumnOperators): :param criterion: an optional ClauseElement formulated against the member class' table or attributes. - :param \**kwargs: key/value pairs corresponding to member class attribute - names which will be compared via equality to the corresponding - values. + :param \**kwargs: key/value pairs corresponding to member class + attribute names which will be compared via equality to the + corresponding values. """ @@ -381,9 +384,9 @@ class PropComparator(operators.ColumnOperators): :param criterion: an optional ClauseElement formulated against the member class' table or attributes. - :param \**kwargs: key/value pairs corresponding to member class attribute - names which will be compared via equality to the corresponding - values. + :param \**kwargs: key/value pairs corresponding to member class + attribute names which will be compared via equality to the + corresponding values. """ @@ -456,6 +459,7 @@ class StrategizedProperty(MapperProperty): not mapper.class_manager._attr_has_impl(self.key): self.strategy.init_class_attribute(mapper) + class MapperOption(object): """Describe a modification to a Query.""" @@ -476,6 +480,7 @@ class MapperOption(object): self.process_query(query) + class PropertyOption(MapperOption): """A MapperOption that is applied to a property off the mapper or one of its child mappers, identified by a dot-separated key @@ -685,6 +690,7 @@ class PropertyOption(MapperOption): return paths + class StrategizedOption(PropertyOption): """A MapperOption that affects which LoaderStrategy will be used for an operation by a StrategizedProperty. @@ -711,6 +717,7 @@ class StrategizedOption(PropertyOption): def get_strategy_class(self): raise NotImplementedError() + class LoaderStrategy(object): """Describe the loading behavior of a StrategizedProperty object. @@ -758,5 +765,3 @@ class LoaderStrategy(object): def __str__(self): return str(self.parent_property) - - diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index df1477210f..a5d156a1fb 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -23,6 +23,7 @@ sessionlib = util.importlater("sqlalchemy.orm", "session") _new_runid = util.counter() + def instances(query, cursor, context): """Return an ORM result as an iterator.""" session = query.session @@ -96,6 +97,7 @@ def instances(query, cursor, context): if not query._yield_per: break + def merge_result(query, iterator, load=True): """Merge a result into this :class:`.Query` object's Session.""" @@ -137,6 +139,7 @@ def merge_result(query, iterator, load=True): finally: session.autoflush = autoflush + def get_from_identity(session, key, passive): """Look up the given key in the given session's identity map, check the object for expired state if found. @@ -165,6 +168,7 @@ def get_from_identity(session, key, passive): else: return None + def load_on_ident(query, key, refresh_state=None, lockmode=None, only_load_props=None): @@ -222,6 +226,7 @@ def load_on_ident(query, key, except orm_exc.NoResultFound: return None + def instance_processor(mapper, context, path, adapter, polymorphic_from=None, only_load_props=None, @@ -475,7 +480,6 @@ def instance_processor(mapper, context, path, adapter, if isnew: state.manager.dispatch.refresh(state, context, attrs) - if result is not None: if append_result: for fn in append_result: @@ -491,6 +495,7 @@ def instance_processor(mapper, context, path, adapter, return instance return _instance + def _populators(mapper, context, path, row, adapter, new_populators, existing_populators, eager_populators): """Produce a collection of attribute level row processor @@ -509,6 +514,7 @@ def _populators(mapper, context, path, row, adapter, if delayed_populators: new_populators.extend(delayed_populators) + def _configure_subclass_mapper(mapper, context, path, adapter): """Produce a mapper level row processor callable factory for mappers inheriting this one.""" @@ -538,6 +544,7 @@ def _configure_subclass_mapper(mapper, context, path, adapter): polymorphic_from=mapper) return configure_subclass_mapper + def load_scalar_attributes(mapper, state, attribute_names): """initiate a column-based attribute refresh operation.""" @@ -599,4 +606,3 @@ def load_scalar_attributes(mapper, state, attribute_names): # may not complete (even if PK attributes are assigned) if has_key and result is None: raise orm_exc.ObjectDeletedError(state) - diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index dfd8a12b7c..b89163340c 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -54,6 +54,7 @@ NO_ATTRIBUTE = util.symbol('NO_ATTRIBUTE') # lock used to synchronize the "mapper configure" step _CONFIGURE_MUTEX = util.threading.RLock() + class Mapper(_InspectionAttr): """Define the correlation of class attributes to database table columns. @@ -629,7 +630,6 @@ class Mapper(_InspectionAttr): column=None): self._adapt_inherited_property(key, prop, False) - def _set_polymorphic_on(self, polymorphic_on): self.polymorphic_on = polymorphic_on self._configure_polymorphic_setter(True) @@ -745,7 +745,6 @@ class Mapper(_InspectionAttr): configure_mappers() return self - @property @util.deprecated("0.7", message=":attr:`.Mapper.compiled` " "is replaced by :attr:`.Mapper.configured`") @@ -1051,8 +1050,6 @@ class Mapper(_InspectionAttr): else: self._set_polymorphic_identity = None - - def _adapt_inherited_property(self, key, prop, init): if not self.concrete: self._configure_property(key, prop, init=False, setparent=False) @@ -1409,7 +1406,6 @@ class Mapper(_InspectionAttr): return [self] return self._mappers_from_spec(*self.with_polymorphic) - @_memoized_configured_property def _with_polymorphic_selectable(self): if not self.with_polymorphic: @@ -1822,7 +1818,6 @@ class Mapper(_InspectionAttr): return state.manager[prop.key].impl.\ get_committed_value(state, dict_, passive=passive) - def _optimized_get_statement(self, state, attribute_names): """assemble a WHERE clause which retrieves a given state by primary key, using a minimized set of tables. @@ -2008,6 +2003,7 @@ class Mapper(_InspectionAttr): inspection._self_inspects(Mapper) log.class_logger(Mapper) + def configure_mappers(): """Initialize the inter-mapper relationships of all mappers that have been constructed thus far. @@ -2068,6 +2064,7 @@ def configure_mappers(): if _call_configured is not None: _call_configured.dispatch.after_configured() + def reconstructor(fn): """Decorate a method as the 'reconstructor' hook. @@ -2087,6 +2084,7 @@ def reconstructor(fn): fn.__sa_reconstructor__ = True return fn + def validates(*names, **kw): """Decorate a method as a 'validator' for one or more named properties. @@ -2120,11 +2118,13 @@ def validates(*names, **kw): return fn return wrap + def _event_on_load(state, ctx): instrumenting_mapper = state.manager.info[_INSTRUMENTOR] if instrumenting_mapper._reconstructor: instrumenting_mapper._reconstructor(state.obj()) + def _event_on_first_init(manager, cls): """Initial mapper compilation trigger. @@ -2138,6 +2138,7 @@ def _event_on_first_init(manager, cls): if _new_mappers: configure_mappers() + def _event_on_init(state, args, kwargs): """Run init_instance hooks. @@ -2154,6 +2155,7 @@ def _event_on_init(state, args, kwargs): if instrumenting_mapper._set_polymorphic_identity: instrumenting_mapper._set_polymorphic_identity(state) + def _event_on_resurrect(state): # re-populate the primary key elements # of the dict based on the mapping. diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py index 5945addc4c..4774667b24 100644 --- a/lib/sqlalchemy/orm/persistence.py +++ b/lib/sqlalchemy/orm/persistence.py @@ -20,6 +20,7 @@ from . import attributes, sync, exc as orm_exc, evaluator from .util import _state_mapper, state_str, _attr_as_key from ..sql import expression + def save_obj(base_mapper, states, uowtransaction, single=False): """Issue ``INSERT`` and/or ``UPDATE`` statements for a list of objects. @@ -64,6 +65,7 @@ def save_obj(base_mapper, states, uowtransaction, single=False): _finalize_insert_update_commands(base_mapper, uowtransaction, states_to_insert, states_to_update) + def post_update(base_mapper, states, uowtransaction, post_update_cols): """Issue UPDATE statements on behalf of a relationship() which specifies post_update. @@ -75,7 +77,6 @@ def post_update(base_mapper, states, uowtransaction, post_update_cols): base_mapper, states, uowtransaction) - for table, mapper in base_mapper._sorted_tables.iteritems(): update = _collect_post_update_commands(base_mapper, uowtransaction, table, states_to_update, @@ -86,6 +87,7 @@ def post_update(base_mapper, states, uowtransaction, post_update_cols): cached_connections, mapper, table, update) + def delete_obj(base_mapper, states, uowtransaction): """Issue ``DELETE`` statements for a list of objects. @@ -116,6 +118,7 @@ def delete_obj(base_mapper, states, uowtransaction): in states_to_delete: mapper.dispatch.after_delete(mapper, connection, state) + def _organize_states_for_save(base_mapper, states, uowtransaction): """Make an initial pass across a set of states for INSERT or UPDATE. @@ -185,6 +188,7 @@ def _organize_states_for_save(base_mapper, states, uowtransaction): return states_to_insert, states_to_update + def _organize_states_for_post_update(base_mapper, states, uowtransaction): """Make an initial pass across a set of states for UPDATE @@ -198,6 +202,7 @@ def _organize_states_for_post_update(base_mapper, states, return list(_connections_for_states(base_mapper, uowtransaction, states)) + def _organize_states_for_delete(base_mapper, states, uowtransaction): """Make an initial pass across a set of states for DELETE. @@ -218,6 +223,7 @@ def _organize_states_for_delete(base_mapper, states, uowtransaction): bool(state.key), connection)) return states_to_delete + def _collect_insert_commands(base_mapper, uowtransaction, table, states_to_insert): """Identify sets of values to use in INSERT statements for a @@ -261,6 +267,7 @@ def _collect_insert_commands(base_mapper, uowtransaction, table, connection, value_params, has_all_pks)) return insert + def _collect_update_commands(base_mapper, uowtransaction, table, states_to_update): """Identify sets of values to use in UPDATE statements for a @@ -412,6 +419,7 @@ def _collect_post_update_commands(base_mapper, uowtransaction, table, connection)) return update + def _collect_delete_commands(base_mapper, uowtransaction, table, states_to_delete): """Identify values to use in DELETE statements for a list of @@ -507,6 +515,7 @@ def _emit_update_statements(base_mapper, uowtransaction, c.dialect.dialect_description, stacklevel=12) + def _emit_insert_statements(base_mapper, uowtransaction, cached_connections, table, insert): """Emit INSERT statements corresponding to value lists collected @@ -582,7 +591,6 @@ def _emit_insert_statements(base_mapper, uowtransaction, value_params) - def _emit_post_update_statements(base_mapper, uowtransaction, cached_connections, mapper, table, update): """Emit UPDATE statements corresponding to value lists collected @@ -703,6 +711,7 @@ def _finalize_insert_update_commands(base_mapper, uowtransaction, else: mapper.dispatch.after_update(mapper, connection, state) + def _postfetch(mapper, uowtransaction, table, state, dict_, prefetch_cols, postfetch_cols, params, value_params): @@ -733,6 +742,7 @@ def _postfetch(mapper, uowtransaction, table, uowtransaction, mapper.passive_updates) + def _connections_for_states(base_mapper, uowtransaction, states): """Return an iterator of (state, state.dict, mapper, connection). @@ -762,6 +772,7 @@ def _connections_for_states(base_mapper, uowtransaction, states): yield state, state.dict, mapper, connection + def _cached_connection_dict(base_mapper): # dictionary of connection->connection_with_cache_options. return util.PopulateDict( @@ -769,6 +780,7 @@ def _cached_connection_dict(base_mapper): compiled_cache=base_mapper._compiled_cache )) + def _sort_states(states): pending = set(states) persistent = set(s for s in pending if s.key is not None) @@ -776,6 +788,7 @@ def _sort_states(states): return sorted(pending, key=operator.attrgetter("insert_order")) + \ sorted(persistent, key=lambda q: q.key[1]) + class BulkUD(object): """Handle bulk update and deletes via a :class:`.Query`.""" @@ -825,6 +838,7 @@ class BulkUD(object): def _do_post_synchronize(self): pass + class BulkEvaluate(BulkUD): """BulkUD which does the 'evaluate' method of session state resolution.""" @@ -858,6 +872,7 @@ class BulkEvaluate(BulkUD): if issubclass(cls, target_cls) and eval_condition(obj)] + class BulkFetch(BulkUD): """BulkUD which does the 'fetch' method of session state resolution.""" @@ -870,6 +885,7 @@ class BulkFetch(BulkUD): select_stmt, params=query._params).fetchall() + class BulkUpdate(BulkUD): """BulkUD which handles UPDATEs.""" @@ -899,6 +915,7 @@ class BulkUpdate(BulkUD): session.dispatch.after_bulk_update(session, self.query, self.context, self.result) + class BulkDelete(BulkUD): """BulkUD which handles DELETEs.""" @@ -927,6 +944,7 @@ class BulkDelete(BulkUD): session.dispatch.after_bulk_delete(session, self.query, self.context, self.result) + class BulkUpdateEvaluate(BulkEvaluate, BulkUpdate): """BulkUD which handles UPDATEs using the "evaluate" method of session resolution.""" @@ -962,6 +980,7 @@ class BulkUpdateEvaluate(BulkEvaluate, BulkUpdate): states.add(state) session._register_altered(states) + class BulkDeleteEvaluate(BulkEvaluate, BulkDelete): """BulkUD which handles DELETEs using the "evaluate" method of session resolution.""" @@ -971,6 +990,7 @@ class BulkDeleteEvaluate(BulkEvaluate, BulkDelete): [attributes.instance_state(obj) for obj in self.matched_objects]) + class BulkUpdateFetch(BulkFetch, BulkUpdate): """BulkUD which handles UPDATEs using the "fetch" method of session resolution.""" @@ -993,6 +1013,7 @@ class BulkUpdateFetch(BulkFetch, BulkUpdate): session._expire_state(state, attrib) session._register_altered(states) + class BulkDeleteFetch(BulkFetch, BulkDelete): """BulkUD which handles DELETEs using the "fetch" method of session resolution.""" @@ -1011,4 +1032,3 @@ class BulkDeleteFetch(BulkFetch, BulkDelete): session.identity_map[identity_key] )] ) - diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index e2b5e94e06..12656952a5 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -44,7 +44,8 @@ class ColumnProperty(StrategizedProperty): def __init__(self, *columns, **kwargs): """Construct a ColumnProperty. - Note the public constructor is the :func:`.orm.column_property` function. + Note the public constructor is the :func:`.orm.column_property` + function. :param \*columns: The list of `columns` describes a single object property. If there are multiple tables joined @@ -108,7 +109,6 @@ class ColumnProperty(StrategizedProperty): else: self.strategy_class = strategies.ColumnLoader - @property def expression(self): """Return the primary column or expression for this ColumnProperty. @@ -170,7 +170,8 @@ class ColumnProperty(StrategizedProperty): """Produce boolean, comparison, and other operators for :class:`.ColumnProperty` attributes. - See the documentation for :class:`.PropComparator` for a brief overview. + See the documentation for :class:`.PropComparator` for a brief + overview. See also: @@ -189,8 +190,8 @@ class ColumnProperty(StrategizedProperty): return self.adapter(self.prop.columns[0]) else: return self.prop.columns[0]._annotate({ - "parententity": self._parentmapper, - "parentmapper": self._parentmapper}) + "parententity": self._parentmapper, + "parentmapper": self._parentmapper}) def __getattr__(self, key): """proxy attribute access down to the mapped column. @@ -214,6 +215,7 @@ class ColumnProperty(StrategizedProperty): log.class_logger(ColumnProperty) + class RelationshipProperty(StrategizedProperty): """Describes an object property that holds a single item or list of items that correspond to a related database table. @@ -541,7 +543,8 @@ class RelationshipProperty(StrategizedProperty): # should not correlate or otherwise reach out # to anything in the enclosing query. if criterion is not None: - criterion = criterion._annotate({'no_replacement_traverse': True}) + criterion = criterion._annotate( + {'no_replacement_traverse': True}) crit = j & criterion @@ -582,7 +585,8 @@ class RelationshipProperty(StrategizedProperty): will produce:: SELECT * FROM my_table WHERE - NOT EXISTS (SELECT 1 FROM related WHERE related.my_id=my_table.id) + NOT EXISTS (SELECT 1 FROM related WHERE + related.my_id=my_table.id) :meth:`~.RelationshipProperty.Comparator.any` is only valid for collections, i.e. a :func:`.relationship` @@ -612,8 +616,8 @@ class RelationshipProperty(StrategizedProperty): Will produce a query like:: SELECT * FROM my_table WHERE - EXISTS (SELECT 1 FROM related WHERE related.id==my_table.related_id - AND related.x=2) + EXISTS (SELECT 1 FROM related WHERE + related.id==my_table.related_id AND related.x=2) Because :meth:`~.RelationshipProperty.Comparator.has` uses a correlated subquery, its performance is not nearly as @@ -706,10 +710,9 @@ class RelationshipProperty(StrategizedProperty): state = attributes.instance_state(other) def state_bindparam(x, state, col): - o = state.obj() # strong ref - return sql.bindparam(x, unique=True, callable_=lambda : \ - self.property.mapper._get_committed_attr_by_column(o, - col)) + o = state.obj() # strong ref + return sql.bindparam(x, unique=True, callable_=lambda: \ + self.property.mapper._get_committed_attr_by_column(o, col)) def adapt(col): if self.adapter: @@ -724,7 +727,7 @@ class RelationshipProperty(StrategizedProperty): adapt(x) == None) for (x, y) in self.property.local_remote_pairs]) - criterion = sql.and_(*[x==y for (x, y) in + criterion = sql.and_(*[x == y for (x, y) in zip( self.property.mapper.primary_key, self.property.\ @@ -835,7 +838,6 @@ class RelationshipProperty(StrategizedProperty): if (source_state, r) in _recursive: return - if not "merge" in self.cascade: return @@ -912,8 +914,8 @@ class RelationshipProperty(StrategizedProperty): else: return [(attributes.instance_state(x), x)] - - def cascade_iterator(self, type_, state, dict_, visited_states, halt_on=None): + def cascade_iterator(self, type_, state, dict_, + visited_states, halt_on=None): #assert type_ in self.cascade # only actively lazy load on the 'delete' cascade @@ -967,7 +969,6 @@ class RelationshipProperty(StrategizedProperty): yield c, instance_mapper, instance_state, instance_dict - def _add_reverse_property(self, key): other = self.mapper.get_property(key, _configure_mappers=False) self._reverse_property.add(other) @@ -1140,7 +1141,6 @@ class RelationshipProperty(StrategizedProperty): "cause dependency issues during flush" % (self.key, self.parent, inheriting)) - def _check_cascade_settings(self): if self.cascade.delete_orphan and not self.single_parent \ and (self.direction is MANYTOMANY or self.direction @@ -1288,4 +1288,3 @@ class RelationshipProperty(StrategizedProperty): PropertyLoader = RelationProperty = RelationshipProperty log.class_logger(RelationshipProperty) - diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index a34fd882a8..ca334e2735 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -27,7 +27,7 @@ from . import ( from .util import ( AliasedClass, ORMAdapter, _entity_descriptor, PathRegistry, _is_aliased_class, _is_mapped_class, _orm_columns, - join as orm_join,with_parent, aliased + join as orm_join, with_parent, aliased ) from .. import sql, util, log, exc as sa_exc, inspect, inspection, \ types as sqltypes @@ -54,6 +54,7 @@ def _generative(*assertions): _path_registry = PathRegistry.root + class Query(object): """ORM-level SQL construction object. @@ -177,7 +178,6 @@ class Query(object): self._from_obj_alias = sql_util.ColumnAdapter( self._from_obj[0], equivs) - def _reset_polymorphic_adapter(self, mapper): for m2 in mapper._with_polymorphic_mappers: self._polymorphic_adapters.pop(m2, None) @@ -274,7 +274,6 @@ class Query(object): return self._select_from_entity or \ self._entity_zero().entity_zero - @property def _mapper_entities(self): # TODO: this is wrong, its hardcoded to "primary entity" when @@ -325,7 +324,6 @@ class Query(object): ) return self._entity_zero() - def __all_equivs(self): equivs = {} for ent in self._mapper_entities: @@ -540,10 +538,9 @@ class Query(object): return self.enable_eagerloads(False).statement.label(name) - def as_scalar(self): - """Return the full SELECT statement represented by this :class:`.Query`, converted - to a scalar subquery. + """Return the full SELECT statement represented by this + :class:`.Query`, converted to a scalar subquery. Analogous to :meth:`sqlalchemy.sql.SelectBaseMixin.as_scalar`. @@ -618,7 +615,8 @@ class Query(object): @property def whereclause(self): - """A readonly attribute which returns the current WHERE criterion for this Query. + """A readonly attribute which returns the current WHERE criterion for + this Query. This returned value is a SQL expression construct, or ``None`` if no criterion has been established. @@ -648,11 +646,11 @@ class Query(object): :meth:`.Query.with_polymorphic` applies transformations to the "main" mapped class represented by this :class:`.Query`. The "main" mapped class here means the :class:`.Query` - object's first argument is a full class, i.e. ``session.query(SomeClass)``. - These transformations allow additional tables to be present - in the FROM clause so that columns for a joined-inheritance - subclass are available in the query, both for the purposes - of load-time efficiency as well as the ability to use + object's first argument is a full class, i.e. + ``session.query(SomeClass)``. These transformations allow additional + tables to be present in the FROM clause so that columns for a + joined-inheritance subclass are available in the query, both for the + purposes of load-time efficiency as well as the ability to use these columns at query time. See the documentation section :ref:`with_polymorphic` for @@ -783,7 +781,8 @@ class Query(object): not mapper.always_refresh and \ self._lockmode is None: - instance = loading.get_from_identity(self.session, key, attributes.PASSIVE_OFF) + instance = loading.get_from_identity( + self.session, key, attributes.PASSIVE_OFF) if instance is not None: # reject calls for id in identity map but class # mismatch. @@ -980,8 +979,8 @@ class Query(object): @_generative() def with_entities(self, *entities): - """Return a new :class:`.Query` replacing the SELECT list with the given - entities. + """Return a new :class:`.Query` replacing the SELECT list with the + given entities. e.g.:: @@ -1006,7 +1005,6 @@ class Query(object): """ self._set_entities(entities) - @_generative() def add_columns(self, *column): """Add one or more column expressions to the list @@ -1024,13 +1022,13 @@ class Query(object): ":meth:`.add_column` is superseded by :meth:`.add_columns`", False) def add_column(self, column): - """Add a column expression to the list of result columns to be returned. + """Add a column expression to the list of result columns to be + returned. Pending deprecation: :meth:`.add_column` will be superseded by :meth:`.add_columns`. """ - return self.add_columns(column) def options(self, *args): @@ -1340,9 +1338,8 @@ class Query(object): """ - return self._from_selectable( - expression.union(*([self]+ list(q)))) + expression.union(*([self] + list(q)))) def union_all(self, *q): """Produce a UNION ALL of this Query against one or more queries. @@ -1352,7 +1349,7 @@ class Query(object): """ return self._from_selectable( - expression.union_all(*([self]+ list(q))) + expression.union_all(*([self] + list(q))) ) def intersect(self, *q): @@ -1363,7 +1360,7 @@ class Query(object): """ return self._from_selectable( - expression.intersect(*([self]+ list(q))) + expression.intersect(*([self] + list(q))) ) def intersect_all(self, *q): @@ -1374,7 +1371,7 @@ class Query(object): """ return self._from_selectable( - expression.intersect_all(*([self]+ list(q))) + expression.intersect_all(*([self] + list(q))) ) def except_(self, *q): @@ -1385,7 +1382,7 @@ class Query(object): """ return self._from_selectable( - expression.except_(*([self]+ list(q))) + expression.except_(*([self] + list(q))) ) def except_all(self, *q): @@ -1396,7 +1393,7 @@ class Query(object): """ return self._from_selectable( - expression.except_all(*([self]+ list(q))) + expression.except_all(*([self] + list(q))) ) def join(self, *props, **kwargs): @@ -1422,9 +1419,9 @@ class Query(object): In the above example we refer to ``User.addresses`` as passed to :meth:`~.Query.join` as the *on clause*, that is, it indicates how the "ON" portion of the JOIN should be constructed. For a - single-entity query such as the one above (i.e. we start by selecting only from - ``User`` and nothing else), the relationship can also be specified by its - string name:: + single-entity query such as the one above (i.e. we start by selecting + only from ``User`` and nothing else), the relationship can also be + specified by its string name:: q = session.query(User).join("addresses") @@ -1434,8 +1431,9 @@ class Query(object): q = session.query(User).join("orders", "items", "keywords") - The above would be shorthand for three separate calls to :meth:`~.Query.join`, - each using an explicit attribute to indicate the source entity:: + The above would be shorthand for three separate calls to + :meth:`~.Query.join`, each using an explicit attribute to indicate + the source entity:: q = session.query(User).\\ join(User.orders).\\ @@ -1511,25 +1509,26 @@ class Query(object): There is a lot of flexibility in what the "target" can be when using :meth:`~.Query.join`. As noted previously, it also accepts - :class:`.Table` constructs and other selectables such as :func:`.alias` - and :func:`.select` constructs, with either the one or two-argument forms:: + :class:`.Table` constructs and other selectables such as + :func:`.alias` and :func:`.select` constructs, with either the one + or two-argument forms:: addresses_q = select([Address.user_id]).\\ - where(Address.email_address.endswith("@bar.com")).\\ - alias() + where(Address.email_address.endswith("@bar.com")).\\ + alias() q = session.query(User).\\ join(addresses_q, addresses_q.c.user_id==User.id) :meth:`~.Query.join` also features the ability to *adapt* a - :meth:`~sqlalchemy.orm.relationship` -driven ON clause to the target selectable. - Below we construct a JOIN from ``User`` to a subquery against ``Address``, allowing - the relationship denoted by ``User.addresses`` to *adapt* itself - to the altered target:: + :meth:`~sqlalchemy.orm.relationship` -driven ON clause to the target + selectable. Below we construct a JOIN from ``User`` to a subquery + against ``Address``, allowing the relationship denoted by + ``User.addresses`` to *adapt* itself to the altered target:: address_subq = session.query(Address).\\ - filter(Address.email_address == 'ed@foo.com').\\ - subquery() + filter(Address.email_address == 'ed@foo.com').\\ + subquery() q = session.query(User).join(address_subq, User.addresses) @@ -1811,7 +1810,7 @@ class Query(object): if not create_aliases and prop: self._update_joinpoint({ '_joinpoint_entity': right, - 'prev':((left, right, prop.key), self._joinpoint) + 'prev': ((left, right, prop.key), self._joinpoint) }) else: self._joinpoint = { @@ -2051,7 +2050,7 @@ class Query(object): if item == -1: return list(self)[-1] else: - return list(self[item:item+1])[0] + return list(self[item:item + 1])[0] @_generative(_no_statement_condition) def slice(self, start, stop): @@ -2261,8 +2260,8 @@ class Query(object): def _execute_and_instances(self, querycontext): conn = self._connection_from_session( - mapper = self._mapper_zero_or_none(), - clause = querycontext.statement, + mapper=self._mapper_zero_or_none(), + clause=querycontext.statement, close_with_result=True) result = conn.execute(querycontext.statement, self._params) @@ -2330,20 +2329,20 @@ class Query(object): return loading.instances(self, cursor, context) - def merge_result(self, iterator, load=True): """Merge a result into this :class:`.Query` object's Session. - Given an iterator returned by a :class:`.Query` of the same structure as this - one, return an identical iterator of results, with all mapped - instances merged into the session using :meth:`.Session.merge`. This is an - optimized method which will merge all mapped instances, preserving the - structure of the result rows and unmapped columns with less method - overhead than that of calling :meth:`.Session.merge` explicitly for each - value. + Given an iterator returned by a :class:`.Query` of the same structure + as this one, return an identical iterator of results, with all mapped + instances merged into the session using :meth:`.Session.merge`. This + is an optimized method which will merge all mapped instances, + preserving the structure of the result rows and unmapped columns with + less method overhead than that of calling :meth:`.Session.merge` + explicitly for each value. The structure of the results is determined based on the column list of - this :class:`.Query` - if these do not correspond, unchecked errors will occur. + this :class:`.Query` - if these do not correspond, unchecked errors + will occur. The 'load' argument is the same as that of :meth:`.Session.merge`. @@ -2359,12 +2358,12 @@ class Query(object): @property def _select_args(self): return { - 'limit':self._limit, - 'offset':self._offset, - 'distinct':self._distinct, - 'prefixes':self._prefixes, - 'group_by':self._group_by or None, - 'having':self._having + 'limit': self._limit, + 'offset': self._offset, + 'distinct': self._distinct, + 'prefixes': self._prefixes, + 'group_by': self._group_by or None, + 'having': self._having } @property @@ -2435,8 +2434,8 @@ class Query(object): removed from the session. Matched objects are removed from the session. - ``'evaluate'`` - Evaluate the query's criteria in Python straight on - the objects in the session. If evaluation of the criteria isn't + ``'evaluate'`` - Evaluate the query's criteria in Python straight + on the objects in the session. If evaluation of the criteria isn't implemented, an error is raised. In that case you probably want to use the 'fetch' strategy as a fallback. @@ -2487,8 +2486,8 @@ class Query(object): objects that are matched by the update query. The updated attributes are expired on matched objects. - ``'evaluate'`` - Evaluate the Query's criteria in Python straight on - the objects in the session. If evaluation of the criteria isn't + ``'evaluate'`` - Evaluate the Query's criteria in Python straight + on the objects in the session. If evaluation of the criteria isn't implemented, an exception is raised. The expression evaluator currently doesn't account for differing @@ -2522,7 +2521,6 @@ class Query(object): update_op.exec_() return update_op.rowcount - _lockmode_lookup = { 'read': 'read', 'read_nowait': 'read_nowait', @@ -2708,6 +2706,7 @@ class Query(object): inspection._self_inspects(Query) + class _QueryEntity(object): """represent an entity column returned within a Query result.""" @@ -2726,6 +2725,7 @@ class _QueryEntity(object): q.__dict__ = self.__dict__.copy() return q + class _MapperEntity(_QueryEntity): """mapper/class/AliasedClass entity""" @@ -2739,7 +2739,7 @@ class _MapperEntity(_QueryEntity): def setup_entity(self, ext_info, aliased_adapter): self.mapper = ext_info.mapper self.aliased_adapter = aliased_adapter - self.selectable = ext_info.selectable + self.selectable = ext_info.selectable self.is_aliased_class = ext_info.is_aliased_class self._with_polymorphic = ext_info.with_polymorphic_mappers self._polymorphic_discriminator = \ @@ -2829,28 +2829,27 @@ class _MapperEntity(_QueryEntity): # require row aliasing unconditionally. if not adapter and self.mapper._requires_row_aliasing: adapter = sql_util.ColumnAdapter( - self.selectable, - self.mapper._equivalent_columns) + self.selectable, + self.mapper._equivalent_columns) if self.primary_entity: _instance = loading.instance_processor( - self.mapper, - context, - self.path, - adapter, - only_load_props=query._only_load_props, - refresh_state=context.refresh_state, - polymorphic_discriminator= - self._polymorphic_discriminator + self.mapper, + context, + self.path, + adapter, + only_load_props=query._only_load_props, + refresh_state=context.refresh_state, + polymorphic_discriminator=self._polymorphic_discriminator ) else: _instance = loading.instance_processor( - self.mapper, - context, - self.path, - adapter, - polymorphic_discriminator= - self._polymorphic_discriminator) + self.mapper, + context, + self.path, + adapter, + polymorphic_discriminator=self._polymorphic_discriminator + ) return _instance, self._label_name @@ -2902,6 +2901,7 @@ class _MapperEntity(_QueryEntity): def __str__(self): return str(self.mapper) + class _ColumnEntity(_QueryEntity): """Column/expression based entity.""" @@ -2931,7 +2931,6 @@ class _ColumnEntity(_QueryEntity): if c is not column: return - if not isinstance(column, sql.ColumnElement): raise sa_exc.InvalidRequestError( "SQL expression, column, or mapped entity " @@ -2981,7 +2980,6 @@ class _ColumnEntity(_QueryEntity): else: self.entity_zero = None - @property def entity_zero_or_selectable(self): if self.entity_zero is not None: @@ -2995,7 +2993,6 @@ class _ColumnEntity(_QueryEntity): def type(self): return self.column.type - def adapt_to_selectable(self, query, sel): c = _ColumnEntity(query, sel.corresponding_column(self.column)) c._label_name = self._label_name @@ -3040,8 +3037,10 @@ class _ColumnEntity(_QueryEntity): def __str__(self): return str(self.column) + log.class_logger(Query) + class QueryContext(object): multi_row_eager_loaders = False adapter = None @@ -3089,5 +3088,3 @@ class AliasOption(interfaces.MapperOption): else: alias = self.alias query._from_obj_alias = sql_util.ColumnAdapter(alias) - - diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py index 373fba785e..24ca32d9a7 100644 --- a/lib/sqlalchemy/orm/relationships.py +++ b/lib/sqlalchemy/orm/relationships.py @@ -22,6 +22,7 @@ from ..sql.util import ( from ..sql import operators, expression, visitors from .interfaces import MANYTOMANY, MANYTOONE, ONETOMANY + def remote(expr): """Annotate a portion of a primaryjoin expression with a 'remote' annotation. @@ -41,6 +42,7 @@ def remote(expr): return _annotate_columns(expression._clause_element_as_expr(expr), {"remote": True}) + def foreign(expr): """Annotate a portion of a primaryjoin expression with a 'foreign' annotation. @@ -73,6 +75,7 @@ def _annotate_columns(element, annotations): element = clone(element) return element + class JoinCondition(object): def __init__(self, parent_selectable, @@ -166,35 +169,33 @@ class JoinCondition(object): # general mapped table, which in the case of inheritance is # a join. try: + consider_as_foreign_keys = self.consider_as_foreign_keys or None if self.secondary is not None: if self.secondaryjoin is None: self.secondaryjoin = \ join_condition( - self.child_selectable, - self.secondary, - a_subset=self.child_local_selectable, - consider_as_foreign_keys=\ - self.consider_as_foreign_keys or None - ) + self.child_selectable, + self.secondary, + a_subset=self.child_local_selectable, + consider_as_foreign_keys=consider_as_foreign_keys + ) if self.primaryjoin is None: self.primaryjoin = \ join_condition( - self.parent_selectable, - self.secondary, - a_subset=self.parent_local_selectable, - consider_as_foreign_keys=\ - self.consider_as_foreign_keys or None - ) + self.parent_selectable, + self.secondary, + a_subset=self.parent_local_selectable, + consider_as_foreign_keys=consider_as_foreign_keys + ) else: if self.primaryjoin is None: self.primaryjoin = \ join_condition( - self.parent_selectable, - self.child_selectable, - a_subset=self.parent_local_selectable, - consider_as_foreign_keys=\ - self.consider_as_foreign_keys or None - ) + self.parent_selectable, + self.child_selectable, + a_subset=self.parent_local_selectable, + consider_as_foreign_keys=consider_as_foreign_keys + ) except sa_exc.NoForeignKeysError: if self.secondary is not None: raise sa_exc.NoForeignKeysError("Could not determine join " @@ -312,7 +313,7 @@ class JoinCondition(object): def _annotate_from_fk_list(self): def check_fk(col): if col in self.consider_as_foreign_keys: - return col._annotate({"foreign":True}) + return col._annotate({"foreign": True}) self.primaryjoin = visitors.replacement_traverse( self.primaryjoin, {}, @@ -330,6 +331,7 @@ class JoinCondition(object): secondarycols = util.column_set(self.secondary.c) else: secondarycols = set() + def is_foreign(a, b): if isinstance(a, schema.Column) and \ isinstance(b, schema.Column): @@ -355,21 +357,21 @@ class JoinCondition(object): if col is not None: if col.compare(binary.left): binary.left = binary.left._annotate( - {"foreign":True}) + {"foreign": True}) elif col.compare(binary.right): binary.right = binary.right._annotate( - {"foreign":True}) + {"foreign": True}) self.primaryjoin = visitors.cloned_traverse( self.primaryjoin, {}, - {"binary":visit_binary} + {"binary": visit_binary} ) if self.secondaryjoin is not None: self.secondaryjoin = visitors.cloned_traverse( self.secondaryjoin, {}, - {"binary":visit_binary} + {"binary": visit_binary} ) def _refers_to_parent_table(self): @@ -380,6 +382,7 @@ class JoinCondition(object): pt = self.parent_selectable mt = self.child_selectable result = [False] + def visit_binary(binary): c, f = binary.left, binary.right if ( @@ -394,7 +397,7 @@ class JoinCondition(object): visitors.traverse( self.primaryjoin, {}, - {"binary":visit_binary} + {"binary": visit_binary} ) return result[0] @@ -421,7 +424,7 @@ class JoinCondition(object): elif self._local_remote_pairs or self._remote_side: self._annotate_remote_from_args() elif self._refers_to_parent_table(): - self._annotate_selfref(lambda col:"foreign" in col._annotations) + self._annotate_selfref(lambda col: "foreign" in col._annotations) elif self._tables_overlap(): self._annotate_remote_with_overlap() else: @@ -434,7 +437,7 @@ class JoinCondition(object): """ def repl(element): if self.secondary.c.contains_column(element): - return element._annotate({"remote":True}) + return element._annotate({"remote": True}) self.primaryjoin = visitors.replacement_traverse( self.primaryjoin, {}, repl) self.secondaryjoin = visitors.replacement_traverse( @@ -451,17 +454,17 @@ class JoinCondition(object): isinstance(binary.right, expression.ColumnClause): # assume one to many - FKs are "remote" if fn(binary.left): - binary.left = binary.left._annotate({"remote":True}) + binary.left = binary.left._annotate({"remote": True}) if fn(binary.right) and \ not equated: binary.right = binary.right._annotate( - {"remote":True}) + {"remote": True}) else: self._warn_non_column_elements() self.primaryjoin = visitors.cloned_traverse( self.primaryjoin, {}, - {"binary":visit_binary}) + {"binary": visit_binary}) def _annotate_remote_from_args(self): """annotate 'remote' in primaryjoin, secondaryjoin @@ -481,11 +484,11 @@ class JoinCondition(object): remote_side = self._remote_side if self._refers_to_parent_table(): - self._annotate_selfref(lambda col:col in remote_side) + self._annotate_selfref(lambda col: col in remote_side) else: def repl(element): if element in remote_side: - return element._annotate({"remote":True}) + return element._annotate({"remote": True}) self.primaryjoin = visitors.replacement_traverse( self.primaryjoin, {}, repl) @@ -501,20 +504,21 @@ class JoinCondition(object): binary.right) binary.right, binary.left = proc_left_right(binary.right, binary.left) + def proc_left_right(left, right): if isinstance(left, expression.ColumnClause) and \ isinstance(right, expression.ColumnClause): if self.child_selectable.c.contains_column(right) and \ self.parent_selectable.c.contains_column(left): - right = right._annotate({"remote":True}) + right = right._annotate({"remote": True}) else: - self._warn_non_column_elements() + self._warn_non_column_elements() return left, right self.primaryjoin = visitors.cloned_traverse( self.primaryjoin, {}, - {"binary":visit_binary}) + {"binary": visit_binary}) def _annotate_remote_distinct_selectables(self): """annotate 'remote' in primaryjoin, secondaryjoin @@ -530,7 +534,7 @@ class JoinCondition(object): or self.child_local_selectable.c.\ contains_column(element) ): - return element._annotate({"remote":True}) + return element._annotate({"remote": True}) self.primaryjoin = visitors.replacement_traverse( self.primaryjoin, {}, repl) @@ -565,7 +569,7 @@ class JoinCondition(object): def locals_(elem): if "remote" not in elem._annotations and \ elem in local_side: - return elem._annotate({"local":True}) + return elem._annotate({"local": True}) self.primaryjoin = visitors.replacement_traverse( self.primaryjoin, {}, locals_ ) @@ -736,7 +740,8 @@ class JoinCondition(object): self.local_remote_pairs = self._deannotate_pairs(lrp) self.synchronize_pairs = self._deannotate_pairs(sync_pairs) - self.secondary_synchronize_pairs = self._deannotate_pairs(secondary_sync_pairs) + self.secondary_synchronize_pairs = \ + self._deannotate_pairs(secondary_sync_pairs) @util.memoized_property def remote_columns(self): @@ -780,7 +785,6 @@ class JoinCondition(object): if annotation.issubset(col._annotations) ]) - def join_targets(self, source_selectable, dest_selectable, aliased, @@ -801,7 +805,7 @@ class JoinCondition(object): # regardless of context. dest_selectable = _shallow_annotate( dest_selectable, - {'no_replacement_traverse':True}) + {'no_replacement_traverse': True}) primaryjoin, secondaryjoin, secondary = self.primaryjoin, \ self.secondaryjoin, self.secondary @@ -894,6 +898,3 @@ class JoinCondition(object): bind_to_col = dict((binds[col].key, col) for col in binds) return lazywhere, bind_to_col, equated_columns - - - diff --git a/lib/sqlalchemy/orm/scoping.py b/lib/sqlalchemy/orm/scoping.py index 3c4a0e5d86..e0ee620122 100644 --- a/lib/sqlalchemy/orm/scoping.py +++ b/lib/sqlalchemy/orm/scoping.py @@ -87,7 +87,8 @@ class scoped_session(object): self.registry.clear() def configure(self, **kwargs): - """reconfigure the :class:`.sessionmaker` used by this :class:`.scoped_session`. + """reconfigure the :class:`.sessionmaker` used by this + :class:`.scoped_session`. See :meth:`.sessionmaker.configure`. @@ -142,27 +143,34 @@ class scoped_session(object): ScopedSession = scoped_session """Old name for backwards compatibility.""" + def instrument(name): def do(self, *args, **kwargs): return getattr(self.registry(), name)(*args, **kwargs) return do + for meth in Session.public_methods: setattr(scoped_session, meth, instrument(meth)) + def makeprop(name): def set(self, attr): setattr(self.registry(), name, attr) + def get(self): return getattr(self.registry(), name) + return property(get, set) + for prop in ('bind', 'dirty', 'deleted', 'new', 'identity_map', - 'is_active', 'autoflush', 'no_autoflush'): + 'is_active', 'autoflush', 'no_autoflush'): setattr(scoped_session, prop, makeprop(prop)) + def clslevel(name): def do(cls, *args, **kwargs): return getattr(Session, name)(*args, **kwargs) return classmethod(do) + for prop in ('close_all', 'object_session', 'identity_key'): setattr(scoped_session, prop, clslevel(prop)) -