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,322 @@
1
+ # util/concurrency.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
+ # mypy: allow-untyped-defs, allow-untyped-calls
8
+
9
+ """asyncio-related concurrency functions."""
10
+
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ import sys
15
+ from typing import Any
16
+ from typing import Awaitable
17
+ from typing import Callable
18
+ from typing import Coroutine
19
+ from typing import Literal
20
+ from typing import NoReturn
21
+ from typing import TYPE_CHECKING
22
+ from typing import TypeGuard
23
+ from typing import TypeVar
24
+ from typing import Union
25
+
26
+ from .compat import py311
27
+ from .langhelpers import memoized_property
28
+ from .typing import Self
29
+ from .. import exc
30
+
31
+ _T = TypeVar("_T")
32
+
33
+
34
+ def is_exit_exception(e: BaseException) -> bool:
35
+ # note asyncio.CancelledError is already BaseException
36
+ # so was an exit exception in any case
37
+ return not isinstance(e, Exception) or isinstance(
38
+ e, (asyncio.TimeoutError, asyncio.CancelledError)
39
+ )
40
+
41
+
42
+ _ERROR_MESSAGE = (
43
+ "The SQLAlchemy asyncio module requires that the Python 'greenlet' "
44
+ "library is installed. In order to ensure this dependency is "
45
+ "available, use the 'sqlalchemy[asyncio]' install target: "
46
+ "'pip install sqlalchemy[asyncio]'"
47
+ )
48
+
49
+
50
+ def _not_implemented(*arg: Any, **kw: Any) -> NoReturn:
51
+ raise ImportError(_ERROR_MESSAGE)
52
+
53
+
54
+ class _concurrency_shim_cls:
55
+ """Late import shim for greenlet"""
56
+
57
+ __slots__ = (
58
+ "_has_greenlet",
59
+ "greenlet",
60
+ "_AsyncIoGreenlet",
61
+ "getcurrent",
62
+ )
63
+
64
+ def _initialize(self, *, raise_: bool = True) -> None:
65
+ """Import greenlet and initialize the class"""
66
+ if "greenlet" in globals():
67
+ return
68
+
69
+ if not TYPE_CHECKING:
70
+ global getcurrent, greenlet, _AsyncIoGreenlet
71
+ global _has_gr_context
72
+
73
+ try:
74
+ from greenlet import getcurrent
75
+ from greenlet import greenlet
76
+ except ImportError as e:
77
+ if not TYPE_CHECKING:
78
+ # set greenlet in the global scope to prevent re-init
79
+ greenlet = None
80
+ self._has_greenlet = False
81
+ self._initialize_no_greenlet()
82
+ if raise_:
83
+ raise ImportError(_ERROR_MESSAGE) from e
84
+ else:
85
+ self._has_greenlet = True
86
+ # If greenlet.gr_context is present in current version of greenlet,
87
+ # it will be set with the current context on creation.
88
+ # Refs: https://github.com/python-greenlet/greenlet/pull/198
89
+ _has_gr_context = hasattr(getcurrent(), "gr_context")
90
+
91
+ # implementation based on snaury gist at
92
+ # https://gist.github.com/snaury/202bf4f22c41ca34e56297bae5f33fef
93
+ # Issue for context: https://github.com/python-greenlet/greenlet/issues/173 # noqa: E501
94
+
95
+ class _AsyncIoGreenlet(greenlet):
96
+ dead: bool
97
+
98
+ __sqlalchemy_greenlet_provider__ = True
99
+
100
+ def __init__(self, fn: Callable[..., Any], driver: greenlet):
101
+ greenlet.__init__(self, fn, driver)
102
+ if _has_gr_context:
103
+ self.gr_context = driver.gr_context
104
+
105
+ self.greenlet = greenlet
106
+ self.getcurrent = getcurrent
107
+ self._AsyncIoGreenlet = _AsyncIoGreenlet
108
+
109
+ def _initialize_no_greenlet(self):
110
+ self.getcurrent = _not_implemented
111
+ self.greenlet = _not_implemented # type: ignore[assignment]
112
+ self._AsyncIoGreenlet = _not_implemented # type: ignore[assignment]
113
+
114
+ def __getattr__(self, key: str) -> Any:
115
+ if key in self.__slots__:
116
+ self._initialize()
117
+ return getattr(self, key)
118
+ else:
119
+ raise AttributeError(key)
120
+
121
+
122
+ _concurrency_shim = _concurrency_shim_cls()
123
+
124
+ if TYPE_CHECKING:
125
+ _T_co = TypeVar("_T_co", covariant=True)
126
+
127
+ def iscoroutine(
128
+ awaitable: Awaitable[_T_co],
129
+ ) -> TypeGuard[Coroutine[Any, Any, _T_co]]: ...
130
+
131
+ else:
132
+ iscoroutine = asyncio.iscoroutine
133
+
134
+
135
+ def _safe_cancel_awaitable(awaitable: Awaitable[Any]) -> None:
136
+ # https://docs.python.org/3/reference/datamodel.html#coroutine.close
137
+
138
+ if iscoroutine(awaitable):
139
+ awaitable.close()
140
+
141
+
142
+ def in_greenlet() -> bool:
143
+ current = _concurrency_shim.getcurrent()
144
+ return getattr(current, "__sqlalchemy_greenlet_provider__", False)
145
+
146
+
147
+ def await_(awaitable: Awaitable[_T]) -> _T:
148
+ """Awaits an async function in a sync method.
149
+
150
+ The sync method must be inside a :func:`greenlet_spawn` context.
151
+ :func:`await_` calls cannot be nested.
152
+
153
+ :param awaitable: The coroutine to call.
154
+
155
+ """
156
+ # this is called in the context greenlet while running fn
157
+ current = _concurrency_shim.getcurrent()
158
+ if not getattr(current, "__sqlalchemy_greenlet_provider__", False):
159
+ _safe_cancel_awaitable(awaitable)
160
+
161
+ raise exc.MissingGreenlet(
162
+ "greenlet_spawn has not been called; can't call await_() "
163
+ "here. Was IO attempted in an unexpected place?"
164
+ )
165
+
166
+ # returns the control to the driver greenlet passing it
167
+ # a coroutine to run. Once the awaitable is done, the driver greenlet
168
+ # switches back to this greenlet with the result of awaitable that is
169
+ # then returned to the caller (or raised as error)
170
+ assert current.parent
171
+ return current.parent.switch(awaitable) # type: ignore[no-any-return]
172
+
173
+
174
+ await_only = await_ # old name. deprecated on 2.2
175
+
176
+
177
+ async def greenlet_spawn(
178
+ fn: Callable[..., _T],
179
+ *args: Any,
180
+ _require_await: bool = False,
181
+ **kwargs: Any,
182
+ ) -> _T:
183
+ """Runs a sync function ``fn`` in a new greenlet.
184
+
185
+ The sync function can then use :func:`await_` to wait for async
186
+ functions.
187
+
188
+ :param fn: The sync callable to call.
189
+ :param \\*args: Positional arguments to pass to the ``fn`` callable.
190
+ :param \\*\\*kwargs: Keyword arguments to pass to the ``fn`` callable.
191
+ """
192
+
193
+ result: Any
194
+ context = _concurrency_shim._AsyncIoGreenlet(
195
+ fn, _concurrency_shim.getcurrent()
196
+ )
197
+ # runs the function synchronously in gl greenlet. If the execution
198
+ # is interrupted by await_, context is not dead and result is a
199
+ # coroutine to wait. If the context is dead the function has
200
+ # returned, and its result can be returned.
201
+ switch_occurred = False
202
+
203
+ result = context.switch(*args, **kwargs)
204
+ while not context.dead:
205
+ switch_occurred = True
206
+ try:
207
+ # wait for a coroutine from await_ and then return its
208
+ # result back to it.
209
+ value = await result
210
+ except BaseException:
211
+ # this allows an exception to be raised within
212
+ # the moderated greenlet so that it can continue
213
+ # its expected flow.
214
+ result = context.throw(*sys.exc_info())
215
+ else:
216
+ result = context.switch(value)
217
+
218
+ if _require_await and not switch_occurred:
219
+ raise exc.AwaitRequired(
220
+ "The current operation required an async execution but none was "
221
+ "detected. This will usually happen when using a non compatible "
222
+ "DBAPI driver. Please ensure that an async DBAPI is used."
223
+ )
224
+ return result # type: ignore[no-any-return]
225
+
226
+
227
+ class AsyncAdaptedLock:
228
+ @memoized_property
229
+ def mutex(self) -> asyncio.Lock:
230
+ # there should not be a race here for coroutines creating the
231
+ # new lock as we are not using await, so therefore no concurrency
232
+ return asyncio.Lock()
233
+
234
+ def __enter__(self) -> bool:
235
+ # await is used to acquire the lock only after the first calling
236
+ # coroutine has created the mutex.
237
+ return await_(self.mutex.acquire())
238
+
239
+ def __exit__(self, *arg: Any, **kw: Any) -> None:
240
+ self.mutex.release()
241
+
242
+
243
+ if not TYPE_CHECKING and py311:
244
+ _Runner = asyncio.Runner
245
+ else:
246
+
247
+ class _Runner:
248
+ """Runner implementation for test only"""
249
+
250
+ _loop: Union[None, asyncio.AbstractEventLoop, Literal[False]]
251
+
252
+ def __init__(self) -> None:
253
+ self._loop = None
254
+
255
+ def __enter__(self) -> Self:
256
+ self._lazy_init()
257
+ return self
258
+
259
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
260
+ self.close()
261
+
262
+ def close(self) -> None:
263
+ if self._loop:
264
+ try:
265
+ self._loop.run_until_complete(
266
+ self._loop.shutdown_asyncgens()
267
+ )
268
+ finally:
269
+ self._loop.close()
270
+ self._loop = False
271
+
272
+ def get_loop(self) -> asyncio.AbstractEventLoop:
273
+ """Return embedded event loop."""
274
+ self._lazy_init()
275
+ assert self._loop
276
+ return self._loop
277
+
278
+ def run(self, coro: Coroutine[Any, Any, _T]) -> _T:
279
+ self._lazy_init()
280
+ assert self._loop
281
+ return self._loop.run_until_complete(coro)
282
+
283
+ def _lazy_init(self) -> None:
284
+ if self._loop is False:
285
+ raise RuntimeError("Runner is closed")
286
+ if self._loop is None:
287
+ self._loop = asyncio.new_event_loop()
288
+
289
+
290
+ class _AsyncUtil:
291
+ """Asyncio util for test suite/ util only"""
292
+
293
+ def __init__(self) -> None:
294
+ self.runner = _Runner() # runner it lazy so it can be created here
295
+
296
+ def run(
297
+ self,
298
+ fn: Callable[..., Coroutine[Any, Any, _T]],
299
+ *args: Any,
300
+ **kwargs: Any,
301
+ ) -> _T:
302
+ """Run coroutine on the loop"""
303
+ return self.runner.run(fn(*args, **kwargs))
304
+
305
+ def run_in_greenlet(
306
+ self, fn: Callable[..., _T], *args: Any, **kwargs: Any
307
+ ) -> _T:
308
+ """Run sync function in greenlet. Support nested calls"""
309
+ _concurrency_shim._initialize(raise_=False)
310
+
311
+ if _concurrency_shim._has_greenlet:
312
+ if self.runner.get_loop().is_running():
313
+ # allow for a wrapped test function to call another
314
+ assert in_greenlet()
315
+ return fn(*args, **kwargs)
316
+ else:
317
+ return self.runner.run(greenlet_spawn(fn, *args, **kwargs))
318
+ else:
319
+ return fn(*args, **kwargs)
320
+
321
+ def close(self) -> None:
322
+ self.runner.close()
@@ -0,0 +1,79 @@
1
+ # util/cython.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
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+ from typing import Callable
11
+ from typing import Type
12
+ from typing import TypeVar
13
+
14
+ _T = TypeVar("_T")
15
+ _NO_OP = Callable[[_T], _T]
16
+
17
+ # cython module shims
18
+ # --
19
+ IS_SHIM = True
20
+ # constants
21
+ compiled = False
22
+
23
+ # types
24
+ int = int # noqa: A001
25
+ char = int
26
+ bint = bool
27
+ longlong = int
28
+ ulonglong = int
29
+ Py_ssize_t = int
30
+ uint = int
31
+ float = float # noqa: A001
32
+ double = float
33
+ void = Any
34
+ NULL = None
35
+
36
+
37
+ # functions
38
+ def _no_op(fn: _T) -> _T:
39
+ return fn
40
+
41
+
42
+ cclass = _no_op # equivalent to "cdef class"
43
+ ccall = _no_op # equivalent to "cpdef" function
44
+ cfunc = _no_op # equivalent to "cdef" function
45
+ inline = _no_op
46
+ final = _no_op
47
+ pointer = _no_op # not sure how to express a pointer to a type
48
+
49
+
50
+ def declare(t: Type[_T], value: Any = None, **kw: Any) -> _T:
51
+ return value # type: ignore[no-any-return]
52
+
53
+
54
+ def annotation_typing(_: bool) -> _NO_OP[_T]:
55
+ return _no_op
56
+
57
+
58
+ def exceptval(value: Any = None, *, check: bool = False) -> _NO_OP[_T]:
59
+ return _no_op
60
+
61
+
62
+ def cast(type_: Type[_T], value: Any, *, typecheck: bool = False) -> _T:
63
+ return value # type: ignore[no-any-return]
64
+
65
+
66
+ def returns(_: type) -> _NO_OP[_T]:
67
+ return _no_op
68
+
69
+
70
+ def locals(**kwargs: Any) -> _NO_OP[_T]: # noqa: A001
71
+ return _no_op
72
+
73
+
74
+ def wraparound(value: bool) -> _NO_OP[_T]:
75
+ return _no_op
76
+
77
+
78
+ def boundscheck(value: bool) -> _NO_OP[_T]:
79
+ return _no_op