Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
api.py226 linesDownload Raw Back to event
1# event/api.py
2# Copyright (C) 2005-2024 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: https://www.opensource.org/licenses/mit-license.php
7
8"""Public API functions for the event system.
9
10"""
11from __future__ import annotations
12
13from typing import Any
14from typing import Callable
15
16from .base import _registrars
17from .registry import _ET
18from .registry import _EventKey
19from .registry import _ListenerFnType
20from .. import exc
21from .. import util
22
23
24CANCEL = util.symbol("CANCEL")
25NO_RETVAL = util.symbol("NO_RETVAL")
26
27
28def _event_key(
29    target: _ET, identifier: str, fn: _ListenerFnType
30) -> _EventKey[_ET]:
31    for evt_cls in _registrars[identifier]:
32        tgt = evt_cls._accept_with(target, identifier)
33        if tgt is not None:
34            return _EventKey(target, identifier, fn, tgt)
35    else:
36        raise exc.InvalidRequestError(
37            "No such event '%s' for target '%s'" % (identifier, target)
38        )
39
40
41def listen(
42    target: Any, identifier: str, fn: Callable[..., Any], *args: Any, **kw: Any
43) -> None:
44    """Register a listener function for the given target.
45
46    The :func:`.listen` function is part of the primary interface for the
47    SQLAlchemy event system, documented at :ref:`event_toplevel`.
48
49    e.g.::
50
51        from sqlalchemy import event
52        from sqlalchemy.schema import UniqueConstraint
53
54        def unique_constraint_name(const, table):
55            const.name = "uq_%s_%s" % (
56                table.name,
57                list(const.columns)[0].name
58            )
59        event.listen(
60                UniqueConstraint,
61                "after_parent_attach",
62                unique_constraint_name)
63
64    :param bool insert: The default behavior for event handlers is to append
65      the decorated user defined function to an internal list of registered
66      event listeners upon discovery. If a user registers a function with
67      ``insert=True``, SQLAlchemy will insert (prepend) the function to the
68      internal list upon discovery. This feature is not typically used or
69      recommended by the SQLAlchemy maintainers, but is provided to ensure
70      certain user defined functions can run before others, such as when
71      :ref:`Changing the sql_mode in MySQL <mysql_sql_mode>`.
72
73    :param bool named: When using named argument passing, the names listed in
74      the function argument specification will be used as keys in the
75      dictionary.
76      See :ref:`event_named_argument_styles`.
77
78    :param bool once: Private/Internal API usage. Deprecated.  This parameter
79      would provide that an event function would run only once per given
80      target. It does not however imply automatic de-registration of the
81      listener function; associating an arbitrarily high number of listeners
82      without explicitly removing them will cause memory to grow unbounded even
83      if ``once=True`` is specified.
84
85    :param bool propagate: The ``propagate`` kwarg is available when working
86      with ORM instrumentation and mapping events.
87      See :class:`_ormevent.MapperEvents` and
88      :meth:`_ormevent.MapperEvents.before_mapper_configured` for examples.
89
90    :param bool retval: This flag applies only to specific event listeners,
91      each of which includes documentation explaining when it should be used.
92      By default, no listener ever requires a return value.
93      However, some listeners do support special behaviors for return values,
94      and include in their documentation that the ``retval=True`` flag is
95      necessary for a return value to be processed.
96
97      Event listener suites that make use of :paramref:`_event.listen.retval`
98      include :class:`_events.ConnectionEvents` and
99      :class:`_ormevent.AttributeEvents`.
100
101    .. note::
102
103        The :func:`.listen` function cannot be called at the same time
104        that the target event is being run.   This has implications
105        for thread safety, and also means an event cannot be added
106        from inside the listener function for itself.  The list of
107        events to be run are present inside of a mutable collection
108        that can't be changed during iteration.
109
110        Event registration and removal is not intended to be a "high
111        velocity" operation; it is a configurational operation.  For
112        systems that need to quickly associate and deassociate with
113        events at high scale, use a mutable structure that is handled
114        from inside of a single listener.
115
116    .. seealso::
117
118        :func:`.listens_for`
119
120        :func:`.remove`
121
122    """
123
124    _event_key(target, identifier, fn).listen(*args, **kw)
125
126
127def listens_for(
128    target: Any, identifier: str, *args: Any, **kw: Any
129) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
130    """Decorate a function as a listener for the given target + identifier.
131
132    The :func:`.listens_for` decorator is part of the primary interface for the
133    SQLAlchemy event system, documented at :ref:`event_toplevel`.
134
135    This function generally shares the same kwargs as :func:`.listen`.
136
137    e.g.::
138
139        from sqlalchemy import event
140        from sqlalchemy.schema import UniqueConstraint
141
142        @event.listens_for(UniqueConstraint, "after_parent_attach")
143        def unique_constraint_name(const, table):
144            const.name = "uq_%s_%s" % (
145                table.name,
146                list(const.columns)[0].name
147            )
148
149    A given function can also be invoked for only the first invocation
150    of the event using the ``once`` argument::
151
152        @event.listens_for(Mapper, "before_configure", once=True)
153        def on_config():
154            do_config()
155
156
157    .. warning:: The ``once`` argument does not imply automatic de-registration
158       of the listener function after it has been invoked a first time; a
159       listener entry will remain associated with the target object.
160       Associating an arbitrarily high number of listeners without explicitly
161       removing them will cause memory to grow unbounded even if ``once=True``
162       is specified.
163
164    .. seealso::
165
166        :func:`.listen` - general description of event listening
167
168    """
169
170    def decorate(fn: Callable[..., Any]) -> Callable[..., Any]:
171        listen(target, identifier, fn, *args, **kw)
172        return fn
173
174    return decorate
175
176
177def remove(target: Any, identifier: str, fn: Callable[..., Any]) -> None:
178    """Remove an event listener.
179
180    The arguments here should match exactly those which were sent to
181    :func:`.listen`; all the event registration which proceeded as a result
182    of this call will be reverted by calling :func:`.remove` with the same
183    arguments.
184
185    e.g.::
186
187        # if a function was registered like this...
188        @event.listens_for(SomeMappedClass, "before_insert", propagate=True)
189        def my_listener_function(*arg):
190            pass
191
192        # ... it's removed like this
193        event.remove(SomeMappedClass, "before_insert", my_listener_function)
194
195    Above, the listener function associated with ``SomeMappedClass`` was also
196    propagated to subclasses of ``SomeMappedClass``; the :func:`.remove`
197    function will revert all of these operations.
198
199    .. note::
200
201        The :func:`.remove` function cannot be called at the same time
202        that the target event is being run.   This has implications
203        for thread safety, and also means an event cannot be removed
204        from inside the listener function for itself.  The list of
205        events to be run are present inside of a mutable collection
206        that can't be changed during iteration.
207
208        Event registration and removal is not intended to be a "high
209        velocity" operation; it is a configurational operation.  For
210        systems that need to quickly associate and deassociate with
211        events at high scale, use a mutable structure that is handled
212        from inside of a single listener.
213
214    .. seealso::
215
216        :func:`.listen`
217
218    """
219    _event_key(target, identifier, fn).remove()
220
221
222def contains(target: Any, identifier: str, fn: Callable[..., Any]) -> bool:
223    """Return True if the given target/ident/fn is set up to listen."""
224
225    return _event_key(target, identifier, fn).contains()
226 
codekingpro/portable-devtools · Team Ai