SQLAlchemy 2.0.47__cp313-cp313t-win32.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-win32.pyd +0 -0
  8. sqlalchemy/cyextension/collections.pyx +409 -0
  9. sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
  10. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  11. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  12. sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
  13. sqlalchemy/cyextension/processors.pyx +68 -0
  14. sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
  15. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  16. sqlalchemy/cyextension/util.cp313t-win32.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,401 @@
1
+ # util/deprecations.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
+ """Helpers related to deprecation of functions, methods, classes, other
10
+ functionality."""
11
+
12
+ from __future__ import annotations
13
+
14
+ import re
15
+ from typing import Any
16
+ from typing import Callable
17
+ from typing import Dict
18
+ from typing import Match
19
+ from typing import Optional
20
+ from typing import Sequence
21
+ from typing import Set
22
+ from typing import Tuple
23
+ from typing import Type
24
+ from typing import TypeVar
25
+ from typing import Union
26
+
27
+ from . import compat
28
+ from .langhelpers import _hash_limit_string
29
+ from .langhelpers import _warnings_warn
30
+ from .langhelpers import decorator
31
+ from .langhelpers import inject_docstring_text
32
+ from .langhelpers import inject_param_text
33
+ from .. import exc
34
+
35
+ _T = TypeVar("_T", bound=Any)
36
+
37
+
38
+ # https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
39
+ _F = TypeVar("_F", bound="Callable[..., Any]")
40
+
41
+
42
+ def _warn_with_version(
43
+ msg: str,
44
+ version: str,
45
+ type_: Type[exc.SADeprecationWarning],
46
+ stacklevel: int,
47
+ code: Optional[str] = None,
48
+ ) -> None:
49
+ warn = type_(msg, code=code)
50
+ warn.deprecated_since = version
51
+
52
+ _warnings_warn(warn, stacklevel=stacklevel + 1)
53
+
54
+
55
+ def warn_deprecated(
56
+ msg: str, version: str, stacklevel: int = 3, code: Optional[str] = None
57
+ ) -> None:
58
+ _warn_with_version(
59
+ msg, version, exc.SADeprecationWarning, stacklevel, code=code
60
+ )
61
+
62
+
63
+ def warn_deprecated_limited(
64
+ msg: str,
65
+ args: Sequence[Any],
66
+ version: str,
67
+ stacklevel: int = 3,
68
+ code: Optional[str] = None,
69
+ ) -> None:
70
+ """Issue a deprecation warning with a parameterized string,
71
+ limiting the number of registrations.
72
+
73
+ """
74
+ if args:
75
+ msg = _hash_limit_string(msg, 10, args)
76
+ _warn_with_version(
77
+ msg, version, exc.SADeprecationWarning, stacklevel, code=code
78
+ )
79
+
80
+
81
+ def deprecated_cls(
82
+ version: str, message: str, constructor: Optional[str] = "__init__"
83
+ ) -> Callable[[Type[_T]], Type[_T]]:
84
+ header = ".. deprecated:: %s %s" % (version, (message or ""))
85
+
86
+ def decorate(cls: Type[_T]) -> Type[_T]:
87
+ return _decorate_cls_with_warning(
88
+ cls,
89
+ constructor,
90
+ exc.SADeprecationWarning,
91
+ message % dict(func=constructor),
92
+ version,
93
+ header,
94
+ )
95
+
96
+ return decorate
97
+
98
+
99
+ def deprecated(
100
+ version: str,
101
+ message: Optional[str] = None,
102
+ add_deprecation_to_docstring: bool = True,
103
+ warning: Optional[Type[exc.SADeprecationWarning]] = None,
104
+ enable_warnings: bool = True,
105
+ ) -> Callable[[_F], _F]:
106
+ """Decorates a function and issues a deprecation warning on use.
107
+
108
+ :param version:
109
+ Issue version in the warning.
110
+
111
+ :param message:
112
+ If provided, issue message in the warning. A sensible default
113
+ is used if not provided.
114
+
115
+ :param add_deprecation_to_docstring:
116
+ Default True. If False, the wrapped function's __doc__ is left
117
+ as-is. If True, the 'message' is prepended to the docs if
118
+ provided, or sensible default if message is omitted.
119
+
120
+ """
121
+
122
+ if add_deprecation_to_docstring:
123
+ header = ".. deprecated:: %s %s" % (
124
+ version,
125
+ (message or ""),
126
+ )
127
+ else:
128
+ header = None
129
+
130
+ if message is None:
131
+ message = "Call to deprecated function %(func)s"
132
+
133
+ if warning is None:
134
+ warning = exc.SADeprecationWarning
135
+
136
+ message += " (deprecated since: %s)" % version
137
+
138
+ def decorate(fn: _F) -> _F:
139
+ assert message is not None
140
+ assert warning is not None
141
+ return _decorate_with_warning(
142
+ fn,
143
+ warning,
144
+ message % dict(func=fn.__name__),
145
+ version,
146
+ header,
147
+ enable_warnings=enable_warnings,
148
+ )
149
+
150
+ return decorate
151
+
152
+
153
+ def moved_20(
154
+ message: str, **kw: Any
155
+ ) -> Callable[[Callable[..., _T]], Callable[..., _T]]:
156
+ return deprecated(
157
+ "2.0", message=message, warning=exc.MovedIn20Warning, **kw
158
+ )
159
+
160
+
161
+ def became_legacy_20(
162
+ api_name: str, alternative: Optional[str] = None, **kw: Any
163
+ ) -> Callable[[_F], _F]:
164
+ type_reg = re.match("^:(attr|func|meth):", api_name)
165
+ if type_reg:
166
+ type_ = {"attr": "attribute", "func": "function", "meth": "method"}[
167
+ type_reg.group(1)
168
+ ]
169
+ else:
170
+ type_ = "construct"
171
+ message = (
172
+ "The %s %s is considered legacy as of the "
173
+ "1.x series of SQLAlchemy and %s in 2.0."
174
+ % (
175
+ api_name,
176
+ type_,
177
+ "becomes a legacy construct",
178
+ )
179
+ )
180
+
181
+ if ":attr:" in api_name:
182
+ attribute_ok = kw.pop("warn_on_attribute_access", False)
183
+ if not attribute_ok:
184
+ assert kw.get("enable_warnings") is False, (
185
+ "attribute %s will emit a warning on read access. "
186
+ "If you *really* want this, "
187
+ "add warn_on_attribute_access=True. Otherwise please add "
188
+ "enable_warnings=False." % api_name
189
+ )
190
+
191
+ if alternative:
192
+ message += " " + alternative
193
+
194
+ warning_cls = exc.LegacyAPIWarning
195
+
196
+ return deprecated("2.0", message=message, warning=warning_cls, **kw)
197
+
198
+
199
+ def deprecated_params(**specs: Tuple[str, str]) -> Callable[[_F], _F]:
200
+ """Decorates a function to warn on use of certain parameters.
201
+
202
+ e.g. ::
203
+
204
+ @deprecated_params(
205
+ weak_identity_map=(
206
+ "0.7",
207
+ "the :paramref:`.Session.weak_identity_map parameter "
208
+ "is deprecated.",
209
+ )
210
+ )
211
+ def some_function(**kwargs): ...
212
+
213
+ """
214
+
215
+ messages: Dict[str, str] = {}
216
+ versions: Dict[str, str] = {}
217
+ version_warnings: Dict[str, Type[exc.SADeprecationWarning]] = {}
218
+
219
+ for param, (version, message) in specs.items():
220
+ versions[param] = version
221
+ messages[param] = _sanitize_restructured_text(message)
222
+ version_warnings[param] = exc.SADeprecationWarning
223
+
224
+ def decorate(fn: _F) -> _F:
225
+ spec = compat.inspect_getfullargspec(fn)
226
+
227
+ check_defaults: Union[Set[str], Tuple[()]]
228
+ if spec.defaults is not None:
229
+ defaults = dict(
230
+ zip(
231
+ spec.args[(len(spec.args) - len(spec.defaults)) :],
232
+ spec.defaults,
233
+ )
234
+ )
235
+ check_defaults = set(defaults).intersection(messages)
236
+ check_kw = set(messages).difference(defaults)
237
+ elif spec.kwonlydefaults is not None:
238
+ defaults = spec.kwonlydefaults
239
+ check_defaults = set(defaults).intersection(messages)
240
+ check_kw = set(messages).difference(defaults)
241
+ else:
242
+ check_defaults = ()
243
+ check_kw = set(messages)
244
+
245
+ check_any_kw = spec.varkw
246
+
247
+ # latest mypy has opinions here, not sure if they implemented
248
+ # Concatenate or something
249
+ @decorator
250
+ def warned(fn: _F, *args: Any, **kwargs: Any) -> _F:
251
+ for m in check_defaults:
252
+ if (defaults[m] is None and kwargs[m] is not None) or (
253
+ defaults[m] is not None and kwargs[m] != defaults[m]
254
+ ):
255
+ _warn_with_version(
256
+ messages[m],
257
+ versions[m],
258
+ version_warnings[m],
259
+ stacklevel=3,
260
+ )
261
+
262
+ if check_any_kw in messages and set(kwargs).difference(
263
+ check_defaults
264
+ ):
265
+ assert check_any_kw is not None
266
+ _warn_with_version(
267
+ messages[check_any_kw],
268
+ versions[check_any_kw],
269
+ version_warnings[check_any_kw],
270
+ stacklevel=3,
271
+ )
272
+
273
+ for m in check_kw:
274
+ if m in kwargs:
275
+ _warn_with_version(
276
+ messages[m],
277
+ versions[m],
278
+ version_warnings[m],
279
+ stacklevel=3,
280
+ )
281
+ return fn(*args, **kwargs) # type: ignore[no-any-return]
282
+
283
+ doc = fn.__doc__ is not None and fn.__doc__ or ""
284
+ if doc:
285
+ doc = inject_param_text(
286
+ doc,
287
+ {
288
+ param: ".. deprecated:: %s %s"
289
+ % ("1.4" if version == "2.0" else version, (message or ""))
290
+ for param, (version, message) in specs.items()
291
+ },
292
+ )
293
+ decorated = warned(fn)
294
+ decorated.__doc__ = doc
295
+ return decorated
296
+
297
+ return decorate
298
+
299
+
300
+ def _sanitize_restructured_text(text: str) -> str:
301
+ def repl(m: Match[str]) -> str:
302
+ type_, name = m.group(1, 2)
303
+ if type_ in ("func", "meth"):
304
+ name += "()"
305
+ return name
306
+
307
+ text = re.sub(r":ref:`(.+) <.*>`", lambda m: '"%s"' % m.group(1), text)
308
+ return re.sub(r"\:(\w+)\:`~?(?:_\w+)?\.?(.+?)`", repl, text)
309
+
310
+
311
+ def _decorate_cls_with_warning(
312
+ cls: Type[_T],
313
+ constructor: Optional[str],
314
+ wtype: Type[exc.SADeprecationWarning],
315
+ message: str,
316
+ version: str,
317
+ docstring_header: Optional[str] = None,
318
+ ) -> Type[_T]:
319
+ doc = cls.__doc__ is not None and cls.__doc__ or ""
320
+ if docstring_header is not None:
321
+ if constructor is not None:
322
+ docstring_header %= dict(func=constructor)
323
+
324
+ if issubclass(wtype, exc.Base20DeprecationWarning):
325
+ docstring_header += (
326
+ " (Background on SQLAlchemy 2.0 at: "
327
+ ":ref:`migration_20_toplevel`)"
328
+ )
329
+ doc = inject_docstring_text(doc, docstring_header, 1)
330
+
331
+ constructor_fn = None
332
+ if type(cls) is type:
333
+ clsdict = dict(cls.__dict__)
334
+ clsdict["__doc__"] = doc
335
+ clsdict.pop("__dict__", None)
336
+ clsdict.pop("__weakref__", None)
337
+ cls = type(cls.__name__, cls.__bases__, clsdict)
338
+ if constructor is not None:
339
+ constructor_fn = clsdict[constructor]
340
+
341
+ else:
342
+ cls.__doc__ = doc
343
+ if constructor is not None:
344
+ constructor_fn = getattr(cls, constructor)
345
+
346
+ if constructor is not None:
347
+ assert constructor_fn is not None
348
+ assert wtype is not None
349
+ setattr(
350
+ cls,
351
+ constructor,
352
+ _decorate_with_warning(
353
+ constructor_fn, wtype, message, version, None
354
+ ),
355
+ )
356
+ return cls
357
+
358
+
359
+ def _decorate_with_warning(
360
+ func: _F,
361
+ wtype: Type[exc.SADeprecationWarning],
362
+ message: str,
363
+ version: str,
364
+ docstring_header: Optional[str] = None,
365
+ enable_warnings: bool = True,
366
+ ) -> _F:
367
+ """Wrap a function with a warnings.warn and augmented docstring."""
368
+
369
+ message = _sanitize_restructured_text(message)
370
+
371
+ if issubclass(wtype, exc.Base20DeprecationWarning):
372
+ doc_only = (
373
+ " (Background on SQLAlchemy 2.0 at: "
374
+ ":ref:`migration_20_toplevel`)"
375
+ )
376
+ else:
377
+ doc_only = ""
378
+
379
+ @decorator
380
+ def warned(fn: _F, *args: Any, **kwargs: Any) -> _F:
381
+ skip_warning = not enable_warnings or kwargs.pop(
382
+ "_sa_skip_warning", False
383
+ )
384
+ if not skip_warning:
385
+ _warn_with_version(message, version, wtype, stacklevel=3)
386
+ return fn(*args, **kwargs) # type: ignore[no-any-return]
387
+
388
+ doc = func.__doc__ is not None and func.__doc__ or ""
389
+ if docstring_header is not None:
390
+ docstring_header %= dict(func=func.__name__)
391
+
392
+ docstring_header += doc_only
393
+
394
+ doc = inject_docstring_text(doc, docstring_header, 1)
395
+
396
+ decorated = warned(func)
397
+ decorated.__doc__ = doc
398
+ decorated._sa_warn = lambda: _warn_with_version( # type: ignore
399
+ message, version, wtype, stacklevel=3
400
+ )
401
+ return decorated