SQLAlchemy 2.0.45__cp314-cp314-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.cp314-win_amd64.pyd +0 -0
  8. sqlalchemy/cyextension/collections.pyx +409 -0
  9. sqlalchemy/cyextension/immutabledict.cp314-win_amd64.pyd +0 -0
  10. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  11. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  12. sqlalchemy/cyextension/processors.cp314-win_amd64.pyd +0 -0
  13. sqlalchemy/cyextension/processors.pyx +68 -0
  14. sqlalchemy/cyextension/resultproxy.cp314-win_amd64.pyd +0 -0
  15. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  16. sqlalchemy/cyextension/util.cp314-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 +4089 -0
  23. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  24. sqlalchemy/dialects/mssql/json.py +129 -0
  25. sqlalchemy/dialects/mssql/provision.py +168 -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 +3933 -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 +73 -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 +147 -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 +5328 -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 +395 -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 +175 -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 +446 -0
  76. sqlalchemy/dialects/sqlite/base.py +3045 -0
  77. sqlalchemy/dialects/sqlite/dml.py +263 -0
  78. sqlalchemy/dialects/sqlite/json.py +92 -0
  79. sqlalchemy/dialects/sqlite/provision.py +223 -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 +3382 -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 +2387 -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 +1516 -0
  182. sqlalchemy/pool/events.py +372 -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 +481 -0
  193. sqlalchemy/sql/annotation.py +587 -0
  194. sqlalchemy/sql/base.py +2219 -0
  195. sqlalchemy/sql/cache_key.py +1057 -0
  196. sqlalchemy/sql/coercions.py +1404 -0
  197. sqlalchemy/sql/compiler.py +8034 -0
  198. sqlalchemy/sql/crud.py +1744 -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 +2139 -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 +478 -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 +366 -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 +327 -0
  236. sqlalchemy/testing/provision.py +597 -0
  237. sqlalchemy/testing/requirements.py +1940 -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 +717 -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 +316 -0
  262. sqlalchemy/util/concurrency.py +110 -0
  263. sqlalchemy/util/deprecations.py +401 -0
  264. sqlalchemy/util/langhelpers.py +2306 -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.45.dist-info/METADATA +243 -0
  271. sqlalchemy-2.0.45.dist-info/RECORD +274 -0
  272. sqlalchemy-2.0.45.dist-info/WHEEL +5 -0
  273. sqlalchemy-2.0.45.dist-info/licenses/LICENSE +19 -0
  274. sqlalchemy-2.0.45.dist-info/top_level.txt +1 -0
@@ -0,0 +1,535 @@
1
+ # testing/util.py
2
+ # Copyright (C) 2005-2025 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: ignore-errors
8
+
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections import deque
13
+ from collections import namedtuple
14
+ import contextlib
15
+ import decimal
16
+ import gc
17
+ from itertools import chain
18
+ import pickle
19
+ import random
20
+ import sys
21
+ from sys import getsizeof
22
+ import time
23
+ import types
24
+ from typing import Any
25
+
26
+ from . import config
27
+ from . import mock
28
+ from .. import inspect
29
+ from ..engine import Connection
30
+ from ..schema import Column
31
+ from ..schema import DropConstraint
32
+ from ..schema import DropTable
33
+ from ..schema import ForeignKeyConstraint
34
+ from ..schema import MetaData
35
+ from ..schema import Table
36
+ from ..sql import schema
37
+ from ..sql.sqltypes import Integer
38
+ from ..util import decorator
39
+ from ..util import defaultdict
40
+ from ..util import has_refcount_gc
41
+ from ..util import inspect_getfullargspec
42
+
43
+
44
+ if not has_refcount_gc:
45
+
46
+ def non_refcount_gc_collect(*args):
47
+ gc.collect()
48
+ gc.collect()
49
+
50
+ gc_collect = lazy_gc = non_refcount_gc_collect
51
+ else:
52
+ # assume CPython - straight gc.collect, lazy_gc() is a pass
53
+ gc_collect = gc.collect
54
+
55
+ def lazy_gc():
56
+ pass
57
+
58
+
59
+ def picklers():
60
+ nt = namedtuple("picklers", ["loads", "dumps"])
61
+
62
+ for protocol in range(-2, pickle.HIGHEST_PROTOCOL + 1):
63
+ yield nt(pickle.loads, lambda d: pickle.dumps(d, protocol))
64
+
65
+
66
+ def random_choices(population, k=1):
67
+ return random.choices(population, k=k)
68
+
69
+
70
+ def round_decimal(value, prec):
71
+ if isinstance(value, float):
72
+ return round(value, prec)
73
+
74
+ # can also use shift() here but that is 2.6 only
75
+ return (value * decimal.Decimal("1" + "0" * prec)).to_integral(
76
+ decimal.ROUND_FLOOR
77
+ ) / pow(10, prec)
78
+
79
+
80
+ class RandomSet(set):
81
+ def __iter__(self):
82
+ l = list(set.__iter__(self))
83
+ random.shuffle(l)
84
+ return iter(l)
85
+
86
+ def pop(self):
87
+ index = random.randint(0, len(self) - 1)
88
+ item = list(set.__iter__(self))[index]
89
+ self.remove(item)
90
+ return item
91
+
92
+ def union(self, other):
93
+ return RandomSet(set.union(self, other))
94
+
95
+ def difference(self, other):
96
+ return RandomSet(set.difference(self, other))
97
+
98
+ def intersection(self, other):
99
+ return RandomSet(set.intersection(self, other))
100
+
101
+ def copy(self):
102
+ return RandomSet(self)
103
+
104
+
105
+ def conforms_partial_ordering(tuples, sorted_elements):
106
+ """True if the given sorting conforms to the given partial ordering."""
107
+
108
+ deps = defaultdict(set)
109
+ for parent, child in tuples:
110
+ deps[parent].add(child)
111
+ for i, node in enumerate(sorted_elements):
112
+ for n in sorted_elements[i:]:
113
+ if node in deps[n]:
114
+ return False
115
+ else:
116
+ return True
117
+
118
+
119
+ def all_partial_orderings(tuples, elements):
120
+ edges = defaultdict(set)
121
+ for parent, child in tuples:
122
+ edges[child].add(parent)
123
+
124
+ def _all_orderings(elements):
125
+ if len(elements) == 1:
126
+ yield list(elements)
127
+ else:
128
+ for elem in elements:
129
+ subset = set(elements).difference([elem])
130
+ if not subset.intersection(edges[elem]):
131
+ for sub_ordering in _all_orderings(subset):
132
+ yield [elem] + sub_ordering
133
+
134
+ return iter(_all_orderings(elements))
135
+
136
+
137
+ def function_named(fn, name):
138
+ """Return a function with a given __name__.
139
+
140
+ Will assign to __name__ and return the original function if possible on
141
+ the Python implementation, otherwise a new function will be constructed.
142
+
143
+ This function should be phased out as much as possible
144
+ in favor of @decorator. Tests that "generate" many named tests
145
+ should be modernized.
146
+
147
+ """
148
+ try:
149
+ fn.__name__ = name
150
+ except TypeError:
151
+ fn = types.FunctionType(
152
+ fn.__code__, fn.__globals__, name, fn.__defaults__, fn.__closure__
153
+ )
154
+ return fn
155
+
156
+
157
+ def run_as_contextmanager(ctx, fn, *arg, **kw):
158
+ """Run the given function under the given contextmanager,
159
+ simulating the behavior of 'with' to support older
160
+ Python versions.
161
+
162
+ This is not necessary anymore as we have placed 2.6
163
+ as minimum Python version, however some tests are still using
164
+ this structure.
165
+
166
+ """
167
+
168
+ obj = ctx.__enter__()
169
+ try:
170
+ result = fn(obj, *arg, **kw)
171
+ ctx.__exit__(None, None, None)
172
+ return result
173
+ except:
174
+ exc_info = sys.exc_info()
175
+ raise_ = ctx.__exit__(*exc_info)
176
+ if not raise_:
177
+ raise
178
+ else:
179
+ return raise_
180
+
181
+
182
+ def rowset(results):
183
+ """Converts the results of sql execution into a plain set of column tuples.
184
+
185
+ Useful for asserting the results of an unordered query.
186
+ """
187
+
188
+ return {tuple(row) for row in results}
189
+
190
+
191
+ def fail(msg):
192
+ assert False, msg
193
+
194
+
195
+ @decorator
196
+ def provide_metadata(fn, *args, **kw):
197
+ """Provide bound MetaData for a single test, dropping afterwards.
198
+
199
+ Legacy; use the "metadata" pytest fixture.
200
+
201
+ """
202
+
203
+ from . import fixtures
204
+
205
+ metadata = schema.MetaData()
206
+ self = args[0]
207
+ prev_meta = getattr(self, "metadata", None)
208
+ self.metadata = metadata
209
+ try:
210
+ return fn(*args, **kw)
211
+ finally:
212
+ # close out some things that get in the way of dropping tables.
213
+ # when using the "metadata" fixture, there is a set ordering
214
+ # of things that makes sure things are cleaned up in order, however
215
+ # the simple "decorator" nature of this legacy function means
216
+ # we have to hardcode some of that cleanup ahead of time.
217
+
218
+ # close ORM sessions
219
+ fixtures.close_all_sessions()
220
+
221
+ # integrate with the "connection" fixture as there are many
222
+ # tests where it is used along with provide_metadata
223
+ cfc = fixtures.base._connection_fixture_connection
224
+ if cfc:
225
+ # TODO: this warning can be used to find all the places
226
+ # this is used with connection fixture
227
+ # warn("mixing legacy provide metadata with connection fixture")
228
+ drop_all_tables_from_metadata(metadata, cfc)
229
+ # as the provide_metadata fixture is often used with "testing.db",
230
+ # when we do the drop we have to commit the transaction so that
231
+ # the DB is actually updated as the CREATE would have been
232
+ # committed
233
+ cfc.get_transaction().commit()
234
+ else:
235
+ drop_all_tables_from_metadata(metadata, config.db)
236
+ self.metadata = prev_meta
237
+
238
+
239
+ def flag_combinations(*combinations):
240
+ """A facade around @testing.combinations() oriented towards boolean
241
+ keyword-based arguments.
242
+
243
+ Basically generates a nice looking identifier based on the keywords
244
+ and also sets up the argument names.
245
+
246
+ E.g.::
247
+
248
+ @testing.flag_combinations(
249
+ dict(lazy=False, passive=False),
250
+ dict(lazy=True, passive=False),
251
+ dict(lazy=False, passive=True),
252
+ dict(lazy=False, passive=True, raiseload=True),
253
+ )
254
+ def test_fn(lazy, passive, raiseload): ...
255
+
256
+ would result in::
257
+
258
+ @testing.combinations(
259
+ ("", False, False, False),
260
+ ("lazy", True, False, False),
261
+ ("lazy_passive", True, True, False),
262
+ ("lazy_passive", True, True, True),
263
+ id_="iaaa",
264
+ argnames="lazy,passive,raiseload",
265
+ )
266
+ def test_fn(lazy, passive, raiseload): ...
267
+
268
+ """
269
+
270
+ keys = set()
271
+
272
+ for d in combinations:
273
+ keys.update(d)
274
+
275
+ keys = sorted(keys)
276
+
277
+ return config.combinations(
278
+ *[
279
+ ("_".join(k for k in keys if d.get(k, False)),)
280
+ + tuple(d.get(k, False) for k in keys)
281
+ for d in combinations
282
+ ],
283
+ id_="i" + ("a" * len(keys)),
284
+ argnames=",".join(keys),
285
+ )
286
+
287
+
288
+ def lambda_combinations(lambda_arg_sets, **kw):
289
+ args = inspect_getfullargspec(lambda_arg_sets)
290
+
291
+ arg_sets = lambda_arg_sets(*[mock.Mock() for arg in args[0]])
292
+
293
+ def create_fixture(pos):
294
+ def fixture(**kw):
295
+ return lambda_arg_sets(**kw)[pos]
296
+
297
+ fixture.__name__ = "fixture_%3.3d" % pos
298
+ return fixture
299
+
300
+ return config.combinations(
301
+ *[(create_fixture(i),) for i in range(len(arg_sets))], **kw
302
+ )
303
+
304
+
305
+ def resolve_lambda(__fn, **kw):
306
+ """Given a no-arg lambda and a namespace, return a new lambda that
307
+ has all the values filled in.
308
+
309
+ This is used so that we can have module-level fixtures that
310
+ refer to instance-level variables using lambdas.
311
+
312
+ """
313
+
314
+ pos_args = inspect_getfullargspec(__fn)[0]
315
+ pass_pos_args = {arg: kw.pop(arg) for arg in pos_args}
316
+ glb = dict(__fn.__globals__)
317
+ glb.update(kw)
318
+ new_fn = types.FunctionType(__fn.__code__, glb)
319
+ return new_fn(**pass_pos_args)
320
+
321
+
322
+ def metadata_fixture(ddl="function"):
323
+ """Provide MetaData for a pytest fixture."""
324
+
325
+ def decorate(fn):
326
+ def run_ddl(self):
327
+ metadata = self.metadata = schema.MetaData()
328
+ try:
329
+ result = fn(self, metadata)
330
+ metadata.create_all(config.db)
331
+ # TODO:
332
+ # somehow get a per-function dml erase fixture here
333
+ yield result
334
+ finally:
335
+ metadata.drop_all(config.db)
336
+
337
+ return config.fixture(scope=ddl)(run_ddl)
338
+
339
+ return decorate
340
+
341
+
342
+ def force_drop_names(*names):
343
+ """Force the given table names to be dropped after test complete,
344
+ isolating for foreign key cycles
345
+
346
+ """
347
+
348
+ @decorator
349
+ def go(fn, *args, **kw):
350
+ try:
351
+ return fn(*args, **kw)
352
+ finally:
353
+ drop_all_tables(config.db, inspect(config.db), include_names=names)
354
+
355
+ return go
356
+
357
+
358
+ class adict(dict):
359
+ """Dict keys available as attributes. Shadows."""
360
+
361
+ def __getattribute__(self, key):
362
+ try:
363
+ return self[key]
364
+ except KeyError:
365
+ return dict.__getattribute__(self, key)
366
+
367
+ def __call__(self, *keys):
368
+ return tuple([self[key] for key in keys])
369
+
370
+ get_all = __call__
371
+
372
+
373
+ def drop_all_tables_from_metadata(metadata, engine_or_connection):
374
+ from . import engines
375
+
376
+ def go(connection):
377
+ engines.testing_reaper.prepare_for_drop_tables(connection)
378
+
379
+ if not connection.dialect.supports_alter:
380
+ from . import assertions
381
+
382
+ with assertions.expect_warnings(
383
+ "Can't sort tables", assert_=False
384
+ ):
385
+ metadata.drop_all(connection)
386
+ else:
387
+ metadata.drop_all(connection)
388
+
389
+ if not isinstance(engine_or_connection, Connection):
390
+ with engine_or_connection.begin() as connection:
391
+ go(connection)
392
+ else:
393
+ go(engine_or_connection)
394
+
395
+
396
+ def drop_all_tables(
397
+ engine,
398
+ inspector,
399
+ schema=None,
400
+ consider_schemas=(None,),
401
+ include_names=None,
402
+ ):
403
+ if include_names is not None:
404
+ include_names = set(include_names)
405
+
406
+ if schema is not None:
407
+ assert consider_schemas == (
408
+ None,
409
+ ), "consider_schemas and schema are mutually exclusive"
410
+ consider_schemas = (schema,)
411
+
412
+ with engine.begin() as conn:
413
+ for table_key, fkcs in reversed(
414
+ inspector.sort_tables_on_foreign_key_dependency(
415
+ consider_schemas=consider_schemas
416
+ )
417
+ ):
418
+ if table_key:
419
+ if (
420
+ include_names is not None
421
+ and table_key[1] not in include_names
422
+ ):
423
+ continue
424
+ conn.execute(
425
+ DropTable(
426
+ Table(table_key[1], MetaData(), schema=table_key[0])
427
+ )
428
+ )
429
+ elif fkcs:
430
+ if not engine.dialect.supports_alter:
431
+ continue
432
+ for t_key, fkc in fkcs:
433
+ if (
434
+ include_names is not None
435
+ and t_key[1] not in include_names
436
+ ):
437
+ continue
438
+ tb = Table(
439
+ t_key[1],
440
+ MetaData(),
441
+ Column("x", Integer),
442
+ Column("y", Integer),
443
+ schema=t_key[0],
444
+ )
445
+ conn.execute(
446
+ DropConstraint(
447
+ ForeignKeyConstraint([tb.c.x], [tb.c.y], name=fkc)
448
+ )
449
+ )
450
+
451
+
452
+ def teardown_events(event_cls):
453
+ @decorator
454
+ def decorate(fn, *arg, **kw):
455
+ try:
456
+ return fn(*arg, **kw)
457
+ finally:
458
+ event_cls._clear()
459
+
460
+ return decorate
461
+
462
+
463
+ def total_size(o):
464
+ """Returns the approximate memory footprint an object and all of its
465
+ contents.
466
+
467
+ source: https://code.activestate.com/recipes/577504/
468
+
469
+
470
+ """
471
+
472
+ def dict_handler(d):
473
+ return chain.from_iterable(d.items())
474
+
475
+ all_handlers = {
476
+ tuple: iter,
477
+ list: iter,
478
+ deque: iter,
479
+ dict: dict_handler,
480
+ set: iter,
481
+ frozenset: iter,
482
+ }
483
+ seen = set() # track which object id's have already been seen
484
+ default_size = getsizeof(0) # estimate sizeof object without __sizeof__
485
+
486
+ def sizeof(o):
487
+ if id(o) in seen: # do not double count the same object
488
+ return 0
489
+ seen.add(id(o))
490
+ s = getsizeof(o, default_size)
491
+
492
+ for typ, handler in all_handlers.items():
493
+ if isinstance(o, typ):
494
+ s += sum(map(sizeof, handler(o)))
495
+ break
496
+ return s
497
+
498
+ return sizeof(o)
499
+
500
+
501
+ def count_cache_key_tuples(tup):
502
+ """given a cache key tuple, counts how many instances of actual
503
+ tuples are found.
504
+
505
+ used to alert large jumps in cache key complexity.
506
+
507
+ """
508
+ stack = [tup]
509
+
510
+ sentinel = object()
511
+ num_elements = 0
512
+
513
+ while stack:
514
+ elem = stack.pop(0)
515
+ if elem is sentinel:
516
+ num_elements += 1
517
+ elif isinstance(elem, tuple):
518
+ if elem:
519
+ stack = list(elem) + [sentinel] + stack
520
+ return num_elements
521
+
522
+
523
+ @contextlib.contextmanager
524
+ def skip_if_timeout(seconds: float, cleanup: Any = None):
525
+
526
+ now = time.time()
527
+ yield
528
+ sec = time.time() - now
529
+ if sec > seconds:
530
+ try:
531
+ cleanup()
532
+ finally:
533
+ config.skip_test(
534
+ f"test took too long ({sec:.4f} seconds > {seconds})"
535
+ )
@@ -0,0 +1,52 @@
1
+ # testing/warnings.py
2
+ # Copyright (C) 2005-2025 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: ignore-errors
8
+
9
+ from __future__ import annotations
10
+
11
+ import warnings
12
+
13
+ from . import assertions
14
+ from .. import exc
15
+ from .. import exc as sa_exc
16
+ from ..exc import SATestSuiteWarning
17
+ from ..util.langhelpers import _warnings_warn
18
+
19
+
20
+ def warn_test_suite(message):
21
+ _warnings_warn(message, category=SATestSuiteWarning)
22
+
23
+
24
+ def setup_filters():
25
+ """hook for setting up warnings filters.
26
+
27
+ SQLAlchemy-specific classes must only be here and not in pytest config,
28
+ as we need to delay importing SQLAlchemy until conftest.py has been
29
+ processed.
30
+
31
+ NOTE: filters on subclasses of DeprecationWarning or
32
+ PendingDeprecationWarning have no effect if added here, since pytest
33
+ will add at each test the following filters
34
+ ``always::PendingDeprecationWarning`` and ``always::DeprecationWarning``
35
+ that will take precedence over any added here.
36
+
37
+ """
38
+ warnings.filterwarnings("error", category=exc.SAWarning)
39
+ warnings.filterwarnings("always", category=exc.SATestSuiteWarning)
40
+
41
+
42
+ def assert_warnings(fn, warning_msgs, regex=False):
43
+ """Assert that each of the given warnings are emitted by fn.
44
+
45
+ Deprecated. Please use assertions.expect_warnings().
46
+
47
+ """
48
+
49
+ with assertions._expect_warnings(
50
+ sa_exc.SAWarning, warning_msgs, regex=regex
51
+ ):
52
+ return fn()
sqlalchemy/types.py ADDED
@@ -0,0 +1,74 @@
1
+ # types.py
2
+ # Copyright (C) 2005-2025 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
+ """Compatibility namespace for sqlalchemy.sql.types."""
9
+
10
+
11
+ from __future__ import annotations
12
+
13
+ from .sql.sqltypes import _Binary as _Binary
14
+ from .sql.sqltypes import ARRAY as ARRAY
15
+ from .sql.sqltypes import BIGINT as BIGINT
16
+ from .sql.sqltypes import BigInteger as BigInteger
17
+ from .sql.sqltypes import BINARY as BINARY
18
+ from .sql.sqltypes import BLOB as BLOB
19
+ from .sql.sqltypes import BOOLEAN as BOOLEAN
20
+ from .sql.sqltypes import Boolean as Boolean
21
+ from .sql.sqltypes import CHAR as CHAR
22
+ from .sql.sqltypes import CLOB as CLOB
23
+ from .sql.sqltypes import Concatenable as Concatenable
24
+ from .sql.sqltypes import DATE as DATE
25
+ from .sql.sqltypes import Date as Date
26
+ from .sql.sqltypes import DATETIME as DATETIME
27
+ from .sql.sqltypes import DateTime as DateTime
28
+ from .sql.sqltypes import DECIMAL as DECIMAL
29
+ from .sql.sqltypes import DOUBLE as DOUBLE
30
+ from .sql.sqltypes import Double as Double
31
+ from .sql.sqltypes import DOUBLE_PRECISION as DOUBLE_PRECISION
32
+ from .sql.sqltypes import Enum as Enum
33
+ from .sql.sqltypes import FLOAT as FLOAT
34
+ from .sql.sqltypes import Float as Float
35
+ from .sql.sqltypes import Indexable as Indexable
36
+ from .sql.sqltypes import INT as INT
37
+ from .sql.sqltypes import INTEGER as INTEGER
38
+ from .sql.sqltypes import Integer as Integer
39
+ from .sql.sqltypes import Interval as Interval
40
+ from .sql.sqltypes import JSON as JSON
41
+ from .sql.sqltypes import LargeBinary as LargeBinary
42
+ from .sql.sqltypes import MatchType as MatchType
43
+ from .sql.sqltypes import NCHAR as NCHAR
44
+ from .sql.sqltypes import NULLTYPE as NULLTYPE
45
+ from .sql.sqltypes import NullType as NullType
46
+ from .sql.sqltypes import NUMERIC as NUMERIC
47
+ from .sql.sqltypes import Numeric as Numeric
48
+ from .sql.sqltypes import NVARCHAR as NVARCHAR
49
+ from .sql.sqltypes import PickleType as PickleType
50
+ from .sql.sqltypes import REAL as REAL
51
+ from .sql.sqltypes import SchemaType as SchemaType
52
+ from .sql.sqltypes import SMALLINT as SMALLINT
53
+ from .sql.sqltypes import SmallInteger as SmallInteger
54
+ from .sql.sqltypes import String as String
55
+ from .sql.sqltypes import STRINGTYPE as STRINGTYPE
56
+ from .sql.sqltypes import TEXT as TEXT
57
+ from .sql.sqltypes import Text as Text
58
+ from .sql.sqltypes import TIME as TIME
59
+ from .sql.sqltypes import Time as Time
60
+ from .sql.sqltypes import TIMESTAMP as TIMESTAMP
61
+ from .sql.sqltypes import TupleType as TupleType
62
+ from .sql.sqltypes import Unicode as Unicode
63
+ from .sql.sqltypes import UnicodeText as UnicodeText
64
+ from .sql.sqltypes import UUID as UUID
65
+ from .sql.sqltypes import Uuid as Uuid
66
+ from .sql.sqltypes import VARBINARY as VARBINARY
67
+ from .sql.sqltypes import VARCHAR as VARCHAR
68
+ from .sql.type_api import adapt_type as adapt_type
69
+ from .sql.type_api import ExternalType as ExternalType
70
+ from .sql.type_api import to_instance as to_instance
71
+ from .sql.type_api import TypeDecorator as TypeDecorator
72
+ from .sql.type_api import TypeEngine as TypeEngine
73
+ from .sql.type_api import UserDefinedType as UserDefinedType
74
+ from .sql.type_api import Variant as Variant