summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2018-02-19 18:19:01 -0500
committerGerrit Code Review <gerrit@ci.zzzcomputing.com>2018-02-19 18:19:01 -0500
commit191dd0055c05f51fa985d4e24f107faa58743022 (patch)
tree1d928bbf065922644d3fe1536f1fa35369dcc5bc
parent5cb5b8b5f7a5b4488fb5df82c53861d565537405 (diff)
parent1393eac44c49299e733a5181f387ba140aaa3e44 (diff)
downloadsqlalchemy-191dd0055c05f51fa985d4e24f107faa58743022.tar.gz
Merge "Implement remove() for _empty_collection"
-rw-r--r--doc/build/changelog/unreleased_12/4190.rst9
-rw-r--r--lib/sqlalchemy/event/attr.py3
-rw-r--r--test/base/test_events.py58
-rw-r--r--test/engine/test_execute.py9
4 files changed, 79 insertions, 0 deletions
diff --git a/doc/build/changelog/unreleased_12/4190.rst b/doc/build/changelog/unreleased_12/4190.rst
new file mode 100644
index 000000000..0969ea3a2
--- /dev/null
+++ b/doc/build/changelog/unreleased_12/4190.rst
@@ -0,0 +1,9 @@
+.. change::
+ :tags: bug, engine
+ :tickets: 4190
+
+ Fixed regression caused in 1.2.3 due to fix from :ticket:`4181` where
+ the changes to the event system involving :class:`.Engine` and
+ :class:`.OptionEngine` did not accommodate for event removals, which
+ would raise an ``AttributeError`` when invoked at the class
+ level.
diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py
index efa8fab42..c33ec82ff 100644
--- a/lib/sqlalchemy/event/attr.py
+++ b/lib/sqlalchemy/event/attr.py
@@ -54,6 +54,9 @@ class _empty_collection(object):
def extend(self, other):
pass
+ def remove(self, element):
+ pass
+
def __iter__(self):
return iter([])
diff --git a/test/base/test_events.py b/test/base/test_events.py
index b502a0348..288c6091f 100644
--- a/test/base/test_events.py
+++ b/test/base/test_events.py
@@ -1033,6 +1033,64 @@ class JoinTest(fixtures.TestBase):
)
+class DisableClsPropagateTest(fixtures.TestBase):
+
+ def setUp(self):
+ class TargetEvents(event.Events):
+ def event_one(self, target, arg):
+ pass
+
+ class BaseTarget(object):
+ dispatch = event.dispatcher(TargetEvents)
+
+ class SubTarget(BaseTarget):
+ _sa_propagate_class_events = False
+
+ def __init__(self, parent):
+ self.dispatch = self.dispatch._join(parent.dispatch)
+
+ self.BaseTarget = BaseTarget
+ self.SubTarget = SubTarget
+
+ def tearDown(self):
+ for cls in (self.SubTarget, self.BaseTarget):
+ if 'dispatch' in cls.__dict__:
+ event.base._remove_dispatcher(cls.__dict__['dispatch'].events)
+
+ def test_listen_invoke_clslevel(self):
+ canary = Mock()
+
+ event.listen(self.BaseTarget, "event_one", canary)
+
+ s1 = self.SubTarget(self.BaseTarget())
+ s1.dispatch.event_one()
+
+ eq_(canary.mock_calls, [call.event_one()])
+
+ def test_insert_invoke_clslevel(self):
+ canary = Mock()
+
+ event.listen(self.BaseTarget, "event_one", canary, insert=True)
+
+ s1 = self.SubTarget(self.BaseTarget())
+ s1.dispatch.event_one()
+
+ eq_(canary.mock_calls, [call.event_one()])
+
+ def test_remove_invoke_clslevel(self):
+ canary = Mock()
+
+ event.listen(self.BaseTarget, "event_one", canary)
+
+ s1 = self.SubTarget(self.BaseTarget())
+
+ event.remove(self.BaseTarget, "event_one", canary)
+
+ s1.dispatch.event_one()
+
+ eq_(canary.mock_calls, [])
+
+
class RemovalTest(fixtures.TestBase):
def _fixture(self):
class TargetEvents(event.Events):
diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py
index e0727f770..2d602fa12 100644
--- a/test/engine/test_execute.py
+++ b/test/engine/test_execute.py
@@ -1399,6 +1399,15 @@ class EngineEventsTest(fixtures.TestBase):
eq_(canary, ["l1", "l2", "l3", "l4", "l1", "l2", "l3"])
+ canary[:] = []
+
+ event.remove(Engine, "before_execute", l1)
+ event.remove(eng1, "before_execute", l4)
+ event.remove(eng, "before_execute", l3)
+
+ eng1.execute(select([1])).close()
+ eq_(canary, ["l2"])
+
@testing.requires.ad_hoc_engines
def test_cant_listen_to_option_engine(self):
from sqlalchemy.engine import base