Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/sqlalchemy/event/api.py : 88%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# event/api.py
2# Copyright (C) 2005-2020 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: http://www.opensource.org/licenses/mit-license.php
8"""Public API functions for the event system.
10"""
11from __future__ import absolute_import
13from .base import _registrars
14from .registry import _EventKey
15from .. import exc
16from .. import util
19CANCEL = util.symbol("CANCEL")
20NO_RETVAL = util.symbol("NO_RETVAL")
23def _event_key(target, identifier, fn):
24 for evt_cls in _registrars[identifier]:
25 tgt = evt_cls._accept_with(target)
26 if tgt is not None:
27 return _EventKey(target, identifier, fn, tgt)
28 else:
29 raise exc.InvalidRequestError(
30 "No such event '%s' for target '%s'" % (identifier, target)
31 )
34def listen(target, identifier, fn, *args, **kw):
35 """Register a listener function for the given target.
37 The :func:`.listen` function is part of the primary interface for the
38 SQLAlchemy event system, documented at :ref:`event_toplevel`.
40 e.g.::
42 from sqlalchemy import event
43 from sqlalchemy.schema import UniqueConstraint
45 def unique_constraint_name(const, table):
46 const.name = "uq_%s_%s" % (
47 table.name,
48 list(const.columns)[0].name
49 )
50 event.listen(
51 UniqueConstraint,
52 "after_parent_attach",
53 unique_constraint_name)
56 A given function can also be invoked for only the first invocation
57 of the event using the ``once`` argument::
59 def on_config():
60 do_config()
62 event.listen(Mapper, "before_configure", on_config, once=True)
64 .. versionadded:: 0.9.4 Added ``once=True`` to :func:`.event.listen`
65 and :func:`.event.listens_for`.
67 .. warning:: The ``once`` argument does not imply automatic de-registration
68 of the listener function after it has been invoked a first time; a
69 listener entry will remain associated with the target object.
70 Associating an arbitrarily high number of listeners without explictitly
71 removing them will cause memory to grow unbounded even if ``once=True``
72 is specified.
74 .. note::
76 The :func:`.listen` function cannot be called at the same time
77 that the target event is being run. This has implications
78 for thread safety, and also means an event cannot be added
79 from inside the listener function for itself. The list of
80 events to be run are present inside of a mutable collection
81 that can't be changed during iteration.
83 Event registration and removal is not intended to be a "high
84 velocity" operation; it is a configurational operation. For
85 systems that need to quickly associate and deassociate with
86 events at high scale, use a mutable structure that is handled
87 from inside of a single listener.
89 .. versionchanged:: 1.0.0 - a ``collections.deque()`` object is now
90 used as the container for the list of events, which explicitly
91 disallows collection mutation while the collection is being
92 iterated.
94 .. seealso::
96 :func:`.listens_for`
98 :func:`.remove`
100 """
102 _event_key(target, identifier, fn).listen(*args, **kw)
105def listens_for(target, identifier, *args, **kw):
106 """Decorate a function as a listener for the given target + identifier.
108 The :func:`.listens_for` decorator is part of the primary interface for the
109 SQLAlchemy event system, documented at :ref:`event_toplevel`.
111 e.g.::
113 from sqlalchemy import event
114 from sqlalchemy.schema import UniqueConstraint
116 @event.listens_for(UniqueConstraint, "after_parent_attach")
117 def unique_constraint_name(const, table):
118 const.name = "uq_%s_%s" % (
119 table.name,
120 list(const.columns)[0].name
121 )
123 A given function can also be invoked for only the first invocation
124 of the event using the ``once`` argument::
126 @event.listens_for(Mapper, "before_configure", once=True)
127 def on_config():
128 do_config()
131 .. versionadded:: 0.9.4 Added ``once=True`` to :func:`.event.listen`
132 and :func:`.event.listens_for`.
134 .. warning:: The ``once`` argument does not imply automatic de-registration
135 of the listener function after it has been invoked a first time; a
136 listener entry will remain associated with the target object.
137 Associating an arbitrarily high number of listeners without explictitly
138 removing them will cause memory to grow unbounded even if ``once=True``
139 is specified.
141 .. seealso::
143 :func:`.listen` - general description of event listening
145 """
147 def decorate(fn):
148 listen(target, identifier, fn, *args, **kw)
149 return fn
151 return decorate
154def remove(target, identifier, fn):
155 """Remove an event listener.
157 The arguments here should match exactly those which were sent to
158 :func:`.listen`; all the event registration which proceeded as a result
159 of this call will be reverted by calling :func:`.remove` with the same
160 arguments.
162 e.g.::
164 # if a function was registered like this...
165 @event.listens_for(SomeMappedClass, "before_insert", propagate=True)
166 def my_listener_function(*arg):
167 pass
169 # ... it's removed like this
170 event.remove(SomeMappedClass, "before_insert", my_listener_function)
172 Above, the listener function associated with ``SomeMappedClass`` was also
173 propagated to subclasses of ``SomeMappedClass``; the :func:`.remove`
174 function will revert all of these operations.
176 .. versionadded:: 0.9.0
178 .. note::
180 The :func:`.remove` function cannot be called at the same time
181 that the target event is being run. This has implications
182 for thread safety, and also means an event cannot be removed
183 from inside the listener function for itself. The list of
184 events to be run are present inside of a mutable collection
185 that can't be changed during iteration.
187 Event registration and removal is not intended to be a "high
188 velocity" operation; it is a configurational operation. For
189 systems that need to quickly associate and deassociate with
190 events at high scale, use a mutable structure that is handled
191 from inside of a single listener.
193 .. versionchanged:: 1.0.0 - a ``collections.deque()`` object is now
194 used as the container for the list of events, which explicitly
195 disallows collection mutation while the collection is being
196 iterated.
198 .. seealso::
200 :func:`.listen`
202 """
203 _event_key(target, identifier, fn).remove()
206def contains(target, identifier, fn):
207 """Return True if the given target/ident/fn is set up to listen.
209 .. versionadded:: 0.9.0
211 """
213 return _event_key(target, identifier, fn).contains()