summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/event/attr.py
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2018-02-07 20:58:47 -0500
committerGerrit Code Review <gerrit@ci.zzzcomputing.com>2018-02-07 20:58:47 -0500
commitba957f84d333918ca34d562b407cc6d65bccbccb (patch)
tree4ec38c96ba774bdc6b8ef91ed55ae81c954b21fe /lib/sqlalchemy/event/attr.py
parent9f657fee5ba66820b9cd6b80653332c07eec0451 (diff)
parent4065352c7e9779cfeae34f01073ef6c43aeae488 (diff)
downloadsqlalchemy-ba957f84d333918ca34d562b407cc6d65bccbccb.tar.gz
Merge "Add flag for class-level disallow of events, apply to OptionEngine"
Diffstat (limited to 'lib/sqlalchemy/event/attr.py')
-rw-r--r--lib/sqlalchemy/event/attr.py35
1 files changed, 30 insertions, 5 deletions
diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py
index 1068257cb..efa8fab42 100644
--- a/lib/sqlalchemy/event/attr.py
+++ b/lib/sqlalchemy/event/attr.py
@@ -30,7 +30,7 @@ as well as support for subclass propagation (e.g. events assigned to
"""
from __future__ import absolute_import, with_statement
-
+from .. import exc
from .. import util
from ..util import threading
from . import registry
@@ -47,6 +47,20 @@ class RefCollection(util.MemoizedSlots):
return weakref.ref(self, registry._collection_gced)
+class _empty_collection(object):
+ def append(self, element):
+ pass
+
+ def extend(self, other):
+ pass
+
+ def __iter__(self):
+ return iter([])
+
+ def clear(self):
+ pass
+
+
class _ClsLevelDispatch(RefCollection):
"""Class-level events on :class:`._Dispatch` classes."""
@@ -91,6 +105,9 @@ class _ClsLevelDispatch(RefCollection):
target = event_key.dispatch_target
assert isinstance(target, type), \
"Class-level Event targets must be classes."
+ if not getattr(target, '_sa_propagate_class_events', True):
+ raise exc.InvalidRequestError(
+ "Can't assign an event directly to the %s class" % target)
stack = [target]
while stack:
cls = stack.pop(0)
@@ -99,7 +116,7 @@ class _ClsLevelDispatch(RefCollection):
self.update_subclass(cls)
else:
if cls not in self._clslevel:
- self._clslevel[cls] = collections.deque()
+ self._assign_cls_collection(cls)
self._clslevel[cls].appendleft(event_key._listen_fn)
registry._stored_in_collection(event_key, self)
@@ -107,7 +124,9 @@ class _ClsLevelDispatch(RefCollection):
target = event_key.dispatch_target
assert isinstance(target, type), \
"Class-level Event targets must be classes."
-
+ if not getattr(target, '_sa_propagate_class_events', True):
+ raise exc.InvalidRequestError(
+ "Can't assign an event directly to the %s class" % target)
stack = [target]
while stack:
cls = stack.pop(0)
@@ -116,13 +135,19 @@ class _ClsLevelDispatch(RefCollection):
self.update_subclass(cls)
else:
if cls not in self._clslevel:
- self._clslevel[cls] = collections.deque()
+ self._assign_cls_collection(cls)
self._clslevel[cls].append(event_key._listen_fn)
registry._stored_in_collection(event_key, self)
+ def _assign_cls_collection(self, target):
+ if getattr(target, '_sa_propagate_class_events', True):
+ self._clslevel[target] = collections.deque()
+ else:
+ self._clslevel[target] = _empty_collection()
+
def update_subclass(self, target):
if target not in self._clslevel:
- self._clslevel[target] = collections.deque()
+ self._assign_cls_collection(target)
clslevel = self._clslevel[target]
for cls in target.__mro__[1:]:
if cls in self._clslevel: