SQLAlchemy 2.0.47__cp313-cp313t-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 (274) hide show
  1. sqlalchemy/__init__.py +283 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +184 -0
  4. sqlalchemy/connectors/asyncio.py +429 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/cyextension/__init__.py +6 -0
  7. sqlalchemy/cyextension/collections.cp313t-win_amd64.pyd +0 -0
  8. sqlalchemy/cyextension/collections.pyx +409 -0
  9. sqlalchemy/cyextension/immutabledict.cp313t-win_amd64.pyd +0 -0
  10. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  11. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  12. sqlalchemy/cyextension/processors.cp313t-win_amd64.pyd +0 -0
  13. sqlalchemy/cyextension/processors.pyx +68 -0
  14. sqlalchemy/cyextension/resultproxy.cp313t-win_amd64.pyd +0 -0
  15. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  16. sqlalchemy/cyextension/util.cp313t-win_amd64.pyd +0 -0
  17. sqlalchemy/cyextension/util.pyx +90 -0
  18. sqlalchemy/dialects/__init__.py +62 -0
  19. sqlalchemy/dialects/_typing.py +30 -0
  20. sqlalchemy/dialects/mssql/__init__.py +88 -0
  21. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  22. sqlalchemy/dialects/mssql/base.py +4093 -0
  23. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  24. sqlalchemy/dialects/mssql/json.py +129 -0
  25. sqlalchemy/dialects/mssql/provision.py +185 -0
  26. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  27. sqlalchemy/dialects/mssql/pyodbc.py +760 -0
  28. sqlalchemy/dialects/mysql/__init__.py +104 -0
  29. sqlalchemy/dialects/mysql/aiomysql.py +250 -0
  30. sqlalchemy/dialects/mysql/asyncmy.py +231 -0
  31. sqlalchemy/dialects/mysql/base.py +3949 -0
  32. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  33. sqlalchemy/dialects/mysql/dml.py +225 -0
  34. sqlalchemy/dialects/mysql/enumerated.py +282 -0
  35. sqlalchemy/dialects/mysql/expression.py +146 -0
  36. sqlalchemy/dialects/mysql/json.py +91 -0
  37. sqlalchemy/dialects/mysql/mariadb.py +72 -0
  38. sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
  39. sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
  40. sqlalchemy/dialects/mysql/mysqldb.py +314 -0
  41. sqlalchemy/dialects/mysql/provision.py +153 -0
  42. sqlalchemy/dialects/mysql/pymysql.py +158 -0
  43. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  44. sqlalchemy/dialects/mysql/reflection.py +727 -0
  45. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  46. sqlalchemy/dialects/mysql/types.py +835 -0
  47. sqlalchemy/dialects/oracle/__init__.py +81 -0
  48. sqlalchemy/dialects/oracle/base.py +3802 -0
  49. sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
  50. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  51. sqlalchemy/dialects/oracle/oracledb.py +941 -0
  52. sqlalchemy/dialects/oracle/provision.py +297 -0
  53. sqlalchemy/dialects/oracle/types.py +316 -0
  54. sqlalchemy/dialects/oracle/vector.py +365 -0
  55. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  56. sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
  57. sqlalchemy/dialects/postgresql/array.py +519 -0
  58. sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
  59. sqlalchemy/dialects/postgresql/base.py +5378 -0
  60. sqlalchemy/dialects/postgresql/dml.py +339 -0
  61. sqlalchemy/dialects/postgresql/ext.py +540 -0
  62. sqlalchemy/dialects/postgresql/hstore.py +406 -0
  63. sqlalchemy/dialects/postgresql/json.py +404 -0
  64. sqlalchemy/dialects/postgresql/named_types.py +524 -0
  65. sqlalchemy/dialects/postgresql/operators.py +129 -0
  66. sqlalchemy/dialects/postgresql/pg8000.py +669 -0
  67. sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
  68. sqlalchemy/dialects/postgresql/provision.py +183 -0
  69. sqlalchemy/dialects/postgresql/psycopg.py +862 -0
  70. sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
  71. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  72. sqlalchemy/dialects/postgresql/ranges.py +1031 -0
  73. sqlalchemy/dialects/postgresql/types.py +313 -0
  74. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  75. sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
  76. sqlalchemy/dialects/sqlite/base.py +3056 -0
  77. sqlalchemy/dialects/sqlite/dml.py +263 -0
  78. sqlalchemy/dialects/sqlite/json.py +92 -0
  79. sqlalchemy/dialects/sqlite/provision.py +229 -0
  80. sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
  81. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  82. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  83. sqlalchemy/engine/__init__.py +62 -0
  84. sqlalchemy/engine/_py_processors.py +136 -0
  85. sqlalchemy/engine/_py_row.py +128 -0
  86. sqlalchemy/engine/_py_util.py +74 -0
  87. sqlalchemy/engine/base.py +3390 -0
  88. sqlalchemy/engine/characteristics.py +155 -0
  89. sqlalchemy/engine/create.py +893 -0
  90. sqlalchemy/engine/cursor.py +2298 -0
  91. sqlalchemy/engine/default.py +2394 -0
  92. sqlalchemy/engine/events.py +965 -0
  93. sqlalchemy/engine/interfaces.py +3471 -0
  94. sqlalchemy/engine/mock.py +134 -0
  95. sqlalchemy/engine/processors.py +61 -0
  96. sqlalchemy/engine/reflection.py +2102 -0
  97. sqlalchemy/engine/result.py +2399 -0
  98. sqlalchemy/engine/row.py +400 -0
  99. sqlalchemy/engine/strategies.py +16 -0
  100. sqlalchemy/engine/url.py +924 -0
  101. sqlalchemy/engine/util.py +167 -0
  102. sqlalchemy/event/__init__.py +26 -0
  103. sqlalchemy/event/api.py +220 -0
  104. sqlalchemy/event/attr.py +676 -0
  105. sqlalchemy/event/base.py +472 -0
  106. sqlalchemy/event/legacy.py +258 -0
  107. sqlalchemy/event/registry.py +390 -0
  108. sqlalchemy/events.py +17 -0
  109. sqlalchemy/exc.py +832 -0
  110. sqlalchemy/ext/__init__.py +11 -0
  111. sqlalchemy/ext/associationproxy.py +2027 -0
  112. sqlalchemy/ext/asyncio/__init__.py +25 -0
  113. sqlalchemy/ext/asyncio/base.py +281 -0
  114. sqlalchemy/ext/asyncio/engine.py +1471 -0
  115. sqlalchemy/ext/asyncio/exc.py +21 -0
  116. sqlalchemy/ext/asyncio/result.py +965 -0
  117. sqlalchemy/ext/asyncio/scoping.py +1599 -0
  118. sqlalchemy/ext/asyncio/session.py +1947 -0
  119. sqlalchemy/ext/automap.py +1701 -0
  120. sqlalchemy/ext/baked.py +570 -0
  121. sqlalchemy/ext/compiler.py +600 -0
  122. sqlalchemy/ext/declarative/__init__.py +65 -0
  123. sqlalchemy/ext/declarative/extensions.py +564 -0
  124. sqlalchemy/ext/horizontal_shard.py +478 -0
  125. sqlalchemy/ext/hybrid.py +1535 -0
  126. sqlalchemy/ext/indexable.py +364 -0
  127. sqlalchemy/ext/instrumentation.py +450 -0
  128. sqlalchemy/ext/mutable.py +1085 -0
  129. sqlalchemy/ext/mypy/__init__.py +6 -0
  130. sqlalchemy/ext/mypy/apply.py +324 -0
  131. sqlalchemy/ext/mypy/decl_class.py +515 -0
  132. sqlalchemy/ext/mypy/infer.py +590 -0
  133. sqlalchemy/ext/mypy/names.py +335 -0
  134. sqlalchemy/ext/mypy/plugin.py +303 -0
  135. sqlalchemy/ext/mypy/util.py +357 -0
  136. sqlalchemy/ext/orderinglist.py +439 -0
  137. sqlalchemy/ext/serializer.py +185 -0
  138. sqlalchemy/future/__init__.py +16 -0
  139. sqlalchemy/future/engine.py +15 -0
  140. sqlalchemy/inspection.py +174 -0
  141. sqlalchemy/log.py +288 -0
  142. sqlalchemy/orm/__init__.py +171 -0
  143. sqlalchemy/orm/_orm_constructors.py +2661 -0
  144. sqlalchemy/orm/_typing.py +179 -0
  145. sqlalchemy/orm/attributes.py +2845 -0
  146. sqlalchemy/orm/base.py +971 -0
  147. sqlalchemy/orm/bulk_persistence.py +2135 -0
  148. sqlalchemy/orm/clsregistry.py +571 -0
  149. sqlalchemy/orm/collections.py +1627 -0
  150. sqlalchemy/orm/context.py +3334 -0
  151. sqlalchemy/orm/decl_api.py +2004 -0
  152. sqlalchemy/orm/decl_base.py +2192 -0
  153. sqlalchemy/orm/dependency.py +1302 -0
  154. sqlalchemy/orm/descriptor_props.py +1092 -0
  155. sqlalchemy/orm/dynamic.py +300 -0
  156. sqlalchemy/orm/evaluator.py +379 -0
  157. sqlalchemy/orm/events.py +3252 -0
  158. sqlalchemy/orm/exc.py +237 -0
  159. sqlalchemy/orm/identity.py +302 -0
  160. sqlalchemy/orm/instrumentation.py +754 -0
  161. sqlalchemy/orm/interfaces.py +1496 -0
  162. sqlalchemy/orm/loading.py +1686 -0
  163. sqlalchemy/orm/mapped_collection.py +557 -0
  164. sqlalchemy/orm/mapper.py +4444 -0
  165. sqlalchemy/orm/path_registry.py +809 -0
  166. sqlalchemy/orm/persistence.py +1788 -0
  167. sqlalchemy/orm/properties.py +935 -0
  168. sqlalchemy/orm/query.py +3459 -0
  169. sqlalchemy/orm/relationships.py +3508 -0
  170. sqlalchemy/orm/scoping.py +2148 -0
  171. sqlalchemy/orm/session.py +5280 -0
  172. sqlalchemy/orm/state.py +1168 -0
  173. sqlalchemy/orm/state_changes.py +196 -0
  174. sqlalchemy/orm/strategies.py +3470 -0
  175. sqlalchemy/orm/strategy_options.py +2568 -0
  176. sqlalchemy/orm/sync.py +164 -0
  177. sqlalchemy/orm/unitofwork.py +796 -0
  178. sqlalchemy/orm/util.py +2403 -0
  179. sqlalchemy/orm/writeonly.py +674 -0
  180. sqlalchemy/pool/__init__.py +44 -0
  181. sqlalchemy/pool/base.py +1524 -0
  182. sqlalchemy/pool/events.py +375 -0
  183. sqlalchemy/pool/impl.py +588 -0
  184. sqlalchemy/py.typed +0 -0
  185. sqlalchemy/schema.py +69 -0
  186. sqlalchemy/sql/__init__.py +145 -0
  187. sqlalchemy/sql/_dml_constructors.py +132 -0
  188. sqlalchemy/sql/_elements_constructors.py +1872 -0
  189. sqlalchemy/sql/_orm_types.py +20 -0
  190. sqlalchemy/sql/_py_util.py +75 -0
  191. sqlalchemy/sql/_selectable_constructors.py +763 -0
  192. sqlalchemy/sql/_typing.py +482 -0
  193. sqlalchemy/sql/annotation.py +587 -0
  194. sqlalchemy/sql/base.py +2293 -0
  195. sqlalchemy/sql/cache_key.py +1057 -0
  196. sqlalchemy/sql/coercions.py +1404 -0
  197. sqlalchemy/sql/compiler.py +8081 -0
  198. sqlalchemy/sql/crud.py +1752 -0
  199. sqlalchemy/sql/ddl.py +1444 -0
  200. sqlalchemy/sql/default_comparator.py +551 -0
  201. sqlalchemy/sql/dml.py +1850 -0
  202. sqlalchemy/sql/elements.py +5589 -0
  203. sqlalchemy/sql/events.py +458 -0
  204. sqlalchemy/sql/expression.py +159 -0
  205. sqlalchemy/sql/functions.py +2158 -0
  206. sqlalchemy/sql/lambdas.py +1442 -0
  207. sqlalchemy/sql/naming.py +209 -0
  208. sqlalchemy/sql/operators.py +2623 -0
  209. sqlalchemy/sql/roles.py +323 -0
  210. sqlalchemy/sql/schema.py +6222 -0
  211. sqlalchemy/sql/selectable.py +7265 -0
  212. sqlalchemy/sql/sqltypes.py +3930 -0
  213. sqlalchemy/sql/traversals.py +1024 -0
  214. sqlalchemy/sql/type_api.py +2368 -0
  215. sqlalchemy/sql/util.py +1485 -0
  216. sqlalchemy/sql/visitors.py +1164 -0
  217. sqlalchemy/testing/__init__.py +96 -0
  218. sqlalchemy/testing/assertions.py +994 -0
  219. sqlalchemy/testing/assertsql.py +520 -0
  220. sqlalchemy/testing/asyncio.py +135 -0
  221. sqlalchemy/testing/config.py +434 -0
  222. sqlalchemy/testing/engines.py +483 -0
  223. sqlalchemy/testing/entities.py +117 -0
  224. sqlalchemy/testing/exclusions.py +476 -0
  225. sqlalchemy/testing/fixtures/__init__.py +28 -0
  226. sqlalchemy/testing/fixtures/base.py +384 -0
  227. sqlalchemy/testing/fixtures/mypy.py +332 -0
  228. sqlalchemy/testing/fixtures/orm.py +227 -0
  229. sqlalchemy/testing/fixtures/sql.py +482 -0
  230. sqlalchemy/testing/pickleable.py +155 -0
  231. sqlalchemy/testing/plugin/__init__.py +6 -0
  232. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  233. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  234. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  235. sqlalchemy/testing/profiling.py +329 -0
  236. sqlalchemy/testing/provision.py +603 -0
  237. sqlalchemy/testing/requirements.py +1945 -0
  238. sqlalchemy/testing/schema.py +198 -0
  239. sqlalchemy/testing/suite/__init__.py +19 -0
  240. sqlalchemy/testing/suite/test_cte.py +237 -0
  241. sqlalchemy/testing/suite/test_ddl.py +389 -0
  242. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  243. sqlalchemy/testing/suite/test_dialect.py +776 -0
  244. sqlalchemy/testing/suite/test_insert.py +630 -0
  245. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  246. sqlalchemy/testing/suite/test_results.py +504 -0
  247. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  248. sqlalchemy/testing/suite/test_select.py +2010 -0
  249. sqlalchemy/testing/suite/test_sequence.py +317 -0
  250. sqlalchemy/testing/suite/test_types.py +2147 -0
  251. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  252. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  253. sqlalchemy/testing/util.py +535 -0
  254. sqlalchemy/testing/warnings.py +52 -0
  255. sqlalchemy/types.py +74 -0
  256. sqlalchemy/util/__init__.py +162 -0
  257. sqlalchemy/util/_collections.py +712 -0
  258. sqlalchemy/util/_concurrency_py3k.py +288 -0
  259. sqlalchemy/util/_has_cy.py +40 -0
  260. sqlalchemy/util/_py_collections.py +541 -0
  261. sqlalchemy/util/compat.py +421 -0
  262. sqlalchemy/util/concurrency.py +110 -0
  263. sqlalchemy/util/deprecations.py +401 -0
  264. sqlalchemy/util/langhelpers.py +2203 -0
  265. sqlalchemy/util/preloaded.py +150 -0
  266. sqlalchemy/util/queue.py +322 -0
  267. sqlalchemy/util/tool_support.py +201 -0
  268. sqlalchemy/util/topological.py +120 -0
  269. sqlalchemy/util/typing.py +734 -0
  270. sqlalchemy-2.0.47.dist-info/METADATA +243 -0
  271. sqlalchemy-2.0.47.dist-info/RECORD +274 -0
  272. sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
  273. sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
  274. sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
@@ -0,0 +1,25 @@
1
+ # ext/asyncio/__init__.py
2
+ # Copyright (C) 2020-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 .engine import async_engine_from_config as async_engine_from_config
9
+ from .engine import AsyncConnection as AsyncConnection
10
+ from .engine import AsyncEngine as AsyncEngine
11
+ from .engine import AsyncTransaction as AsyncTransaction
12
+ from .engine import create_async_engine as create_async_engine
13
+ from .engine import create_async_pool_from_url as create_async_pool_from_url
14
+ from .result import AsyncMappingResult as AsyncMappingResult
15
+ from .result import AsyncResult as AsyncResult
16
+ from .result import AsyncScalarResult as AsyncScalarResult
17
+ from .result import AsyncTupleResult as AsyncTupleResult
18
+ from .scoping import async_scoped_session as async_scoped_session
19
+ from .session import async_object_session as async_object_session
20
+ from .session import async_session as async_session
21
+ from .session import async_sessionmaker as async_sessionmaker
22
+ from .session import AsyncAttrs as AsyncAttrs
23
+ from .session import AsyncSession as AsyncSession
24
+ from .session import AsyncSessionTransaction as AsyncSessionTransaction
25
+ from .session import close_all_sessions as close_all_sessions
@@ -0,0 +1,281 @@
1
+ # ext/asyncio/base.py
2
+ # Copyright (C) 2020-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
+ import abc
11
+ import functools
12
+ from typing import Any
13
+ from typing import AsyncGenerator
14
+ from typing import AsyncIterator
15
+ from typing import Awaitable
16
+ from typing import Callable
17
+ from typing import ClassVar
18
+ from typing import Dict
19
+ from typing import Generator
20
+ from typing import Generic
21
+ from typing import NoReturn
22
+ from typing import Optional
23
+ from typing import overload
24
+ from typing import Tuple
25
+ from typing import TypeVar
26
+ import weakref
27
+
28
+ from . import exc as async_exc
29
+ from ... import util
30
+ from ...util.typing import Literal
31
+ from ...util.typing import Self
32
+
33
+ _T = TypeVar("_T", bound=Any)
34
+ _T_co = TypeVar("_T_co", bound=Any, covariant=True)
35
+
36
+
37
+ _PT = TypeVar("_PT", bound=Any)
38
+
39
+
40
+ class ReversibleProxy(Generic[_PT]):
41
+ _proxy_objects: ClassVar[
42
+ Dict[weakref.ref[Any], weakref.ref[ReversibleProxy[Any]]]
43
+ ] = {}
44
+ __slots__ = ("__weakref__",)
45
+
46
+ @overload
47
+ def _assign_proxied(self, target: _PT) -> _PT: ...
48
+
49
+ @overload
50
+ def _assign_proxied(self, target: None) -> None: ...
51
+
52
+ def _assign_proxied(self, target: Optional[_PT]) -> Optional[_PT]:
53
+ if target is not None:
54
+ target_ref: weakref.ref[_PT] = weakref.ref(
55
+ target, ReversibleProxy._target_gced
56
+ )
57
+ proxy_ref = weakref.ref(
58
+ self,
59
+ functools.partial(ReversibleProxy._target_gced, target_ref),
60
+ )
61
+ ReversibleProxy._proxy_objects[target_ref] = proxy_ref
62
+
63
+ return target
64
+
65
+ @classmethod
66
+ def _target_gced(
67
+ cls,
68
+ ref: weakref.ref[_PT],
69
+ proxy_ref: Optional[weakref.ref[Self]] = None, # noqa: U100
70
+ ) -> None:
71
+ cls._proxy_objects.pop(ref, None)
72
+
73
+ @classmethod
74
+ def _regenerate_proxy_for_target(
75
+ cls, target: _PT, **additional_kw: Any
76
+ ) -> Self:
77
+ raise NotImplementedError()
78
+
79
+ @overload
80
+ @classmethod
81
+ def _retrieve_proxy_for_target(
82
+ cls, target: _PT, regenerate: Literal[True] = ..., **additional_kw: Any
83
+ ) -> Self: ...
84
+
85
+ @overload
86
+ @classmethod
87
+ def _retrieve_proxy_for_target(
88
+ cls, target: _PT, regenerate: bool = True, **additional_kw: Any
89
+ ) -> Optional[Self]: ...
90
+
91
+ @classmethod
92
+ def _retrieve_proxy_for_target(
93
+ cls, target: _PT, regenerate: bool = True, **additional_kw: Any
94
+ ) -> Optional[Self]:
95
+ try:
96
+ proxy_ref = cls._proxy_objects[weakref.ref(target)]
97
+ except KeyError:
98
+ pass
99
+ else:
100
+ proxy = proxy_ref()
101
+ if proxy is not None:
102
+ return proxy # type: ignore
103
+
104
+ if regenerate:
105
+ return cls._regenerate_proxy_for_target(target, **additional_kw)
106
+ else:
107
+ return None
108
+
109
+
110
+ class StartableContext(Awaitable[_T_co], abc.ABC):
111
+ __slots__ = ()
112
+
113
+ @abc.abstractmethod
114
+ async def start(self, is_ctxmanager: bool = False) -> _T_co:
115
+ raise NotImplementedError()
116
+
117
+ def __await__(self) -> Generator[Any, Any, _T_co]:
118
+ return self.start().__await__()
119
+
120
+ async def __aenter__(self) -> _T_co:
121
+ return await self.start(is_ctxmanager=True)
122
+
123
+ @abc.abstractmethod
124
+ async def __aexit__(
125
+ self, type_: Any, value: Any, traceback: Any
126
+ ) -> Optional[bool]:
127
+ pass
128
+
129
+ def _raise_for_not_started(self) -> NoReturn:
130
+ raise async_exc.AsyncContextNotStarted(
131
+ "%s context has not been started and object has not been awaited."
132
+ % (self.__class__.__name__)
133
+ )
134
+
135
+
136
+ class GeneratorStartableContext(StartableContext[_T_co]):
137
+ __slots__ = ("gen",)
138
+
139
+ gen: AsyncGenerator[_T_co, Any]
140
+
141
+ def __init__(
142
+ self,
143
+ func: Callable[..., AsyncIterator[_T_co]],
144
+ args: Tuple[Any, ...],
145
+ kwds: Dict[str, Any],
146
+ ):
147
+ self.gen = func(*args, **kwds) # type: ignore
148
+
149
+ async def start(self, is_ctxmanager: bool = False) -> _T_co:
150
+ try:
151
+ start_value = await util.anext_(self.gen)
152
+ except StopAsyncIteration:
153
+ raise RuntimeError("generator didn't yield") from None
154
+
155
+ # if not a context manager, then interrupt the generator, don't
156
+ # let it complete. this step is technically not needed, as the
157
+ # generator will close in any case at gc time. not clear if having
158
+ # this here is a good idea or not (though it helps for clarity IMO)
159
+ if not is_ctxmanager:
160
+ await self.gen.aclose()
161
+
162
+ return start_value
163
+
164
+ async def __aexit__(
165
+ self, typ: Any, value: Any, traceback: Any
166
+ ) -> Optional[bool]:
167
+ # vendored from contextlib.py
168
+ if typ is None:
169
+ try:
170
+ await util.anext_(self.gen)
171
+ except StopAsyncIteration:
172
+ return False
173
+ else:
174
+ raise RuntimeError("generator didn't stop")
175
+ else:
176
+ if value is None:
177
+ # Need to force instantiation so we can reliably
178
+ # tell if we get the same exception back
179
+ value = typ()
180
+ try:
181
+ await self.gen.athrow(value)
182
+ except StopAsyncIteration as exc:
183
+ # Suppress StopIteration *unless* it's the same exception that
184
+ # was passed to throw(). This prevents a StopIteration
185
+ # raised inside the "with" statement from being suppressed.
186
+ return exc is not value
187
+ except RuntimeError as exc:
188
+ # Don't re-raise the passed in exception. (issue27122)
189
+ if exc is value:
190
+ return False
191
+ # Avoid suppressing if a Stop(Async)Iteration exception
192
+ # was passed to athrow() and later wrapped into a RuntimeError
193
+ # (see PEP 479 for sync generators; async generators also
194
+ # have this behavior). But do this only if the exception
195
+ # wrapped
196
+ # by the RuntimeError is actually Stop(Async)Iteration (see
197
+ # issue29692).
198
+ if (
199
+ isinstance(value, (StopIteration, StopAsyncIteration))
200
+ and exc.__cause__ is value
201
+ ):
202
+ return False
203
+ raise
204
+ except BaseException as exc:
205
+ # only re-raise if it's *not* the exception that was
206
+ # passed to throw(), because __exit__() must not raise
207
+ # an exception unless __exit__() itself failed. But throw()
208
+ # has to raise the exception to signal propagation, so this
209
+ # fixes the impedance mismatch between the throw() protocol
210
+ # and the __exit__() protocol.
211
+ if exc is not value:
212
+ raise
213
+ return False
214
+ raise RuntimeError("generator didn't stop after athrow()")
215
+
216
+
217
+ def asyncstartablecontext(
218
+ func: Callable[..., AsyncIterator[_T_co]],
219
+ ) -> Callable[..., GeneratorStartableContext[_T_co]]:
220
+ """@asyncstartablecontext decorator.
221
+
222
+ the decorated function can be called either as ``async with fn()``, **or**
223
+ ``await fn()``. This is decidedly different from what
224
+ ``@contextlib.asynccontextmanager`` supports, and the usage pattern
225
+ is different as well.
226
+
227
+ Typical usage:
228
+
229
+ .. sourcecode:: text
230
+
231
+ @asyncstartablecontext
232
+ async def some_async_generator(<arguments>):
233
+ <setup>
234
+ try:
235
+ yield <value>
236
+ except GeneratorExit:
237
+ # return value was awaited, no context manager is present
238
+ # and caller will .close() the resource explicitly
239
+ pass
240
+ else:
241
+ <context manager cleanup>
242
+
243
+
244
+ Above, ``GeneratorExit`` is caught if the function were used as an
245
+ ``await``. In this case, it's essential that the cleanup does **not**
246
+ occur, so there should not be a ``finally`` block.
247
+
248
+ If ``GeneratorExit`` is not invoked, this means we're in ``__aexit__``
249
+ and we were invoked as a context manager, and cleanup should proceed.
250
+
251
+
252
+ """
253
+
254
+ @functools.wraps(func)
255
+ def helper(*args: Any, **kwds: Any) -> GeneratorStartableContext[_T_co]:
256
+ return GeneratorStartableContext(func, args, kwds)
257
+
258
+ return helper
259
+
260
+
261
+ class ProxyComparable(ReversibleProxy[_PT]):
262
+ __slots__ = ()
263
+
264
+ @util.ro_non_memoized_property
265
+ def _proxied(self) -> _PT:
266
+ raise NotImplementedError()
267
+
268
+ def __hash__(self) -> int:
269
+ return id(self)
270
+
271
+ def __eq__(self, other: Any) -> bool:
272
+ return (
273
+ isinstance(other, self.__class__)
274
+ and self._proxied == other._proxied
275
+ )
276
+
277
+ def __ne__(self, other: Any) -> bool:
278
+ return (
279
+ not isinstance(other, self.__class__)
280
+ or self._proxied != other._proxied
281
+ )