SQLAlchemy 2.0.36__cp313-cp313-win_amd64.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 (273) hide show
  1. SQLAlchemy-2.0.36.dist-info/LICENSE +19 -0
  2. SQLAlchemy-2.0.36.dist-info/METADATA +243 -0
  3. SQLAlchemy-2.0.36.dist-info/RECORD +273 -0
  4. SQLAlchemy-2.0.36.dist-info/WHEEL +5 -0
  5. SQLAlchemy-2.0.36.dist-info/top_level.txt +1 -0
  6. sqlalchemy/__init__.py +294 -0
  7. sqlalchemy/connectors/__init__.py +18 -0
  8. sqlalchemy/connectors/aioodbc.py +174 -0
  9. sqlalchemy/connectors/asyncio.py +213 -0
  10. sqlalchemy/connectors/pyodbc.py +249 -0
  11. sqlalchemy/cyextension/__init__.py +6 -0
  12. sqlalchemy/cyextension/collections.cp313-win_amd64.pyd +0 -0
  13. sqlalchemy/cyextension/collections.pyx +409 -0
  14. sqlalchemy/cyextension/immutabledict.cp313-win_amd64.pyd +0 -0
  15. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  16. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  17. sqlalchemy/cyextension/processors.cp313-win_amd64.pyd +0 -0
  18. sqlalchemy/cyextension/processors.pyx +68 -0
  19. sqlalchemy/cyextension/resultproxy.cp313-win_amd64.pyd +0 -0
  20. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  21. sqlalchemy/cyextension/util.cp313-win_amd64.pyd +0 -0
  22. sqlalchemy/cyextension/util.pyx +91 -0
  23. sqlalchemy/dialects/__init__.py +61 -0
  24. sqlalchemy/dialects/_typing.py +25 -0
  25. sqlalchemy/dialects/mssql/__init__.py +88 -0
  26. sqlalchemy/dialects/mssql/aioodbc.py +64 -0
  27. sqlalchemy/dialects/mssql/base.py +4010 -0
  28. sqlalchemy/dialects/mssql/information_schema.py +254 -0
  29. sqlalchemy/dialects/mssql/json.py +133 -0
  30. sqlalchemy/dialects/mssql/provision.py +162 -0
  31. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  32. sqlalchemy/dialects/mssql/pyodbc.py +745 -0
  33. sqlalchemy/dialects/mysql/__init__.py +101 -0
  34. sqlalchemy/dialects/mysql/aiomysql.py +333 -0
  35. sqlalchemy/dialects/mysql/asyncmy.py +337 -0
  36. sqlalchemy/dialects/mysql/base.py +3494 -0
  37. sqlalchemy/dialects/mysql/cymysql.py +84 -0
  38. sqlalchemy/dialects/mysql/dml.py +219 -0
  39. sqlalchemy/dialects/mysql/enumerated.py +244 -0
  40. sqlalchemy/dialects/mysql/expression.py +141 -0
  41. sqlalchemy/dialects/mysql/json.py +81 -0
  42. sqlalchemy/dialects/mysql/mariadb.py +32 -0
  43. sqlalchemy/dialects/mysql/mariadbconnector.py +277 -0
  44. sqlalchemy/dialects/mysql/mysqlconnector.py +180 -0
  45. sqlalchemy/dialects/mysql/mysqldb.py +303 -0
  46. sqlalchemy/dialects/mysql/provision.py +110 -0
  47. sqlalchemy/dialects/mysql/pymysql.py +137 -0
  48. sqlalchemy/dialects/mysql/pyodbc.py +138 -0
  49. sqlalchemy/dialects/mysql/reflection.py +677 -0
  50. sqlalchemy/dialects/mysql/reserved_words.py +571 -0
  51. sqlalchemy/dialects/mysql/types.py +774 -0
  52. sqlalchemy/dialects/oracle/__init__.py +67 -0
  53. sqlalchemy/dialects/oracle/base.py +3271 -0
  54. sqlalchemy/dialects/oracle/cx_oracle.py +1483 -0
  55. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  56. sqlalchemy/dialects/oracle/oracledb.py +431 -0
  57. sqlalchemy/dialects/oracle/provision.py +220 -0
  58. sqlalchemy/dialects/oracle/types.py +287 -0
  59. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  60. sqlalchemy/dialects/postgresql/_psycopg_common.py +187 -0
  61. sqlalchemy/dialects/postgresql/array.py +425 -0
  62. sqlalchemy/dialects/postgresql/asyncpg.py +1274 -0
  63. sqlalchemy/dialects/postgresql/base.py +5008 -0
  64. sqlalchemy/dialects/postgresql/dml.py +310 -0
  65. sqlalchemy/dialects/postgresql/ext.py +496 -0
  66. sqlalchemy/dialects/postgresql/hstore.py +397 -0
  67. sqlalchemy/dialects/postgresql/json.py +333 -0
  68. sqlalchemy/dialects/postgresql/named_types.py +509 -0
  69. sqlalchemy/dialects/postgresql/operators.py +129 -0
  70. sqlalchemy/dialects/postgresql/pg8000.py +662 -0
  71. sqlalchemy/dialects/postgresql/pg_catalog.py +300 -0
  72. sqlalchemy/dialects/postgresql/provision.py +175 -0
  73. sqlalchemy/dialects/postgresql/psycopg.py +772 -0
  74. sqlalchemy/dialects/postgresql/psycopg2.py +886 -0
  75. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  76. sqlalchemy/dialects/postgresql/ranges.py +1029 -0
  77. sqlalchemy/dialects/postgresql/types.py +303 -0
  78. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  79. sqlalchemy/dialects/sqlite/aiosqlite.py +396 -0
  80. sqlalchemy/dialects/sqlite/base.py +2805 -0
  81. sqlalchemy/dialects/sqlite/dml.py +240 -0
  82. sqlalchemy/dialects/sqlite/json.py +92 -0
  83. sqlalchemy/dialects/sqlite/provision.py +198 -0
  84. sqlalchemy/dialects/sqlite/pysqlcipher.py +155 -0
  85. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  86. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  87. sqlalchemy/engine/__init__.py +62 -0
  88. sqlalchemy/engine/_py_processors.py +136 -0
  89. sqlalchemy/engine/_py_row.py +128 -0
  90. sqlalchemy/engine/_py_util.py +74 -0
  91. sqlalchemy/engine/base.py +3375 -0
  92. sqlalchemy/engine/characteristics.py +155 -0
  93. sqlalchemy/engine/create.py +875 -0
  94. sqlalchemy/engine/cursor.py +2181 -0
  95. sqlalchemy/engine/default.py +2365 -0
  96. sqlalchemy/engine/events.py +951 -0
  97. sqlalchemy/engine/interfaces.py +3403 -0
  98. sqlalchemy/engine/mock.py +131 -0
  99. sqlalchemy/engine/processors.py +61 -0
  100. sqlalchemy/engine/reflection.py +2098 -0
  101. sqlalchemy/engine/result.py +2382 -0
  102. sqlalchemy/engine/row.py +401 -0
  103. sqlalchemy/engine/strategies.py +19 -0
  104. sqlalchemy/engine/url.py +910 -0
  105. sqlalchemy/engine/util.py +167 -0
  106. sqlalchemy/event/__init__.py +25 -0
  107. sqlalchemy/event/api.py +225 -0
  108. sqlalchemy/event/attr.py +655 -0
  109. sqlalchemy/event/base.py +470 -0
  110. sqlalchemy/event/legacy.py +246 -0
  111. sqlalchemy/event/registry.py +386 -0
  112. sqlalchemy/events.py +17 -0
  113. sqlalchemy/exc.py +830 -0
  114. sqlalchemy/ext/__init__.py +11 -0
  115. sqlalchemy/ext/associationproxy.py +2013 -0
  116. sqlalchemy/ext/asyncio/__init__.py +25 -0
  117. sqlalchemy/ext/asyncio/base.py +279 -0
  118. sqlalchemy/ext/asyncio/engine.py +1466 -0
  119. sqlalchemy/ext/asyncio/exc.py +21 -0
  120. sqlalchemy/ext/asyncio/result.py +961 -0
  121. sqlalchemy/ext/asyncio/scoping.py +1614 -0
  122. sqlalchemy/ext/asyncio/session.py +1936 -0
  123. sqlalchemy/ext/automap.py +1691 -0
  124. sqlalchemy/ext/baked.py +574 -0
  125. sqlalchemy/ext/compiler.py +570 -0
  126. sqlalchemy/ext/declarative/__init__.py +65 -0
  127. sqlalchemy/ext/declarative/extensions.py +548 -0
  128. sqlalchemy/ext/horizontal_shard.py +481 -0
  129. sqlalchemy/ext/hybrid.py +1514 -0
  130. sqlalchemy/ext/indexable.py +341 -0
  131. sqlalchemy/ext/instrumentation.py +450 -0
  132. sqlalchemy/ext/mutable.py +1073 -0
  133. sqlalchemy/ext/mypy/__init__.py +6 -0
  134. sqlalchemy/ext/mypy/apply.py +320 -0
  135. sqlalchemy/ext/mypy/decl_class.py +515 -0
  136. sqlalchemy/ext/mypy/infer.py +590 -0
  137. sqlalchemy/ext/mypy/names.py +335 -0
  138. sqlalchemy/ext/mypy/plugin.py +303 -0
  139. sqlalchemy/ext/mypy/util.py +357 -0
  140. sqlalchemy/ext/orderinglist.py +416 -0
  141. sqlalchemy/ext/serializer.py +181 -0
  142. sqlalchemy/future/__init__.py +16 -0
  143. sqlalchemy/future/engine.py +15 -0
  144. sqlalchemy/inspection.py +174 -0
  145. sqlalchemy/log.py +288 -0
  146. sqlalchemy/orm/__init__.py +170 -0
  147. sqlalchemy/orm/_orm_constructors.py +2571 -0
  148. sqlalchemy/orm/_typing.py +179 -0
  149. sqlalchemy/orm/attributes.py +2835 -0
  150. sqlalchemy/orm/base.py +973 -0
  151. sqlalchemy/orm/bulk_persistence.py +2123 -0
  152. sqlalchemy/orm/clsregistry.py +571 -0
  153. sqlalchemy/orm/collections.py +1620 -0
  154. sqlalchemy/orm/context.py +3268 -0
  155. sqlalchemy/orm/decl_api.py +1883 -0
  156. sqlalchemy/orm/decl_base.py +2190 -0
  157. sqlalchemy/orm/dependency.py +1304 -0
  158. sqlalchemy/orm/descriptor_props.py +1076 -0
  159. sqlalchemy/orm/dynamic.py +300 -0
  160. sqlalchemy/orm/evaluator.py +379 -0
  161. sqlalchemy/orm/events.py +3261 -0
  162. sqlalchemy/orm/exc.py +228 -0
  163. sqlalchemy/orm/identity.py +302 -0
  164. sqlalchemy/orm/instrumentation.py +754 -0
  165. sqlalchemy/orm/interfaces.py +1474 -0
  166. sqlalchemy/orm/loading.py +1682 -0
  167. sqlalchemy/orm/mapped_collection.py +557 -0
  168. sqlalchemy/orm/mapper.py +4432 -0
  169. sqlalchemy/orm/path_registry.py +811 -0
  170. sqlalchemy/orm/persistence.py +1782 -0
  171. sqlalchemy/orm/properties.py +886 -0
  172. sqlalchemy/orm/query.py +3396 -0
  173. sqlalchemy/orm/relationships.py +3500 -0
  174. sqlalchemy/orm/scoping.py +2165 -0
  175. sqlalchemy/orm/session.py +5301 -0
  176. sqlalchemy/orm/state.py +1143 -0
  177. sqlalchemy/orm/state_changes.py +198 -0
  178. sqlalchemy/orm/strategies.py +3473 -0
  179. sqlalchemy/orm/strategy_options.py +2569 -0
  180. sqlalchemy/orm/sync.py +164 -0
  181. sqlalchemy/orm/unitofwork.py +796 -0
  182. sqlalchemy/orm/util.py +2424 -0
  183. sqlalchemy/orm/writeonly.py +678 -0
  184. sqlalchemy/pool/__init__.py +44 -0
  185. sqlalchemy/pool/base.py +1515 -0
  186. sqlalchemy/pool/events.py +370 -0
  187. sqlalchemy/pool/impl.py +581 -0
  188. sqlalchemy/py.typed +0 -0
  189. sqlalchemy/schema.py +70 -0
  190. sqlalchemy/sql/__init__.py +145 -0
  191. sqlalchemy/sql/_dml_constructors.py +140 -0
  192. sqlalchemy/sql/_elements_constructors.py +1850 -0
  193. sqlalchemy/sql/_orm_types.py +20 -0
  194. sqlalchemy/sql/_py_util.py +75 -0
  195. sqlalchemy/sql/_selectable_constructors.py +635 -0
  196. sqlalchemy/sql/_typing.py +460 -0
  197. sqlalchemy/sql/annotation.py +585 -0
  198. sqlalchemy/sql/base.py +2185 -0
  199. sqlalchemy/sql/cache_key.py +1057 -0
  200. sqlalchemy/sql/coercions.py +1405 -0
  201. sqlalchemy/sql/compiler.py +7818 -0
  202. sqlalchemy/sql/crud.py +1669 -0
  203. sqlalchemy/sql/ddl.py +1378 -0
  204. sqlalchemy/sql/default_comparator.py +552 -0
  205. sqlalchemy/sql/dml.py +1817 -0
  206. sqlalchemy/sql/elements.py +5499 -0
  207. sqlalchemy/sql/events.py +455 -0
  208. sqlalchemy/sql/expression.py +162 -0
  209. sqlalchemy/sql/functions.py +2055 -0
  210. sqlalchemy/sql/lambdas.py +1449 -0
  211. sqlalchemy/sql/naming.py +212 -0
  212. sqlalchemy/sql/operators.py +2579 -0
  213. sqlalchemy/sql/roles.py +323 -0
  214. sqlalchemy/sql/schema.py +6158 -0
  215. sqlalchemy/sql/selectable.py +7004 -0
  216. sqlalchemy/sql/sqltypes.py +3827 -0
  217. sqlalchemy/sql/traversals.py +1024 -0
  218. sqlalchemy/sql/type_api.py +2339 -0
  219. sqlalchemy/sql/util.py +1486 -0
  220. sqlalchemy/sql/visitors.py +1165 -0
  221. sqlalchemy/testing/__init__.py +96 -0
  222. sqlalchemy/testing/assertions.py +989 -0
  223. sqlalchemy/testing/assertsql.py +516 -0
  224. sqlalchemy/testing/asyncio.py +135 -0
  225. sqlalchemy/testing/config.py +427 -0
  226. sqlalchemy/testing/engines.py +472 -0
  227. sqlalchemy/testing/entities.py +117 -0
  228. sqlalchemy/testing/exclusions.py +435 -0
  229. sqlalchemy/testing/fixtures/__init__.py +28 -0
  230. sqlalchemy/testing/fixtures/base.py +366 -0
  231. sqlalchemy/testing/fixtures/mypy.py +312 -0
  232. sqlalchemy/testing/fixtures/orm.py +227 -0
  233. sqlalchemy/testing/fixtures/sql.py +503 -0
  234. sqlalchemy/testing/pickleable.py +155 -0
  235. sqlalchemy/testing/plugin/__init__.py +6 -0
  236. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  237. sqlalchemy/testing/plugin/plugin_base.py +779 -0
  238. sqlalchemy/testing/plugin/pytestplugin.py +868 -0
  239. sqlalchemy/testing/profiling.py +324 -0
  240. sqlalchemy/testing/provision.py +496 -0
  241. sqlalchemy/testing/requirements.py +1818 -0
  242. sqlalchemy/testing/schema.py +224 -0
  243. sqlalchemy/testing/suite/__init__.py +19 -0
  244. sqlalchemy/testing/suite/test_cte.py +211 -0
  245. sqlalchemy/testing/suite/test_ddl.py +389 -0
  246. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  247. sqlalchemy/testing/suite/test_dialect.py +740 -0
  248. sqlalchemy/testing/suite/test_insert.py +630 -0
  249. sqlalchemy/testing/suite/test_reflection.py +3225 -0
  250. sqlalchemy/testing/suite/test_results.py +502 -0
  251. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  252. sqlalchemy/testing/suite/test_select.py +1999 -0
  253. sqlalchemy/testing/suite/test_sequence.py +317 -0
  254. sqlalchemy/testing/suite/test_types.py +2141 -0
  255. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  256. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  257. sqlalchemy/testing/util.py +537 -0
  258. sqlalchemy/testing/warnings.py +52 -0
  259. sqlalchemy/types.py +76 -0
  260. sqlalchemy/util/__init__.py +160 -0
  261. sqlalchemy/util/_collections.py +715 -0
  262. sqlalchemy/util/_concurrency_py3k.py +288 -0
  263. sqlalchemy/util/_has_cy.py +40 -0
  264. sqlalchemy/util/_py_collections.py +541 -0
  265. sqlalchemy/util/compat.py +301 -0
  266. sqlalchemy/util/concurrency.py +108 -0
  267. sqlalchemy/util/deprecations.py +401 -0
  268. sqlalchemy/util/langhelpers.py +2218 -0
  269. sqlalchemy/util/preloaded.py +150 -0
  270. sqlalchemy/util/queue.py +322 -0
  271. sqlalchemy/util/tool_support.py +201 -0
  272. sqlalchemy/util/topological.py +120 -0
  273. sqlalchemy/util/typing.py +629 -0
@@ -0,0 +1,386 @@
1
+ # event/registry.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
+ """Provides managed registration services on behalf of :func:`.listen`
9
+ arguments.
10
+
11
+ By "managed registration", we mean that event listening functions and
12
+ other objects can be added to various collections in such a way that their
13
+ membership in all those collections can be revoked at once, based on
14
+ an equivalent :class:`._EventKey`.
15
+
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import collections
20
+ import types
21
+ import typing
22
+ from typing import Any
23
+ from typing import Callable
24
+ from typing import cast
25
+ from typing import Deque
26
+ from typing import Dict
27
+ from typing import Generic
28
+ from typing import Iterable
29
+ from typing import Optional
30
+ from typing import Tuple
31
+ from typing import TypeVar
32
+ from typing import Union
33
+ import weakref
34
+
35
+ from .. import exc
36
+ from .. import util
37
+
38
+ if typing.TYPE_CHECKING:
39
+ from .attr import RefCollection
40
+ from .base import dispatcher
41
+
42
+ _ListenerFnType = Callable[..., Any]
43
+ _ListenerFnKeyType = Union[int, Tuple[int, int]]
44
+ _EventKeyTupleType = Tuple[int, str, _ListenerFnKeyType]
45
+
46
+
47
+ _ET = TypeVar("_ET", bound="EventTarget")
48
+
49
+
50
+ class EventTarget:
51
+ """represents an event target, that is, something we can listen on
52
+ either with that target as a class or as an instance.
53
+
54
+ Examples include: Connection, Mapper, Table, Session,
55
+ InstrumentedAttribute, Engine, Pool, Dialect.
56
+
57
+ """
58
+
59
+ __slots__ = ()
60
+
61
+ dispatch: dispatcher[Any]
62
+
63
+
64
+ _RefCollectionToListenerType = Dict[
65
+ "weakref.ref[RefCollection[Any]]",
66
+ "weakref.ref[_ListenerFnType]",
67
+ ]
68
+
69
+ _key_to_collection: Dict[_EventKeyTupleType, _RefCollectionToListenerType] = (
70
+ collections.defaultdict(dict)
71
+ )
72
+ """
73
+ Given an original listen() argument, can locate all
74
+ listener collections and the listener fn contained
75
+
76
+ (target, identifier, fn) -> {
77
+ ref(listenercollection) -> ref(listener_fn)
78
+ ref(listenercollection) -> ref(listener_fn)
79
+ ref(listenercollection) -> ref(listener_fn)
80
+ }
81
+ """
82
+
83
+ _ListenerToEventKeyType = Dict[
84
+ "weakref.ref[_ListenerFnType]",
85
+ _EventKeyTupleType,
86
+ ]
87
+ _collection_to_key: Dict[
88
+ weakref.ref[RefCollection[Any]],
89
+ _ListenerToEventKeyType,
90
+ ] = collections.defaultdict(dict)
91
+ """
92
+ Given a _ListenerCollection or _ClsLevelListener, can locate
93
+ all the original listen() arguments and the listener fn contained
94
+
95
+ ref(listenercollection) -> {
96
+ ref(listener_fn) -> (target, identifier, fn),
97
+ ref(listener_fn) -> (target, identifier, fn),
98
+ ref(listener_fn) -> (target, identifier, fn),
99
+ }
100
+ """
101
+
102
+
103
+ def _collection_gced(ref: weakref.ref[Any]) -> None:
104
+ # defaultdict, so can't get a KeyError
105
+ if not _collection_to_key or ref not in _collection_to_key:
106
+ return
107
+
108
+ ref = cast("weakref.ref[RefCollection[EventTarget]]", ref)
109
+
110
+ listener_to_key = _collection_to_key.pop(ref)
111
+ for key in listener_to_key.values():
112
+ if key in _key_to_collection:
113
+ # defaultdict, so can't get a KeyError
114
+ dispatch_reg = _key_to_collection[key]
115
+ dispatch_reg.pop(ref)
116
+ if not dispatch_reg:
117
+ _key_to_collection.pop(key)
118
+
119
+
120
+ def _stored_in_collection(
121
+ event_key: _EventKey[_ET], owner: RefCollection[_ET]
122
+ ) -> bool:
123
+ key = event_key._key
124
+
125
+ dispatch_reg = _key_to_collection[key]
126
+
127
+ owner_ref = owner.ref
128
+ listen_ref = weakref.ref(event_key._listen_fn)
129
+
130
+ if owner_ref in dispatch_reg:
131
+ return False
132
+
133
+ dispatch_reg[owner_ref] = listen_ref
134
+
135
+ listener_to_key = _collection_to_key[owner_ref]
136
+ listener_to_key[listen_ref] = key
137
+
138
+ return True
139
+
140
+
141
+ def _removed_from_collection(
142
+ event_key: _EventKey[_ET], owner: RefCollection[_ET]
143
+ ) -> None:
144
+ key = event_key._key
145
+
146
+ dispatch_reg = _key_to_collection[key]
147
+
148
+ listen_ref = weakref.ref(event_key._listen_fn)
149
+
150
+ owner_ref = owner.ref
151
+ dispatch_reg.pop(owner_ref, None)
152
+ if not dispatch_reg:
153
+ del _key_to_collection[key]
154
+
155
+ if owner_ref in _collection_to_key:
156
+ listener_to_key = _collection_to_key[owner_ref]
157
+ listener_to_key.pop(listen_ref)
158
+
159
+
160
+ def _stored_in_collection_multi(
161
+ newowner: RefCollection[_ET],
162
+ oldowner: RefCollection[_ET],
163
+ elements: Iterable[_ListenerFnType],
164
+ ) -> None:
165
+ if not elements:
166
+ return
167
+
168
+ oldowner_ref = oldowner.ref
169
+ newowner_ref = newowner.ref
170
+
171
+ old_listener_to_key = _collection_to_key[oldowner_ref]
172
+ new_listener_to_key = _collection_to_key[newowner_ref]
173
+
174
+ for listen_fn in elements:
175
+ listen_ref = weakref.ref(listen_fn)
176
+ try:
177
+ key = old_listener_to_key[listen_ref]
178
+ except KeyError:
179
+ # can occur during interpreter shutdown.
180
+ # see #6740
181
+ continue
182
+
183
+ try:
184
+ dispatch_reg = _key_to_collection[key]
185
+ except KeyError:
186
+ continue
187
+
188
+ if newowner_ref in dispatch_reg:
189
+ assert dispatch_reg[newowner_ref] == listen_ref
190
+ else:
191
+ dispatch_reg[newowner_ref] = listen_ref
192
+
193
+ new_listener_to_key[listen_ref] = key
194
+
195
+
196
+ def _clear(
197
+ owner: RefCollection[_ET],
198
+ elements: Iterable[_ListenerFnType],
199
+ ) -> None:
200
+ if not elements:
201
+ return
202
+
203
+ owner_ref = owner.ref
204
+ listener_to_key = _collection_to_key[owner_ref]
205
+ for listen_fn in elements:
206
+ listen_ref = weakref.ref(listen_fn)
207
+ key = listener_to_key[listen_ref]
208
+ dispatch_reg = _key_to_collection[key]
209
+ dispatch_reg.pop(owner_ref, None)
210
+
211
+ if not dispatch_reg:
212
+ del _key_to_collection[key]
213
+
214
+
215
+ class _EventKey(Generic[_ET]):
216
+ """Represent :func:`.listen` arguments."""
217
+
218
+ __slots__ = (
219
+ "target",
220
+ "identifier",
221
+ "fn",
222
+ "fn_key",
223
+ "fn_wrap",
224
+ "dispatch_target",
225
+ )
226
+
227
+ target: _ET
228
+ identifier: str
229
+ fn: _ListenerFnType
230
+ fn_key: _ListenerFnKeyType
231
+ dispatch_target: Any
232
+ _fn_wrap: Optional[_ListenerFnType]
233
+
234
+ def __init__(
235
+ self,
236
+ target: _ET,
237
+ identifier: str,
238
+ fn: _ListenerFnType,
239
+ dispatch_target: Any,
240
+ _fn_wrap: Optional[_ListenerFnType] = None,
241
+ ):
242
+ self.target = target
243
+ self.identifier = identifier
244
+ self.fn = fn
245
+ if isinstance(fn, types.MethodType):
246
+ self.fn_key = id(fn.__func__), id(fn.__self__)
247
+ else:
248
+ self.fn_key = id(fn)
249
+ self.fn_wrap = _fn_wrap
250
+ self.dispatch_target = dispatch_target
251
+
252
+ @property
253
+ def _key(self) -> _EventKeyTupleType:
254
+ return (id(self.target), self.identifier, self.fn_key)
255
+
256
+ def with_wrapper(self, fn_wrap: _ListenerFnType) -> _EventKey[_ET]:
257
+ if fn_wrap is self._listen_fn:
258
+ return self
259
+ else:
260
+ return _EventKey(
261
+ self.target,
262
+ self.identifier,
263
+ self.fn,
264
+ self.dispatch_target,
265
+ _fn_wrap=fn_wrap,
266
+ )
267
+
268
+ def with_dispatch_target(self, dispatch_target: Any) -> _EventKey[_ET]:
269
+ if dispatch_target is self.dispatch_target:
270
+ return self
271
+ else:
272
+ return _EventKey(
273
+ self.target,
274
+ self.identifier,
275
+ self.fn,
276
+ dispatch_target,
277
+ _fn_wrap=self.fn_wrap,
278
+ )
279
+
280
+ def listen(self, *args: Any, **kw: Any) -> None:
281
+ once = kw.pop("once", False)
282
+ once_unless_exception = kw.pop("_once_unless_exception", False)
283
+ named = kw.pop("named", False)
284
+
285
+ target, identifier, fn = (
286
+ self.dispatch_target,
287
+ self.identifier,
288
+ self._listen_fn,
289
+ )
290
+
291
+ dispatch_collection = getattr(target.dispatch, identifier)
292
+
293
+ adjusted_fn = dispatch_collection._adjust_fn_spec(fn, named)
294
+
295
+ self = self.with_wrapper(adjusted_fn)
296
+
297
+ stub_function = getattr(
298
+ self.dispatch_target.dispatch._events, self.identifier
299
+ )
300
+ if hasattr(stub_function, "_sa_warn"):
301
+ stub_function._sa_warn()
302
+
303
+ if once or once_unless_exception:
304
+ self.with_wrapper(
305
+ util.only_once(
306
+ self._listen_fn, retry_on_exception=once_unless_exception
307
+ )
308
+ ).listen(*args, **kw)
309
+ else:
310
+ self.dispatch_target.dispatch._listen(self, *args, **kw)
311
+
312
+ def remove(self) -> None:
313
+ key = self._key
314
+
315
+ if key not in _key_to_collection:
316
+ raise exc.InvalidRequestError(
317
+ "No listeners found for event %s / %r / %s "
318
+ % (self.target, self.identifier, self.fn)
319
+ )
320
+
321
+ dispatch_reg = _key_to_collection.pop(key)
322
+
323
+ for collection_ref, listener_ref in dispatch_reg.items():
324
+ collection = collection_ref()
325
+ listener_fn = listener_ref()
326
+ if collection is not None and listener_fn is not None:
327
+ collection.remove(self.with_wrapper(listener_fn))
328
+
329
+ def contains(self) -> bool:
330
+ """Return True if this event key is registered to listen."""
331
+ return self._key in _key_to_collection
332
+
333
+ def base_listen(
334
+ self,
335
+ propagate: bool = False,
336
+ insert: bool = False,
337
+ named: bool = False,
338
+ retval: Optional[bool] = None,
339
+ asyncio: bool = False,
340
+ ) -> None:
341
+ target, identifier = self.dispatch_target, self.identifier
342
+
343
+ dispatch_collection = getattr(target.dispatch, identifier)
344
+
345
+ for_modify = dispatch_collection.for_modify(target.dispatch)
346
+ if asyncio:
347
+ for_modify._set_asyncio()
348
+
349
+ if insert:
350
+ for_modify.insert(self, propagate)
351
+ else:
352
+ for_modify.append(self, propagate)
353
+
354
+ @property
355
+ def _listen_fn(self) -> _ListenerFnType:
356
+ return self.fn_wrap or self.fn
357
+
358
+ def append_to_list(
359
+ self,
360
+ owner: RefCollection[_ET],
361
+ list_: Deque[_ListenerFnType],
362
+ ) -> bool:
363
+ if _stored_in_collection(self, owner):
364
+ list_.append(self._listen_fn)
365
+ return True
366
+ else:
367
+ return False
368
+
369
+ def remove_from_list(
370
+ self,
371
+ owner: RefCollection[_ET],
372
+ list_: Deque[_ListenerFnType],
373
+ ) -> None:
374
+ _removed_from_collection(self, owner)
375
+ list_.remove(self._listen_fn)
376
+
377
+ def prepend_to_list(
378
+ self,
379
+ owner: RefCollection[_ET],
380
+ list_: Deque[_ListenerFnType],
381
+ ) -> bool:
382
+ if _stored_in_collection(self, owner):
383
+ list_.appendleft(self._listen_fn)
384
+ return True
385
+ else:
386
+ return False
sqlalchemy/events.py ADDED
@@ -0,0 +1,17 @@
1
+ # events.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
+ """Core event interfaces."""
9
+
10
+ from __future__ import annotations
11
+
12
+ from .engine.events import ConnectionEvents
13
+ from .engine.events import DialectEvents
14
+ from .pool import PoolResetState
15
+ from .pool.events import PoolEvents
16
+ from .sql.base import SchemaEventTarget
17
+ from .sql.events import DDLEvents