SQLAlchemy 2.1.0b2__cp313-cp313t-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. sqlalchemy/__init__.py +298 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +89 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4166 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +698 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  21. sqlalchemy/dialects/mysql/base.py +3877 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +330 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +156 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3977 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1601 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +158 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +909 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +368 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +229 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1323 -0
  50. sqlalchemy/dialects/postgresql/base.py +5789 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +593 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +423 -0
  55. sqlalchemy/dialects/postgresql/json.py +408 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  57. sqlalchemy/dialects/postgresql/operators.py +130 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +670 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  60. sqlalchemy/dialects/postgresql/provision.py +184 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +799 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  68. sqlalchemy/dialects/sqlite/base.py +3063 -0
  69. sqlalchemy/dialects/sqlite/dml.py +279 -0
  70. sqlalchemy/dialects/sqlite/json.py +100 -0
  71. sqlalchemy/dialects/sqlite/provision.py +229 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +161 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp313t-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp313t-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +633 -0
  80. sqlalchemy/engine/_row_cy.cp313t-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp313t-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3354 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2421 -0
  88. sqlalchemy/engine/default.py +2402 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3495 -0
  91. sqlalchemy/engine/mock.py +134 -0
  92. sqlalchemy/engine/processors.py +82 -0
  93. sqlalchemy/engine/reflection.py +2100 -0
  94. sqlalchemy/engine/result.py +1966 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +156 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +674 -0
  102. sqlalchemy/event/base.py +472 -0
  103. sqlalchemy/event/legacy.py +258 -0
  104. sqlalchemy/event/registry.py +390 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +922 -0
  107. sqlalchemy/ext/__init__.py +11 -0
  108. sqlalchemy/ext/associationproxy.py +2072 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2007 -0
  116. sqlalchemy/ext/automap.py +1701 -0
  117. sqlalchemy/ext/baked.py +559 -0
  118. sqlalchemy/ext/compiler.py +600 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +560 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +439 -0
  127. sqlalchemy/ext/serializer.py +185 -0
  128. sqlalchemy/future/__init__.py +16 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +174 -0
  131. sqlalchemy/log.py +283 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +179 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +976 -0
  137. sqlalchemy/orm/bulk_persistence.py +2152 -0
  138. sqlalchemy/orm/clsregistry.py +582 -0
  139. sqlalchemy/orm/collections.py +1568 -0
  140. sqlalchemy/orm/context.py +3471 -0
  141. sqlalchemy/orm/decl_api.py +2280 -0
  142. sqlalchemy/orm/decl_base.py +2309 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +307 -0
  146. sqlalchemy/orm/evaluator.py +379 -0
  147. sqlalchemy/orm/events.py +3386 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +746 -0
  151. sqlalchemy/orm/interfaces.py +1589 -0
  152. sqlalchemy/orm/loading.py +1684 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4411 -0
  155. sqlalchemy/orm/path_registry.py +829 -0
  156. sqlalchemy/orm/persistence.py +1789 -0
  157. sqlalchemy/orm/properties.py +973 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3570 -0
  160. sqlalchemy/orm/scoping.py +2232 -0
  161. sqlalchemy/orm/session.py +5403 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3492 -0
  165. sqlalchemy/orm/strategy_options.py +2562 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +798 -0
  168. sqlalchemy/orm/util.py +2438 -0
  169. sqlalchemy/orm/writeonly.py +694 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1522 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +582 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +74 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +397 -0
  178. sqlalchemy/sql/_dml_constructors.py +132 -0
  179. sqlalchemy/sql/_elements_constructors.py +2164 -0
  180. sqlalchemy/sql/_orm_types.py +20 -0
  181. sqlalchemy/sql/_selectable_constructors.py +840 -0
  182. sqlalchemy/sql/_typing.py +487 -0
  183. sqlalchemy/sql/_util_cy.cp313t-win_arm64.pyd +0 -0
  184. sqlalchemy/sql/_util_cy.py +127 -0
  185. sqlalchemy/sql/annotation.py +590 -0
  186. sqlalchemy/sql/base.py +2699 -0
  187. sqlalchemy/sql/cache_key.py +1066 -0
  188. sqlalchemy/sql/coercions.py +1373 -0
  189. sqlalchemy/sql/compiler.py +8327 -0
  190. sqlalchemy/sql/crud.py +1815 -0
  191. sqlalchemy/sql/ddl.py +1928 -0
  192. sqlalchemy/sql/default_comparator.py +654 -0
  193. sqlalchemy/sql/dml.py +1977 -0
  194. sqlalchemy/sql/elements.py +6033 -0
  195. sqlalchemy/sql/events.py +458 -0
  196. sqlalchemy/sql/expression.py +172 -0
  197. sqlalchemy/sql/functions.py +2305 -0
  198. sqlalchemy/sql/lambdas.py +1443 -0
  199. sqlalchemy/sql/naming.py +209 -0
  200. sqlalchemy/sql/operators.py +2897 -0
  201. sqlalchemy/sql/roles.py +332 -0
  202. sqlalchemy/sql/schema.py +6703 -0
  203. sqlalchemy/sql/selectable.py +7553 -0
  204. sqlalchemy/sql/sqltypes.py +4093 -0
  205. sqlalchemy/sql/traversals.py +1042 -0
  206. sqlalchemy/sql/type_api.py +2446 -0
  207. sqlalchemy/sql/util.py +1495 -0
  208. sqlalchemy/sql/visitors.py +1157 -0
  209. sqlalchemy/testing/__init__.py +96 -0
  210. sqlalchemy/testing/assertions.py +1007 -0
  211. sqlalchemy/testing/assertsql.py +519 -0
  212. sqlalchemy/testing/asyncio.py +128 -0
  213. sqlalchemy/testing/config.py +440 -0
  214. sqlalchemy/testing/engines.py +483 -0
  215. sqlalchemy/testing/entities.py +117 -0
  216. sqlalchemy/testing/exclusions.py +476 -0
  217. sqlalchemy/testing/fixtures/__init__.py +30 -0
  218. sqlalchemy/testing/fixtures/base.py +384 -0
  219. sqlalchemy/testing/fixtures/mypy.py +247 -0
  220. sqlalchemy/testing/fixtures/orm.py +227 -0
  221. sqlalchemy/testing/fixtures/sql.py +538 -0
  222. sqlalchemy/testing/pickleable.py +155 -0
  223. sqlalchemy/testing/plugin/__init__.py +6 -0
  224. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  225. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  226. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  227. sqlalchemy/testing/profiling.py +329 -0
  228. sqlalchemy/testing/provision.py +613 -0
  229. sqlalchemy/testing/requirements.py +1978 -0
  230. sqlalchemy/testing/schema.py +198 -0
  231. sqlalchemy/testing/suite/__init__.py +19 -0
  232. sqlalchemy/testing/suite/test_cte.py +237 -0
  233. sqlalchemy/testing/suite/test_ddl.py +420 -0
  234. sqlalchemy/testing/suite/test_dialect.py +776 -0
  235. sqlalchemy/testing/suite/test_insert.py +630 -0
  236. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  237. sqlalchemy/testing/suite/test_results.py +660 -0
  238. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  239. sqlalchemy/testing/suite/test_select.py +2112 -0
  240. sqlalchemy/testing/suite/test_sequence.py +317 -0
  241. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  242. sqlalchemy/testing/suite/test_types.py +2271 -0
  243. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  244. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  245. sqlalchemy/testing/util.py +535 -0
  246. sqlalchemy/testing/warnings.py +52 -0
  247. sqlalchemy/types.py +76 -0
  248. sqlalchemy/util/__init__.py +158 -0
  249. sqlalchemy/util/_collections.py +688 -0
  250. sqlalchemy/util/_collections_cy.cp313t-win_arm64.pyd +0 -0
  251. sqlalchemy/util/_collections_cy.pxd +8 -0
  252. sqlalchemy/util/_collections_cy.py +516 -0
  253. sqlalchemy/util/_has_cython.py +46 -0
  254. sqlalchemy/util/_immutabledict_cy.cp313t-win_arm64.pyd +0 -0
  255. sqlalchemy/util/_immutabledict_cy.py +240 -0
  256. sqlalchemy/util/compat.py +299 -0
  257. sqlalchemy/util/concurrency.py +322 -0
  258. sqlalchemy/util/cython.py +79 -0
  259. sqlalchemy/util/deprecations.py +401 -0
  260. sqlalchemy/util/langhelpers.py +2320 -0
  261. sqlalchemy/util/preloaded.py +152 -0
  262. sqlalchemy/util/queue.py +304 -0
  263. sqlalchemy/util/tool_support.py +201 -0
  264. sqlalchemy/util/topological.py +120 -0
  265. sqlalchemy/util/typing.py +711 -0
  266. sqlalchemy-2.1.0b2.dist-info/METADATA +269 -0
  267. sqlalchemy-2.1.0b2.dist-info/RECORD +270 -0
  268. sqlalchemy-2.1.0b2.dist-info/WHEEL +5 -0
  269. sqlalchemy-2.1.0b2.dist-info/licenses/LICENSE +19 -0
  270. sqlalchemy-2.1.0b2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,156 @@
1
+ # engine/util.py
2
+ # Copyright (C) 2005-2026 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
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+ from typing import Callable
12
+ from typing import Optional
13
+ from typing import Protocol
14
+ from typing import TypeVar
15
+
16
+ from ._util_cy import _distill_params_20 as _distill_params_20 # noqa: F401
17
+ from ._util_cy import _distill_raw_params as _distill_raw_params # noqa: F401
18
+ from .. import exc
19
+ from .. import util
20
+ from ..util.typing import Self
21
+
22
+ _C = TypeVar("_C", bound=Callable[[], Any])
23
+
24
+
25
+ def connection_memoize(key: str) -> Callable[[_C], _C]:
26
+ """Decorator, memoize a function in a connection.info stash.
27
+
28
+ Only applicable to functions which take no arguments other than a
29
+ connection. The memo will be stored in ``connection.info[key]``.
30
+ """
31
+
32
+ @util.decorator
33
+ def decorated(fn, self, connection): # type: ignore
34
+ connection = connection.connect()
35
+ try:
36
+ return connection.info[key]
37
+ except KeyError:
38
+ connection.info[key] = val = fn(self, connection)
39
+ return val
40
+
41
+ return decorated
42
+
43
+
44
+ class _TConsSubject(Protocol):
45
+ _trans_context_manager: Optional[TransactionalContext]
46
+
47
+
48
+ class TransactionalContext:
49
+ """Apply Python context manager behavior to transaction objects.
50
+
51
+ Performs validation to ensure the subject of the transaction is not
52
+ used if the transaction were ended prematurely.
53
+
54
+ """
55
+
56
+ __slots__ = ("_outer_trans_ctx", "_trans_subject", "__weakref__")
57
+
58
+ _trans_subject: Optional[_TConsSubject]
59
+
60
+ def _transaction_is_active(self) -> bool:
61
+ raise NotImplementedError()
62
+
63
+ def _transaction_is_closed(self) -> bool:
64
+ raise NotImplementedError()
65
+
66
+ def _rollback_can_be_called(self) -> bool:
67
+ """indicates the object is in a state that is known to be acceptable
68
+ for rollback() to be called.
69
+
70
+ This does not necessarily mean rollback() will succeed or not raise
71
+ an error, just that there is currently no state detected that indicates
72
+ rollback() would fail or emit warnings.
73
+
74
+ It also does not mean that there's a transaction in progress, as
75
+ it is usually safe to call rollback() even if no transaction is
76
+ present.
77
+
78
+ .. versionadded:: 1.4.28
79
+
80
+ """
81
+ raise NotImplementedError()
82
+
83
+ def _get_subject(self) -> _TConsSubject:
84
+ raise NotImplementedError()
85
+
86
+ def commit(self) -> None:
87
+ raise NotImplementedError()
88
+
89
+ def rollback(self) -> None:
90
+ raise NotImplementedError()
91
+
92
+ def close(self) -> None:
93
+ raise NotImplementedError()
94
+
95
+ @classmethod
96
+ def _trans_ctx_check(cls, subject: _TConsSubject) -> None:
97
+ trans_context = subject._trans_context_manager
98
+ if trans_context:
99
+ if not trans_context._transaction_is_active():
100
+ raise exc.InvalidRequestError(
101
+ "Can't operate on closed transaction inside context "
102
+ "manager. Please complete the context manager "
103
+ "before emitting further commands."
104
+ )
105
+
106
+ def __enter__(self) -> Self:
107
+ subject = self._get_subject()
108
+
109
+ # none for outer transaction, may be non-None for nested
110
+ # savepoint, legacy nesting cases
111
+ trans_context = subject._trans_context_manager
112
+ self._outer_trans_ctx = trans_context
113
+
114
+ self._trans_subject = subject
115
+ subject._trans_context_manager = self
116
+ return self
117
+
118
+ def __exit__(self, type_: Any, value: Any, traceback: Any) -> None:
119
+ subject = getattr(self, "_trans_subject", None)
120
+
121
+ # simplistically we could assume that
122
+ # "subject._trans_context_manager is self". However, any calling
123
+ # code that is manipulating __exit__ directly would break this
124
+ # assumption. alembic context manager
125
+ # is an example of partial use that just calls __exit__ and
126
+ # not __enter__ at the moment. it's safe to assume this is being done
127
+ # in the wild also
128
+ out_of_band_exit = (
129
+ subject is None or subject._trans_context_manager is not self
130
+ )
131
+
132
+ if type_ is None and self._transaction_is_active():
133
+ try:
134
+ self.commit()
135
+ except:
136
+ with util.safe_reraise():
137
+ if self._rollback_can_be_called():
138
+ self.rollback()
139
+ finally:
140
+ if not out_of_band_exit:
141
+ assert subject is not None
142
+ subject._trans_context_manager = self._outer_trans_ctx
143
+ self._trans_subject = self._outer_trans_ctx = None
144
+ else:
145
+ try:
146
+ if not self._transaction_is_active():
147
+ if not self._transaction_is_closed():
148
+ self.close()
149
+ else:
150
+ if self._rollback_can_be_called():
151
+ self.rollback()
152
+ finally:
153
+ if not out_of_band_exit:
154
+ assert subject is not None
155
+ subject._trans_context_manager = self._outer_trans_ctx
156
+ self._trans_subject = self._outer_trans_ctx = None
@@ -0,0 +1,26 @@
1
+ # event/__init__.py
2
+ # Copyright (C) 2005-2026 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
+ from __future__ import annotations
9
+
10
+ from .api import CANCEL as CANCEL
11
+ from .api import contains as contains
12
+ from .api import listen as listen
13
+ from .api import listens_for as listens_for
14
+ from .api import NO_RETVAL as NO_RETVAL
15
+ from .api import remove as remove
16
+ from .attr import _InstanceLevelDispatch as _InstanceLevelDispatch
17
+ from .attr import RefCollection as RefCollection
18
+ from .base import _Dispatch as _Dispatch
19
+ from .base import _DispatchCommon as _DispatchCommon
20
+ from .base import dispatcher as dispatcher
21
+ from .base import Events as Events
22
+ from .legacy import _legacy_signature as _legacy_signature
23
+ from .legacy import _omit_standard_example as _omit_standard_example
24
+ from .registry import _EventKey as _EventKey
25
+ from .registry import _ListenerFnType as _ListenerFnType
26
+ from .registry import EventTarget as EventTarget
@@ -0,0 +1,220 @@
1
+ # event/api.py
2
+ # Copyright (C) 2005-2026 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
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+ from typing import Callable
13
+
14
+ from .base import _registrars
15
+ from .registry import _ET
16
+ from .registry import _EventKey
17
+ from .registry import _ListenerFnType
18
+ from .. import exc
19
+ from .. import util
20
+
21
+
22
+ CANCEL = util.symbol("CANCEL")
23
+ NO_RETVAL = util.symbol("NO_RETVAL")
24
+
25
+
26
+ def _event_key(
27
+ target: _ET, identifier: str, fn: _ListenerFnType
28
+ ) -> _EventKey[_ET]:
29
+ for evt_cls in _registrars[identifier]:
30
+ tgt = evt_cls._accept_with(target, identifier)
31
+ if tgt is not None:
32
+ return _EventKey(target, identifier, fn, tgt)
33
+ else:
34
+ raise exc.InvalidRequestError(
35
+ "No such event '%s' for target '%s'" % (identifier, target)
36
+ )
37
+
38
+
39
+ def listen(
40
+ target: Any, identifier: str, fn: Callable[..., Any], *args: Any, **kw: Any
41
+ ) -> None:
42
+ """Register a listener function for the given target.
43
+
44
+ The :func:`.listen` function is part of the primary interface for the
45
+ SQLAlchemy event system, documented at :ref:`event_toplevel`.
46
+
47
+ e.g.::
48
+
49
+ from sqlalchemy import event
50
+ from sqlalchemy.schema import UniqueConstraint
51
+
52
+
53
+ def unique_constraint_name(const, table):
54
+ const.name = "uq_%s_%s" % (table.name, list(const.columns)[0].name)
55
+
56
+
57
+ event.listen(
58
+ UniqueConstraint, "after_parent_attach", unique_constraint_name
59
+ )
60
+
61
+ :param bool insert: The default behavior for event handlers is to append
62
+ the decorated user defined function to an internal list of registered
63
+ event listeners upon discovery. If a user registers a function with
64
+ ``insert=True``, SQLAlchemy will insert (prepend) the function to the
65
+ internal list upon discovery. This feature is not typically used or
66
+ recommended by the SQLAlchemy maintainers, but is provided to ensure
67
+ certain user defined functions can run before others, such as when
68
+ :ref:`Changing the sql_mode in MySQL <mysql_sql_mode>`.
69
+
70
+ :param bool named: When using named argument passing, the names listed in
71
+ the function argument specification will be used as keys in the
72
+ dictionary.
73
+ See :ref:`event_named_argument_styles`.
74
+
75
+ :param bool once: Private/Internal API usage. Deprecated. This parameter
76
+ would provide that an event function would run only once per given
77
+ target. It does not however imply automatic de-registration of the
78
+ listener function; associating an arbitrarily high number of listeners
79
+ without explicitly removing them will cause memory to grow unbounded even
80
+ if ``once=True`` is specified.
81
+
82
+ :param bool propagate: The ``propagate`` kwarg is available when working
83
+ with ORM instrumentation and mapping events.
84
+ See :class:`_ormevent.MapperEvents` and
85
+ :meth:`_ormevent.MapperEvents.before_mapper_configured` for examples.
86
+
87
+ :param bool retval: This flag applies only to specific event listeners,
88
+ each of which includes documentation explaining when it should be used.
89
+ By default, no listener ever requires a return value.
90
+ However, some listeners do support special behaviors for return values,
91
+ and include in their documentation that the ``retval=True`` flag is
92
+ necessary for a return value to be processed.
93
+
94
+ Event listener suites that make use of :paramref:`_event.listen.retval`
95
+ include :class:`_events.ConnectionEvents` and
96
+ :class:`_ormevent.AttributeEvents`.
97
+
98
+ .. note::
99
+
100
+ The :func:`.listen` function cannot be called at the same time
101
+ that the target event is being run. This has implications
102
+ for thread safety, and also means an event cannot be added
103
+ from inside the listener function for itself. The list of
104
+ events to be run are present inside of a mutable collection
105
+ that can't be changed during iteration.
106
+
107
+ Event registration and removal is not intended to be a "high
108
+ velocity" operation; it is a configurational operation. For
109
+ systems that need to quickly associate and deassociate with
110
+ events at high scale, use a mutable structure that is handled
111
+ from inside of a single listener.
112
+
113
+ .. seealso::
114
+
115
+ :func:`.listens_for`
116
+
117
+ :func:`.remove`
118
+
119
+ """
120
+
121
+ _event_key(target, identifier, fn).listen(*args, **kw)
122
+
123
+
124
+ def listens_for(
125
+ target: Any, identifier: str, *args: Any, **kw: Any
126
+ ) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
127
+ """Decorate a function as a listener for the given target + identifier.
128
+
129
+ The :func:`.listens_for` decorator is part of the primary interface for the
130
+ SQLAlchemy event system, documented at :ref:`event_toplevel`.
131
+
132
+ This function generally shares the same kwargs as :func:`.listen`.
133
+
134
+ e.g.::
135
+
136
+ from sqlalchemy import event
137
+ from sqlalchemy.schema import UniqueConstraint
138
+
139
+
140
+ @event.listens_for(UniqueConstraint, "after_parent_attach")
141
+ def unique_constraint_name(const, table):
142
+ const.name = "uq_%s_%s" % (table.name, list(const.columns)[0].name)
143
+
144
+ A given function can also be invoked for only the first invocation
145
+ of the event using the ``once`` argument::
146
+
147
+ @event.listens_for(Mapper, "before_configure", once=True)
148
+ def on_config():
149
+ do_config()
150
+
151
+ .. warning:: The ``once`` argument does not imply automatic de-registration
152
+ of the listener function after it has been invoked a first time; a
153
+ listener entry will remain associated with the target object.
154
+ Associating an arbitrarily high number of listeners without explicitly
155
+ removing them will cause memory to grow unbounded even if ``once=True``
156
+ is specified.
157
+
158
+ .. seealso::
159
+
160
+ :func:`.listen` - general description of event listening
161
+
162
+ """
163
+
164
+ def decorate(fn: Callable[..., Any]) -> Callable[..., Any]:
165
+ listen(target, identifier, fn, *args, **kw)
166
+ return fn
167
+
168
+ return decorate
169
+
170
+
171
+ def remove(target: Any, identifier: str, fn: Callable[..., Any]) -> None:
172
+ """Remove an event listener.
173
+
174
+ The arguments here should match exactly those which were sent to
175
+ :func:`.listen`; all the event registration which proceeded as a result
176
+ of this call will be reverted by calling :func:`.remove` with the same
177
+ arguments.
178
+
179
+ e.g.::
180
+
181
+ # if a function was registered like this...
182
+ @event.listens_for(SomeMappedClass, "before_insert", propagate=True)
183
+ def my_listener_function(*arg):
184
+ pass
185
+
186
+
187
+ # ... it's removed like this
188
+ event.remove(SomeMappedClass, "before_insert", my_listener_function)
189
+
190
+ Above, the listener function associated with ``SomeMappedClass`` was also
191
+ propagated to subclasses of ``SomeMappedClass``; the :func:`.remove`
192
+ function will revert all of these operations.
193
+
194
+ .. note::
195
+
196
+ The :func:`.remove` function cannot be called at the same time
197
+ that the target event is being run. This has implications
198
+ for thread safety, and also means an event cannot be removed
199
+ from inside the listener function for itself. The list of
200
+ events to be run are present inside of a mutable collection
201
+ that can't be changed during iteration.
202
+
203
+ Event registration and removal is not intended to be a "high
204
+ velocity" operation; it is a configurational operation. For
205
+ systems that need to quickly associate and deassociate with
206
+ events at high scale, use a mutable structure that is handled
207
+ from inside of a single listener.
208
+
209
+ .. seealso::
210
+
211
+ :func:`.listen`
212
+
213
+ """
214
+ _event_key(target, identifier, fn).remove()
215
+
216
+
217
+ def contains(target: Any, identifier: str, fn: Callable[..., Any]) -> bool:
218
+ """Return True if the given target/ident/fn is set up to listen."""
219
+
220
+ return _event_key(target, identifier, fn).contains()