diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-03-16 14:50:55 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-03-16 14:50:55 -0400 |
commit | fb09877270cc976f4d0a7fe8d9e0d69430aadf71 (patch) | |
tree | 5b72b32a025a25d83dde5d8181ec4f8c2e3faf6e | |
parent | 56e38b8e4e6412fa3fc3beddd7fa30d6e6ddae2b (diff) | |
download | sqlalchemy-fb09877270cc976f4d0a7fe8d9e0d69430aadf71.tar.gz |
- Added support for the not-quite-yet-documented ``insert=True``
flag for :func:`.event.listen` to work with mapper / instance events.
-rw-r--r-- | doc/build/changelog/changelog_09.rst | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/events.py | 20 | ||||
-rw-r--r-- | test/orm/test_events.py | 54 |
3 files changed, 69 insertions, 11 deletions
diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index d082a29f6..87606c8d8 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -15,6 +15,12 @@ :version: 0.9.4 .. change:: + :tags: bug, orm + + Added support for the not-quite-yet-documented ``insert=True`` + flag for :func:`.event.listen` to work with mapper / instance events. + + .. change:: :tags: feature, sql Added support for literal rendering of boolean values, e.g. diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py index b68475230..078f4d12f 100644 --- a/lib/sqlalchemy/orm/events.py +++ b/lib/sqlalchemy/orm/events.py @@ -58,7 +58,7 @@ class InstrumentationEvents(event.Events): return None @classmethod - def _listen(cls, event_key, propagate=True): + def _listen(cls, event_key, propagate=True, **kw): target, identifier, fn = \ event_key.dispatch_target, event_key.identifier, event_key.fn @@ -79,7 +79,7 @@ class InstrumentationEvents(event.Events): event_key.\ with_dispatch_target(instrumentation._instrumentation_factory).\ - with_wrapper(listen).base_listen() + with_wrapper(listen).base_listen(**kw) @classmethod def _clear(cls): @@ -187,7 +187,7 @@ class InstanceEvents(event.Events): return None @classmethod - def _listen(cls, event_key, raw=False, propagate=False): + def _listen(cls, event_key, raw=False, propagate=False, **kw): target, identifier, fn = \ event_key.dispatch_target, event_key.identifier, event_key.fn @@ -196,7 +196,7 @@ class InstanceEvents(event.Events): return fn(state.obj(), *arg, **kw) event_key = event_key.with_wrapper(wrap) - event_key.base_listen(propagate=propagate) + event_key.base_listen(propagate=propagate, **kw) if propagate: for mgr in target.subclass_managers(True): @@ -347,7 +347,7 @@ class _EventsHold(event.RefCollection): _dispatch_target = None @classmethod - def _listen(cls, event_key, raw=False, propagate=False): + def _listen(cls, event_key, raw=False, propagate=False, **kw): target, identifier, fn = \ event_key.dispatch_target, event_key.identifier, event_key.fn @@ -369,7 +369,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) + listen(raw=raw, propagate=False, **kw) def remove(self, event_key): target, identifier, fn = \ @@ -503,8 +503,7 @@ class MapperEvents(event.Events): return target @classmethod - def _listen(cls, event_key, - raw=False, retval=False, propagate=False): + def _listen(cls, event_key, raw=False, retval=False, propagate=False, **kw): target, identifier, fn = \ event_key.dispatch_target, event_key.identifier, event_key.fn @@ -537,9 +536,10 @@ class MapperEvents(event.Events): if propagate: for mapper in target.self_and_descendants: - event_key.with_dispatch_target(mapper).base_listen(propagate=True) + event_key.with_dispatch_target(mapper).base_listen( + propagate=True, **kw) else: - event_key.base_listen() + event_key.base_listen(**kw) @classmethod def _clear(cls): diff --git a/test/orm/test_events.py b/test/orm/test_events.py index 5260a724a..9c9acc6eb 100644 --- a/test/orm/test_events.py +++ b/test/orm/test_events.py @@ -6,7 +6,7 @@ from sqlalchemy.testing.schema import Table, Column from sqlalchemy.orm import mapper, relationship, \ create_session, class_mapper, \ Mapper, column_property, \ - Session, sessionmaker, attributes + Session, sessionmaker, attributes, configure_mappers from sqlalchemy.orm.instrumentation import ClassManager from sqlalchemy.orm import instrumentation, events from sqlalchemy.testing import eq_ @@ -137,6 +137,58 @@ class MapperEventsTest(_RemoveListeners, _fixtures.FixtureTest): 'before_update', 'after_update', 'before_delete', 'after_delete']) + def test_insert_before_configured(self): + users, User = self.tables.users, self.classes.User + + mapper(User, users) + + canary = Mock() + + event.listen(mapper, "before_configured", canary.listen1) + event.listen(mapper, "before_configured", canary.listen2, insert=True) + event.listen(mapper, "before_configured", canary.listen3) + event.listen(mapper, "before_configured", canary.listen4, insert=True) + + configure_mappers() + + eq_( + canary.mock_calls, + [call.listen4(), call.listen2(), call.listen1(), call.listen3()] + ) + + def test_insert_flags(self): + users, User = self.tables.users, self.classes.User + + m = mapper(User, users) + + canary = Mock() + + arg = Mock() + + event.listen(m, "before_insert", canary.listen1, ) + event.listen(m, "before_insert", canary.listen2, insert=True) + event.listen(m, "before_insert", canary.listen3, propagate=True, insert=True) + event.listen(m, "load", canary.listen4) + event.listen(m, "load", canary.listen5, insert=True) + event.listen(m, "load", canary.listen6, propagate=True, insert=True) + + u1 = User() + state = u1._sa_instance_state + m.dispatch.before_insert(arg, arg, arg) + m.class_manager.dispatch.load(arg, arg) + eq_( + canary.mock_calls, + [ + call.listen3(arg, arg, arg.obj()), + call.listen2(arg, arg, arg.obj()), + call.listen1(arg, arg, arg.obj()), + call.listen6(arg.obj(), arg), + call.listen5(arg.obj(), arg), + call.listen4(arg.obj(), arg) + ] + ) + + def test_merge(self): users, User = self.tables.users, self.classes.User |