diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-08-14 19:58:34 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-08-14 19:58:34 -0400 |
commit | 59141d360e70d1a762719206e3cb0220b4c53fef (patch) | |
tree | 954d39dfa15a5c7b3970549dd77ec96a72444876 /lib/sqlalchemy/orm/events.py | |
parent | 688d799814fff2642926d3bce93b45965cf262da (diff) | |
download | sqlalchemy-59141d360e70d1a762719206e3cb0220b4c53fef.tar.gz |
- apply an import refactoring to the ORM as well
- rework the event system so that event modules load after their
targets, dependencies are reversed
- create an improved strategy lookup system for the ORM
- rework the ORM to have very few import cycles
- move out "importlater" to just util.dependency
- other tricks to cross-populate modules in as clear a way as possible
Diffstat (limited to 'lib/sqlalchemy/orm/events.py')
-rw-r--r-- | lib/sqlalchemy/orm/events.py | 94 |
1 files changed, 62 insertions, 32 deletions
diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py index b38b64f24..e2ca39137 100644 --- a/lib/sqlalchemy/orm/events.py +++ b/lib/sqlalchemy/orm/events.py @@ -8,10 +8,15 @@ """ from .. import event, exc, util -orm = util.importlater("sqlalchemy", "orm") +from .base import _mapper_or_none import inspect import weakref - +from . import interfaces +from . import mapperlib, instrumentation +from .session import Session, sessionmaker +from .scoping import scoped_session +from .attributes import QueryableAttribute +from . import mapper as mapperfunc class InstrumentationEvents(event.Events): """Events related to class instrumentation events. @@ -43,6 +48,8 @@ class InstrumentationEvents(event.Events): """ _target_class_doc = "SomeBaseClass" + _dispatch_target = instrumentation.InstrumentationFactory + @classmethod def _accept_with(cls, target): @@ -65,20 +72,20 @@ class InstrumentationEvents(event.Events): def remove(ref): key = event.registry._EventKey(None, identifier, listen, - orm.instrumentation._instrumentation_factory) - getattr(orm.instrumentation._instrumentation_factory.dispatch, + instrumentation._instrumentation_factory) + getattr(instrumentation._instrumentation_factory.dispatch, identifier).remove(key) target = weakref.ref(target.class_, remove) event_key.\ - with_dispatch_target(orm.instrumentation._instrumentation_factory).\ + with_dispatch_target(instrumentation._instrumentation_factory).\ with_wrapper(listen).base_listen() @classmethod def _clear(cls): super(InstrumentationEvents, cls)._clear() - orm.instrumentation._instrumentation_factory.dispatch._clear() + instrumentation._instrumentation_factory.dispatch._clear() def class_instrument(self, cls): """Called after the given class is instrumented. @@ -100,6 +107,7 @@ class InstrumentationEvents(event.Events): """Called when an attribute is instrumented.""" + class _InstrumentationEventsHold(object): """temporary marker object used to transfer from _accept_with() to _listen() on the InstrumentationEvents class. @@ -110,7 +118,6 @@ class _InstrumentationEventsHold(object): dispatch = event.dispatcher(InstrumentationEvents) - class InstanceEvents(event.Events): """Define events specific to object lifecycle. @@ -154,19 +161,26 @@ class InstanceEvents(event.Events): _target_class_doc = "SomeClass" + _dispatch_target = instrumentation.ClassManager + @classmethod - def _accept_with(cls, target): - if isinstance(target, orm.instrumentation.ClassManager): + def _new_classmanager_instance(cls, class_, classmanager): + _InstanceEventsHold.populate(class_, classmanager) + + @classmethod + @util.dependencies("sqlalchemy.orm") + def _accept_with(cls, orm, target): + if isinstance(target, instrumentation.ClassManager): return target - elif isinstance(target, orm.Mapper): + elif isinstance(target, mapperlib.Mapper): return target.class_manager elif target is orm.mapper: - return orm.instrumentation.ClassManager + return instrumentation.ClassManager elif isinstance(target, type): - if issubclass(target, orm.Mapper): - return orm.instrumentation.ClassManager + if issubclass(target, mapperlib.Mapper): + return instrumentation.ClassManager else: - manager = orm.instrumentation.manager_of_class(target) + manager = instrumentation.manager_of_class(target) if manager: return manager else: @@ -334,6 +348,8 @@ class _EventsHold(event.RefCollection): cls.all_holds.clear() class HoldEvents(object): + _dispatch_target = None + @classmethod def _listen(cls, event_key, raw=False, propagate=False): target, identifier, fn = \ @@ -384,7 +400,7 @@ class _InstanceEventsHold(_EventsHold): all_holds = weakref.WeakKeyDictionary() def resolve(self, class_): - return orm.instrumentation.manager_of_class(class_) + return instrumentation.manager_of_class(class_) class HoldInstanceEvents(_EventsHold.HoldEvents, InstanceEvents): pass @@ -464,16 +480,22 @@ class MapperEvents(event.Events): """ _target_class_doc = "SomeClass" + _dispatch_target = mapperlib.Mapper @classmethod - def _accept_with(cls, target): + def _new_mapper_instance(cls, class_, mapper): + _MapperEventsHold.populate(class_, mapper) + + @classmethod + @util.dependencies("sqlalchemy.orm") + def _accept_with(cls, orm, target): if target is orm.mapper: - return orm.Mapper + return mapperlib.Mapper elif isinstance(target, type): - if issubclass(target, orm.Mapper): + if issubclass(target, mapperlib.Mapper): return target else: - mapper = orm.util._mapper_or_none(target) + mapper = _mapper_or_none(target) if mapper is not None: return mapper else: @@ -504,7 +526,7 @@ class MapperEvents(event.Events): arg[target_index] = arg[target_index].obj() if not retval: wrapped_fn(*arg, **kw) - return orm.interfaces.EXT_CONTINUE + return interfaces.EXT_CONTINUE else: return wrapped_fn(*arg, **kw) fn = wrap @@ -1066,12 +1088,11 @@ class MapperEvents(event.Events): """ - class _MapperEventsHold(_EventsHold): all_holds = weakref.WeakKeyDictionary() def resolve(self, class_): - return orm.util._mapper_or_none(class_) + return _mapper_or_none(class_) class HoldMapperEvents(_EventsHold.HoldEvents, MapperEvents): pass @@ -1106,29 +1127,31 @@ class SessionEvents(event.Events): _target_class_doc = "SomeSessionOrFactory" + _dispatch_target = Session + @classmethod def _accept_with(cls, target): - if isinstance(target, orm.scoped_session): + if isinstance(target, scoped_session): target = target.session_factory - if not isinstance(target, orm.sessionmaker) and \ + if not isinstance(target, sessionmaker) and \ ( not isinstance(target, type) or - not issubclass(target, orm.Session) + not issubclass(target, Session) ): raise exc.ArgumentError( "Session event listen on a scoped_session " "requires that its creation callable " "is associated with the Session class.") - if isinstance(target, orm.sessionmaker): + if isinstance(target, sessionmaker): return target.class_ elif isinstance(target, type): - if issubclass(target, orm.scoped_session): - return orm.Session - elif issubclass(target, orm.Session): + if issubclass(target, scoped_session): + return Session + elif issubclass(target, Session): return target - elif isinstance(target, orm.Session): + elif isinstance(target, Session): return target else: return None @@ -1511,11 +1534,17 @@ class AttributeEvents(event.Events): """ _target_class_doc = "SomeClass.some_attribute" + _dispatch_target = QueryableAttribute + + @staticmethod + def _set_dispatch(cls, dispatch_cls): + event.Events._set_dispatch(cls, dispatch_cls) + dispatch_cls._active_history = False @classmethod def _accept_with(cls, target): # TODO: coverage - if isinstance(target, orm.interfaces.MapperProperty): + if isinstance(target, interfaces.MapperProperty): return getattr(target.parent.class_, target.key) else: return target @@ -1548,7 +1577,7 @@ class AttributeEvents(event.Events): event_key.base_listen(propagate=propagate) if propagate: - manager = orm.instrumentation.manager_of_class(target.class_) + manager = instrumentation.manager_of_class(target.class_) for mgr in manager.subclass_managers(True): event_key.with_dispatch_target(mgr[target.key]).base_listen(propagate=True) @@ -1625,3 +1654,4 @@ class AttributeEvents(event.Events): the given value, or a new effective value, should be returned. """ + |