diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2018-12-23 15:44:37 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2018-12-23 15:44:37 +0000 |
| commit | d27023a30dc24c2fd5941025b36d051da3e596bd (patch) | |
| tree | 794493fa576757f67a2c218e2899a1a3a396afd7 /lib | |
| parent | 504432ed575fe48d378f6bc461e75eaa1ae48a82 (diff) | |
| parent | 65ea042302693492cbaee96dfed5e9337e0d96a4 (diff) | |
| download | sqlalchemy-d27023a30dc24c2fd5941025b36d051da3e596bd.tar.gz | |
Merge "Add before_mapper_configured event"
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/event/registry.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/__init__.py | 1 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/base.py | 1 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/events.py | 71 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 3 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 19 |
6 files changed, 86 insertions, 11 deletions
diff --git a/lib/sqlalchemy/event/registry.py b/lib/sqlalchemy/event/registry.py index 758230487..8d4bada0b 100644 --- a/lib/sqlalchemy/event/registry.py +++ b/lib/sqlalchemy/event/registry.py @@ -225,7 +225,7 @@ class _EventKey(object): return self._key in _key_to_collection def base_listen(self, propagate=False, insert=False, - named=False): + named=False, retval=None): target, identifier, fn = \ self.dispatch_target, self.identifier, self._listen_fn diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index f279c9b40..1784ea21f 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -25,6 +25,7 @@ from .mapper import ( from .interfaces import ( EXT_CONTINUE, EXT_STOP, + EXT_SKIP, PropComparator, ) from .deprecated_interfaces import ( diff --git a/lib/sqlalchemy/orm/base.py b/lib/sqlalchemy/orm/base.py index 62b4f59a9..deddaa5a4 100644 --- a/lib/sqlalchemy/orm/base.py +++ b/lib/sqlalchemy/orm/base.py @@ -149,6 +149,7 @@ _INSTRUMENTOR = ('mapper', 'instrumentor') EXT_CONTINUE = util.symbol('EXT_CONTINUE') EXT_STOP = util.symbol('EXT_STOP') +EXT_SKIP = util.symbol('EXT_SKIP') ONETOMANY = util.symbol( 'ONETOMANY', diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py index f27849e15..c414f548e 100644 --- a/lib/sqlalchemy/orm/events.py +++ b/lib/sqlalchemy/orm/events.py @@ -437,7 +437,9 @@ class _EventsHold(event.RefCollection): _dispatch_target = None @classmethod - def _listen(cls, event_key, raw=False, propagate=False, **kw): + def _listen( + cls, event_key, raw=False, propagate=False, + retval=False, **kw): target, identifier, fn = \ event_key.dispatch_target, event_key.identifier, event_key.fn @@ -447,7 +449,7 @@ class _EventsHold(event.RefCollection): collection = target.all_holds[target.class_] = {} event.registry._stored_in_collection(event_key, target) - collection[event_key._key] = (event_key, raw, propagate) + collection[event_key._key] = (event_key, raw, propagate, retval) if propagate: stack = list(target.class_.__subclasses__()) @@ -459,7 +461,7 @@ class _EventsHold(event.RefCollection): # we are already going through __subclasses__() # so leave generic propagate flag False event_key.with_dispatch_target(subject).\ - listen(raw=raw, propagate=False, **kw) + listen(raw=raw, propagate=False, retval=retval, **kw) def remove(self, event_key): target, identifier, fn = \ @@ -474,7 +476,7 @@ class _EventsHold(event.RefCollection): for subclass in class_.__mro__: if subclass in cls.all_holds: collection = cls.all_holds[subclass] - for event_key, raw, propagate in collection.values(): + for event_key, raw, propagate, retval in collection.values(): if propagate or subclass is class_: # since we can't be sure in what order different # classes in a hierarchy are triggered with @@ -482,7 +484,7 @@ class _EventsHold(event.RefCollection): # assignment, instead of using the generic propagate # flag. event_key.with_dispatch_target(subject).\ - listen(raw=raw, propagate=False) + listen(raw=raw, propagate=False, retval=retval) class _InstanceEventsHold(_EventsHold): @@ -659,6 +661,54 @@ class MapperEvents(event.Events): """ + def before_mapper_configured(self, mapper, class_): + """Called right before a specific mapper is to be configured. + + This event is intended to allow a specific mapper to be skipped during + the configure step, by returning the :attr:`.orm.interfaces.EXT_SKIP` + symbol which indicates to the :func:`.configure_mappers` call that this + particular mapper (or hierarchy of mappers, if ``propagate=True`` is + used) should be skipped in the current configuration run. When one or + more mappers are skipped, the he "new mappers" flag will remain set, + meaning the :func:`.configure_mappers` function will continue to be + called when mappers are used, to continue to try to configure all + available mappers. + + In comparison to the other configure-level events, + :meth:`.MapperEvents.before_configured`, + :meth:`.MapperEvents.after_configured`, and + :meth:`.MapperEvents.mapper_configured`, the + :meth;`.MapperEvents.before_mapper_configured` event provides for a + meaningful return value when it is registered with the ``retval=True`` + parameter. + + .. versionadded:: 1.3 + + e.g.:: + + from sqlalchemy.orm import EXT_SKIP + + Base = declarative_base() + + DontConfigureBase = declarative_base() + + @event.listens_for( + DontConfigureBase, + "before_mapper_configured", retval=True, propagate=True) + def dont_configure(mapper, cls): + return EXT_SKIP + + + .. seealso:: + + :meth:`.MapperEvents.before_configured` + + :meth:`.MapperEvents.after_configured` + + :meth:`.MapperEvents.mapper_configured` + + """ + def mapper_configured(self, mapper, class_): r"""Called when a specific mapper has completed its own configuration within the scope of the :func:`.configure_mappers` call. @@ -708,6 +758,8 @@ class MapperEvents(event.Events): :meth:`.MapperEvents.after_configured` + :meth:`.MapperEvents.before_mapper_configured` + """ # TODO: need coverage for this event @@ -734,8 +786,9 @@ class MapperEvents(event.Events): Contrast this event to :meth:`.MapperEvents.after_configured`, which is invoked after the series of mappers has been configured, - as well as :meth:`.MapperEvents.mapper_configured`, which is invoked - on a per-mapper basis as each one is configured to the extent possible. + as well as :meth:`.MapperEvents.before_mapper_configured` + and :meth:`.MapperEvents.mapper_configured`, which are both invoked + on a per-mapper basis. Theoretically this event is called once per application, but is actually called any time new mappers @@ -757,6 +810,8 @@ class MapperEvents(event.Events): .. seealso:: + :meth:`.MapperEvents.before_mapper_configured` + :meth:`.MapperEvents.mapper_configured` :meth:`.MapperEvents.after_configured` @@ -808,6 +863,8 @@ class MapperEvents(event.Events): .. seealso:: + :meth:`.MapperEvents.before_mapper_configured` + :meth:`.MapperEvents.mapper_configured` :meth:`.MapperEvents.before_configured` diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 95291377b..80d0a6303 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -23,7 +23,7 @@ from __future__ import absolute_import from .. import util from ..sql import operators from .base import (ONETOMANY, MANYTOONE, MANYTOMANY, - EXT_CONTINUE, EXT_STOP, NOT_EXTENSION) + EXT_CONTINUE, EXT_STOP, EXT_SKIP, NOT_EXTENSION) from .base import InspectionAttr, InspectionAttrInfo, _MappedAttribute import collections from .. import inspect @@ -36,6 +36,7 @@ __all__ = ( 'AttributeExtension', 'EXT_CONTINUE', 'EXT_STOP', + 'EXT_SKIP', 'ONETOMANY', 'MANYTOMANY', 'MANYTOONE', diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index f2b326359..fa731f729 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -26,7 +26,9 @@ from ..sql import expression, visitors, operators, util as sql_util from . import instrumentation, attributes, exc as orm_exc, loading from . import properties from . import util as orm_util -from .interfaces import MapperProperty, InspectionAttr, _MappedAttribute +from .interfaces import MapperProperty, InspectionAttr, _MappedAttribute, \ + EXT_SKIP + from .base import _class_to_mapper, _state_mapper, class_mapper, \ state_str, _INSTRUMENTOR @@ -3014,6 +3016,8 @@ def configure_mappers(): if not Mapper._new_mappers: return + has_skip = False + Mapper.dispatch._for_class(Mapper).before_configured() # initialize properties on all mappers # note that _mapper_registry is unordered, which @@ -3021,6 +3025,15 @@ def configure_mappers(): # the order of mapper compilation for mapper in list(_mapper_registry): + run_configure = None + for fn in mapper.dispatch.before_mapper_configured: + run_configure = fn(mapper, mapper.class_) + if run_configure is EXT_SKIP: + has_skip = True + break + if run_configure is EXT_SKIP: + continue + if getattr(mapper, '_configure_failed', False): e = sa_exc.InvalidRequestError( "One or more mappers failed to initialize - " @@ -3030,6 +3043,7 @@ def configure_mappers(): % (mapper, mapper._configure_failed)) e._configure_failed = mapper._configure_failed raise e + if not mapper.configured: try: mapper._post_configure_properties() @@ -3042,7 +3056,8 @@ def configure_mappers(): mapper._configure_failed = exc raise - Mapper._new_mappers = False + if not has_skip: + Mapper._new_mappers = False finally: _already_compiling = False finally: |
