summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-07-14 11:51:11 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-07-14 11:51:11 -0400
commit3eaedb38d306095c683900e7e4625be7f7bc91d2 (patch)
tree1bb7f5ed594ff7c199761bc6ad8e87248c6070cc /lib/sqlalchemy
parent0dde519fe172cf3ac7241cbb1ab93b35beaf6d6a (diff)
downloadsqlalchemy-3eaedb38d306095c683900e7e4625be7f7bc91d2.tar.gz
- move load_scalar_attributes out to loading.py
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/ext/instrumentation.py37
-rw-r--r--lib/sqlalchemy/orm/loading.py65
-rw-r--r--lib/sqlalchemy/orm/mapper.py107
-rw-r--r--lib/sqlalchemy/orm/state.py8
4 files changed, 113 insertions, 104 deletions
diff --git a/lib/sqlalchemy/ext/instrumentation.py b/lib/sqlalchemy/ext/instrumentation.py
index c42cf6ec9..f840ad066 100644
--- a/lib/sqlalchemy/ext/instrumentation.py
+++ b/lib/sqlalchemy/ext/instrumentation.py
@@ -2,7 +2,7 @@
The :mod:`sqlalchemy.ext.instrumentation` package provides for alternate
systems of class instrumentation within the ORM. Class instrumentation
-refers to how the ORM places attributes on the class which maintain
+refers to how the ORM places attributes on the class which maintain
data and track changes to that data, as well as event hooks installed
on the class.
@@ -11,24 +11,24 @@ on the class.
with other object management packages, which already perform
their own instrumentation. It is not intended for general use.
-For examples of how the instrumentation extension is used,
+For examples of how the instrumentation extension is used,
see the example :ref:`examples_instrumentation`.
.. versionchanged:: 0.8
- The :mod:`sqlalchemy.orm.instrumentation` was split out so
+ The :mod:`sqlalchemy.orm.instrumentation` was split out so
that all functionality having to do with non-standard
instrumentation was moved out to :mod:`sqlalchemy.ext.instrumentation`.
When imported, the module installs itself within
:mod:`sqlalchemy.orm.instrumentation` so that it
- takes effect, including recognition of
- ``__sa_instrumentation_manager__`` on mapped classes, as
- well :attr:`.instrumentation_finders`
+ takes effect, including recognition of
+ ``__sa_instrumentation_manager__`` on mapped classes, as
+ well :attr:`.instrumentation_finders`
being used to determine class instrumentation resolution.
-
+
"""
from ..orm import instrumentation as orm_instrumentation
from ..orm.instrumentation import (
- ClassManager, InstrumentationFactory, _default_state_getter,
+ ClassManager, InstrumentationFactory, _default_state_getter,
_default_dict_getter, _default_manager_getter
)
from ..orm import attributes, collections
@@ -66,9 +66,10 @@ def find_native_user_instrumentation_hook(cls):
return getattr(cls, INSTRUMENTATION_MANAGER, None)
instrumentation_finders = [find_native_user_instrumentation_hook]
-"""An extensible sequence of callables which return instrumentation implementations
+"""An extensible sequence of callables which return instrumentation
+implementations
-When a class is registered, each callable will be passed a class object.
+When a class is registered, each callable will be passed a class object.
If None is returned, the
next finder in the sequence is consulted. Otherwise the return must be an
instrumentation factory that follows the same guidelines as
@@ -82,9 +83,9 @@ ClassManager instrumentation is used.
class ExtendedInstrumentationRegistry(InstrumentationFactory):
"""Extends :class:`.InstrumentationFactory` with additional
- bookkeeping, to accommodate multiple types of
+ bookkeeping, to accommodate multiple types of
class managers.
-
+
"""
_manager_finders = weakref.WeakKeyDictionary()
_state_finders = weakref.WeakKeyDictionary()
@@ -116,7 +117,7 @@ class ExtendedInstrumentationRegistry(InstrumentationFactory):
if factory != ClassManager and not self._extended:
# somebody invoked a custom ClassManager.
- # reinstall global "getter" functions with the more
+ # reinstall global "getter" functions with the more
# expensive ones.
self._extended = True
_install_instrumented_lookups()
@@ -196,9 +197,9 @@ class InstrumentationManager(object):
.. versionchanged:: 0.8
:class:`.InstrumentationManager` was moved from
- :mod:`sqlalchemy.orm.instrumentation` to
- :mod:`sqlalchemy.ext.instrumentation`.
-
+ :mod:`sqlalchemy.orm.instrumentation` to
+ :mod:`sqlalchemy.ext.instrumentation`.
+
"""
# r4361 added a mandatory (cls) constructor to this interface.
@@ -307,7 +308,7 @@ class _ClassInstrumentationAdapter(ClassManager):
if delegate:
return delegate(key, state, factory)
else:
- return ClassManager.initialize_collection(self, key,
+ return ClassManager.initialize_collection(self, key,
state, factory)
def new_instance(self, state=None):
@@ -340,7 +341,7 @@ class _ClassInstrumentationAdapter(ClassManager):
def has_state(self, instance):
try:
- state = self._get_state(instance)
+ self._get_state(instance)
except orm_exc.NO_STATE:
return False
else:
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 987d47cea..41b82d8d1 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -18,6 +18,8 @@ from . import attributes, exc as orm_exc, state as statelib
from .interfaces import EXT_CONTINUE
from ..sql import util as sql_util
from .util import _none_set, state_str
+from .. import exc as sa_exc
+sessionlib = util.importlater("sqlalchemy.orm", "session")
_new_runid = util.counter()
@@ -534,3 +536,66 @@ def _configure_subclass_mapper(mapper, context, path, adapter):
adapter,
polymorphic_from=mapper)
return configure_subclass_mapper
+
+def load_scalar_attributes(mapper, state, attribute_names):
+ """initiate a column-based attribute refresh operation."""
+
+ #assert mapper is _state_mapper(state)
+ session = sessionlib._state_session(state)
+ if not session:
+ raise orm_exc.DetachedInstanceError(
+ "Instance %s is not bound to a Session; "
+ "attribute refresh operation cannot proceed" %
+ (state_str(state)))
+
+ has_key = bool(state.key)
+
+ result = False
+
+ if mapper.inherits and not mapper.concrete:
+ statement = mapper._optimized_get_statement(state, attribute_names)
+ if statement is not None:
+ result = load_on_ident(
+ session.query(mapper).from_statement(statement),
+ None,
+ only_load_props=attribute_names,
+ refresh_state=state
+ )
+
+ if result is False:
+ if has_key:
+ identity_key = state.key
+ else:
+ # this codepath is rare - only valid when inside a flush, and the
+ # object is becoming persistent but hasn't yet been assigned
+ # an identity_key.
+ # check here to ensure we have the attrs we need.
+ pk_attrs = [mapper._columntoproperty[col].key
+ for col in mapper.primary_key]
+ if state.expired_attributes.intersection(pk_attrs):
+ raise sa_exc.InvalidRequestError(
+ "Instance %s cannot be refreshed - it's not "
+ " persistent and does not "
+ "contain a full primary key." % state_str(state))
+ identity_key = mapper._identity_key_from_state(state)
+
+ if (_none_set.issubset(identity_key) and \
+ not mapper.allow_partial_pks) or \
+ _none_set.issuperset(identity_key):
+ util.warn("Instance %s to be refreshed doesn't "
+ "contain a full primary key - can't be refreshed "
+ "(and shouldn't be expired, either)."
+ % state_str(state))
+ return
+
+ result = load_on_ident(
+ session.query(mapper),
+ identity_key,
+ refresh_state=state,
+ only_load_props=attribute_names)
+
+ # if instance is pending, a refresh operation
+ # 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 dceccf70f..333956407 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -16,22 +16,19 @@ available in :class:`~sqlalchemy.orm.`.
from __future__ import absolute_import
import types
import weakref
-import operator
-from itertools import chain, groupby
+from itertools import chain
from collections import deque
from .. import sql, util, log, exc as sa_exc, event, schema
from ..sql import expression, visitors, operators, util as sql_util
-from . import instrumentation, attributes, sync, \
+from . import instrumentation, attributes, \
exc as orm_exc, unitofwork, events, loading
-from .interfaces import MapperProperty, EXT_CONTINUE, \
- PropComparator
+from .interfaces import MapperProperty
from .util import _INSTRUMENTOR, _class_to_mapper, \
- _state_mapper, class_mapper, instance_str, state_str,\
- PathRegistry, _none_set
+ _state_mapper, class_mapper, \
+ PathRegistry
import sys
-sessionlib = util.importlater("sqlalchemy.orm", "session")
properties = util.importlater("sqlalchemy.orm", "properties")
descriptor_props = util.importlater("sqlalchemy.orm", "descriptor_props")
@@ -68,17 +65,17 @@ class Mapper(object):
def __init__(self,
class_,
local_table,
- properties = None,
- primary_key = None,
- non_primary = False,
- inherits = None,
- inherit_condition = None,
- inherit_foreign_keys = None,
- extension = None,
- order_by = False,
- always_refresh = False,
- version_id_col = None,
- version_id_generator = None,
+ properties=None,
+ primary_key=None,
+ non_primary=False,
+ inherits=None,
+ inherit_condition=None,
+ inherit_foreign_keys=None,
+ extension=None,
+ order_by=False,
+ always_refresh=False,
+ version_id_col=None,
+ version_id_generator=None,
polymorphic_on=None,
_polymorphic_map=None,
polymorphic_identity=None,
@@ -182,8 +179,8 @@ class Mapper(object):
self.configured = False
# prevent this mapper from being constructed
- # while a configure_mappers() is occurring (and defer a configure_mappers()
- # until construction succeeds)
+ # while a configure_mappers() is occurring (and defer a
+ # configure_mappers() until construction succeeds)
_COMPILE_MUTEX.acquire()
try:
self._configure_inheritance()
@@ -659,7 +656,8 @@ class Mapper(object):
self.class_manager = manager
manager.mapper = self
- manager.deferred_scalar_loader = self._load_scalar_attributes
+ manager.deferred_scalar_loader = util.partial(
+ loading.load_scalar_attributes, self)
# The remaining members can be added by any mapper,
# e_name None or not.
@@ -676,10 +674,11 @@ class Mapper(object):
self._reconstructor = method
event.listen(manager, 'load', _event_on_load, raw=True)
elif hasattr(method, '__sa_validators__'):
- include_removes = getattr(method, "__sa_include_removes__", False)
+ include_removes = getattr(method,
+ "__sa_include_removes__", False)
for name in method.__sa_validators__:
self.validators = self.validators.union(
- {name : (method, include_removes)}
+ {name: (method, include_removes)}
)
manager.info[_INSTRUMENTOR] = self
@@ -1678,65 +1677,6 @@ class Mapper(object):
return state.manager[prop.key].impl.\
get_committed_value(state, dict_, passive=passive)
- def _load_scalar_attributes(self, state, attribute_names):
- """initiate a column-based attribute refresh operation."""
-
- #assert mapper is _state_mapper(state)
- session = sessionlib._state_session(state)
- if not session:
- raise orm_exc.DetachedInstanceError(
- "Instance %s is not bound to a Session; "
- "attribute refresh operation cannot proceed" %
- (state_str(state)))
-
- has_key = bool(state.key)
-
- result = False
-
- if self.inherits and not self.concrete:
- statement = self._optimized_get_statement(state, attribute_names)
- if statement is not None:
- result = loading.load_on_ident(
- session.query(self).from_statement(statement),
- None,
- only_load_props=attribute_names,
- refresh_state=state
- )
-
- if result is False:
- if has_key:
- identity_key = state.key
- else:
- # this codepath is rare - only valid when inside a flush, and the
- # object is becoming persistent but hasn't yet been assigned an identity_key.
- # check here to ensure we have the attrs we need.
- pk_attrs = [self._columntoproperty[col].key
- for col in self.primary_key]
- if state.expired_attributes.intersection(pk_attrs):
- raise sa_exc.InvalidRequestError("Instance %s cannot be refreshed - it's not "
- " persistent and does not "
- "contain a full primary key." % state_str(state))
- identity_key = self._identity_key_from_state(state)
-
- if (_none_set.issubset(identity_key) and \
- not self.allow_partial_pks) or \
- _none_set.issuperset(identity_key):
- util.warn("Instance %s to be refreshed doesn't "
- "contain a full primary key - can't be refreshed "
- "(and shouldn't be expired, either)."
- % state_str(state))
- return
-
- result = loading.load_on_ident(
- session.query(self),
- identity_key,
- refresh_state=state,
- only_load_props=attribute_names)
-
- # if instance is pending, a refresh operation
- # may not complete (even if PK attributes are assigned)
- if has_key and result is None:
- raise orm_exc.ObjectDeletedError(state)
def _optimized_get_statement(self, state, attribute_names):
"""assemble a WHERE clause which retrieves a given state by primary
@@ -2052,6 +1992,7 @@ def validates(*names, **kw):
"""
include_removes = kw.pop('include_removes', False)
+
def wrap(fn):
fn.__sa_validators__ = names
fn.__sa_include_removes__ = include_removes
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 557eeb133..ea0e89caf 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -13,7 +13,7 @@ defines a large part of the ORM's interactivity.
import weakref
from .. import util
-from . import exc as orm_exc, attributes,util as orm_util
+from . import exc as orm_exc, attributes, util as orm_util
from .attributes import (
PASSIVE_NO_RESULT,
SQL_OK, NEVER_SET, ATTR_WAS_SET, NO_VALUE,\
@@ -198,8 +198,10 @@ class InstanceState(object):
if manager is None:
raise orm_exc.UnmappedInstanceError(
inst,
- "Cannot deserialize object of type %r - no mapper() has"
- " been configured for this class within the current Python process!" %
+ "Cannot deserialize object of type %r - "
+ "no mapper() has "
+ "been configured for this class within the current "
+ "Python process!" %
self.class_)
elif manager.is_mapped and not manager.mapper.configured:
mapperlib.configure_mappers()