SQLAlchemy 2.0.36__cp313-cp313-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 (273) hide show
  1. SQLAlchemy-2.0.36.dist-info/LICENSE +19 -0
  2. SQLAlchemy-2.0.36.dist-info/METADATA +243 -0
  3. SQLAlchemy-2.0.36.dist-info/RECORD +273 -0
  4. SQLAlchemy-2.0.36.dist-info/WHEEL +5 -0
  5. SQLAlchemy-2.0.36.dist-info/top_level.txt +1 -0
  6. sqlalchemy/__init__.py +294 -0
  7. sqlalchemy/connectors/__init__.py +18 -0
  8. sqlalchemy/connectors/aioodbc.py +174 -0
  9. sqlalchemy/connectors/asyncio.py +213 -0
  10. sqlalchemy/connectors/pyodbc.py +249 -0
  11. sqlalchemy/cyextension/__init__.py +6 -0
  12. sqlalchemy/cyextension/collections.cp313-win32.pyd +0 -0
  13. sqlalchemy/cyextension/collections.pyx +409 -0
  14. sqlalchemy/cyextension/immutabledict.cp313-win32.pyd +0 -0
  15. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  16. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  17. sqlalchemy/cyextension/processors.cp313-win32.pyd +0 -0
  18. sqlalchemy/cyextension/processors.pyx +68 -0
  19. sqlalchemy/cyextension/resultproxy.cp313-win32.pyd +0 -0
  20. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  21. sqlalchemy/cyextension/util.cp313-win32.pyd +0 -0
  22. sqlalchemy/cyextension/util.pyx +91 -0
  23. sqlalchemy/dialects/__init__.py +61 -0
  24. sqlalchemy/dialects/_typing.py +25 -0
  25. sqlalchemy/dialects/mssql/__init__.py +88 -0
  26. sqlalchemy/dialects/mssql/aioodbc.py +64 -0
  27. sqlalchemy/dialects/mssql/base.py +4010 -0
  28. sqlalchemy/dialects/mssql/information_schema.py +254 -0
  29. sqlalchemy/dialects/mssql/json.py +133 -0
  30. sqlalchemy/dialects/mssql/provision.py +162 -0
  31. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  32. sqlalchemy/dialects/mssql/pyodbc.py +745 -0
  33. sqlalchemy/dialects/mysql/__init__.py +101 -0
  34. sqlalchemy/dialects/mysql/aiomysql.py +333 -0
  35. sqlalchemy/dialects/mysql/asyncmy.py +337 -0
  36. sqlalchemy/dialects/mysql/base.py +3494 -0
  37. sqlalchemy/dialects/mysql/cymysql.py +84 -0
  38. sqlalchemy/dialects/mysql/dml.py +219 -0
  39. sqlalchemy/dialects/mysql/enumerated.py +244 -0
  40. sqlalchemy/dialects/mysql/expression.py +141 -0
  41. sqlalchemy/dialects/mysql/json.py +81 -0
  42. sqlalchemy/dialects/mysql/mariadb.py +32 -0
  43. sqlalchemy/dialects/mysql/mariadbconnector.py +277 -0
  44. sqlalchemy/dialects/mysql/mysqlconnector.py +180 -0
  45. sqlalchemy/dialects/mysql/mysqldb.py +303 -0
  46. sqlalchemy/dialects/mysql/provision.py +110 -0
  47. sqlalchemy/dialects/mysql/pymysql.py +137 -0
  48. sqlalchemy/dialects/mysql/pyodbc.py +138 -0
  49. sqlalchemy/dialects/mysql/reflection.py +677 -0
  50. sqlalchemy/dialects/mysql/reserved_words.py +571 -0
  51. sqlalchemy/dialects/mysql/types.py +774 -0
  52. sqlalchemy/dialects/oracle/__init__.py +67 -0
  53. sqlalchemy/dialects/oracle/base.py +3271 -0
  54. sqlalchemy/dialects/oracle/cx_oracle.py +1483 -0
  55. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  56. sqlalchemy/dialects/oracle/oracledb.py +431 -0
  57. sqlalchemy/dialects/oracle/provision.py +220 -0
  58. sqlalchemy/dialects/oracle/types.py +287 -0
  59. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  60. sqlalchemy/dialects/postgresql/_psycopg_common.py +187 -0
  61. sqlalchemy/dialects/postgresql/array.py +425 -0
  62. sqlalchemy/dialects/postgresql/asyncpg.py +1274 -0
  63. sqlalchemy/dialects/postgresql/base.py +5008 -0
  64. sqlalchemy/dialects/postgresql/dml.py +310 -0
  65. sqlalchemy/dialects/postgresql/ext.py +496 -0
  66. sqlalchemy/dialects/postgresql/hstore.py +397 -0
  67. sqlalchemy/dialects/postgresql/json.py +333 -0
  68. sqlalchemy/dialects/postgresql/named_types.py +509 -0
  69. sqlalchemy/dialects/postgresql/operators.py +129 -0
  70. sqlalchemy/dialects/postgresql/pg8000.py +662 -0
  71. sqlalchemy/dialects/postgresql/pg_catalog.py +300 -0
  72. sqlalchemy/dialects/postgresql/provision.py +175 -0
  73. sqlalchemy/dialects/postgresql/psycopg.py +772 -0
  74. sqlalchemy/dialects/postgresql/psycopg2.py +886 -0
  75. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  76. sqlalchemy/dialects/postgresql/ranges.py +1029 -0
  77. sqlalchemy/dialects/postgresql/types.py +303 -0
  78. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  79. sqlalchemy/dialects/sqlite/aiosqlite.py +396 -0
  80. sqlalchemy/dialects/sqlite/base.py +2805 -0
  81. sqlalchemy/dialects/sqlite/dml.py +240 -0
  82. sqlalchemy/dialects/sqlite/json.py +92 -0
  83. sqlalchemy/dialects/sqlite/provision.py +198 -0
  84. sqlalchemy/dialects/sqlite/pysqlcipher.py +155 -0
  85. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  86. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  87. sqlalchemy/engine/__init__.py +62 -0
  88. sqlalchemy/engine/_py_processors.py +136 -0
  89. sqlalchemy/engine/_py_row.py +128 -0
  90. sqlalchemy/engine/_py_util.py +74 -0
  91. sqlalchemy/engine/base.py +3375 -0
  92. sqlalchemy/engine/characteristics.py +155 -0
  93. sqlalchemy/engine/create.py +875 -0
  94. sqlalchemy/engine/cursor.py +2181 -0
  95. sqlalchemy/engine/default.py +2365 -0
  96. sqlalchemy/engine/events.py +951 -0
  97. sqlalchemy/engine/interfaces.py +3403 -0
  98. sqlalchemy/engine/mock.py +131 -0
  99. sqlalchemy/engine/processors.py +61 -0
  100. sqlalchemy/engine/reflection.py +2098 -0
  101. sqlalchemy/engine/result.py +2382 -0
  102. sqlalchemy/engine/row.py +401 -0
  103. sqlalchemy/engine/strategies.py +19 -0
  104. sqlalchemy/engine/url.py +910 -0
  105. sqlalchemy/engine/util.py +167 -0
  106. sqlalchemy/event/__init__.py +25 -0
  107. sqlalchemy/event/api.py +225 -0
  108. sqlalchemy/event/attr.py +655 -0
  109. sqlalchemy/event/base.py +470 -0
  110. sqlalchemy/event/legacy.py +246 -0
  111. sqlalchemy/event/registry.py +386 -0
  112. sqlalchemy/events.py +17 -0
  113. sqlalchemy/exc.py +830 -0
  114. sqlalchemy/ext/__init__.py +11 -0
  115. sqlalchemy/ext/associationproxy.py +2013 -0
  116. sqlalchemy/ext/asyncio/__init__.py +25 -0
  117. sqlalchemy/ext/asyncio/base.py +279 -0
  118. sqlalchemy/ext/asyncio/engine.py +1466 -0
  119. sqlalchemy/ext/asyncio/exc.py +21 -0
  120. sqlalchemy/ext/asyncio/result.py +961 -0
  121. sqlalchemy/ext/asyncio/scoping.py +1614 -0
  122. sqlalchemy/ext/asyncio/session.py +1936 -0
  123. sqlalchemy/ext/automap.py +1691 -0
  124. sqlalchemy/ext/baked.py +574 -0
  125. sqlalchemy/ext/compiler.py +570 -0
  126. sqlalchemy/ext/declarative/__init__.py +65 -0
  127. sqlalchemy/ext/declarative/extensions.py +548 -0
  128. sqlalchemy/ext/horizontal_shard.py +481 -0
  129. sqlalchemy/ext/hybrid.py +1514 -0
  130. sqlalchemy/ext/indexable.py +341 -0
  131. sqlalchemy/ext/instrumentation.py +450 -0
  132. sqlalchemy/ext/mutable.py +1073 -0
  133. sqlalchemy/ext/mypy/__init__.py +6 -0
  134. sqlalchemy/ext/mypy/apply.py +320 -0
  135. sqlalchemy/ext/mypy/decl_class.py +515 -0
  136. sqlalchemy/ext/mypy/infer.py +590 -0
  137. sqlalchemy/ext/mypy/names.py +335 -0
  138. sqlalchemy/ext/mypy/plugin.py +303 -0
  139. sqlalchemy/ext/mypy/util.py +357 -0
  140. sqlalchemy/ext/orderinglist.py +416 -0
  141. sqlalchemy/ext/serializer.py +181 -0
  142. sqlalchemy/future/__init__.py +16 -0
  143. sqlalchemy/future/engine.py +15 -0
  144. sqlalchemy/inspection.py +174 -0
  145. sqlalchemy/log.py +288 -0
  146. sqlalchemy/orm/__init__.py +170 -0
  147. sqlalchemy/orm/_orm_constructors.py +2571 -0
  148. sqlalchemy/orm/_typing.py +179 -0
  149. sqlalchemy/orm/attributes.py +2835 -0
  150. sqlalchemy/orm/base.py +973 -0
  151. sqlalchemy/orm/bulk_persistence.py +2123 -0
  152. sqlalchemy/orm/clsregistry.py +571 -0
  153. sqlalchemy/orm/collections.py +1620 -0
  154. sqlalchemy/orm/context.py +3268 -0
  155. sqlalchemy/orm/decl_api.py +1883 -0
  156. sqlalchemy/orm/decl_base.py +2190 -0
  157. sqlalchemy/orm/dependency.py +1304 -0
  158. sqlalchemy/orm/descriptor_props.py +1076 -0
  159. sqlalchemy/orm/dynamic.py +300 -0
  160. sqlalchemy/orm/evaluator.py +379 -0
  161. sqlalchemy/orm/events.py +3261 -0
  162. sqlalchemy/orm/exc.py +228 -0
  163. sqlalchemy/orm/identity.py +302 -0
  164. sqlalchemy/orm/instrumentation.py +754 -0
  165. sqlalchemy/orm/interfaces.py +1474 -0
  166. sqlalchemy/orm/loading.py +1682 -0
  167. sqlalchemy/orm/mapped_collection.py +557 -0
  168. sqlalchemy/orm/mapper.py +4432 -0
  169. sqlalchemy/orm/path_registry.py +811 -0
  170. sqlalchemy/orm/persistence.py +1782 -0
  171. sqlalchemy/orm/properties.py +886 -0
  172. sqlalchemy/orm/query.py +3396 -0
  173. sqlalchemy/orm/relationships.py +3500 -0
  174. sqlalchemy/orm/scoping.py +2165 -0
  175. sqlalchemy/orm/session.py +5301 -0
  176. sqlalchemy/orm/state.py +1143 -0
  177. sqlalchemy/orm/state_changes.py +198 -0
  178. sqlalchemy/orm/strategies.py +3473 -0
  179. sqlalchemy/orm/strategy_options.py +2569 -0
  180. sqlalchemy/orm/sync.py +164 -0
  181. sqlalchemy/orm/unitofwork.py +796 -0
  182. sqlalchemy/orm/util.py +2424 -0
  183. sqlalchemy/orm/writeonly.py +678 -0
  184. sqlalchemy/pool/__init__.py +44 -0
  185. sqlalchemy/pool/base.py +1515 -0
  186. sqlalchemy/pool/events.py +370 -0
  187. sqlalchemy/pool/impl.py +581 -0
  188. sqlalchemy/py.typed +0 -0
  189. sqlalchemy/schema.py +70 -0
  190. sqlalchemy/sql/__init__.py +145 -0
  191. sqlalchemy/sql/_dml_constructors.py +140 -0
  192. sqlalchemy/sql/_elements_constructors.py +1850 -0
  193. sqlalchemy/sql/_orm_types.py +20 -0
  194. sqlalchemy/sql/_py_util.py +75 -0
  195. sqlalchemy/sql/_selectable_constructors.py +635 -0
  196. sqlalchemy/sql/_typing.py +460 -0
  197. sqlalchemy/sql/annotation.py +585 -0
  198. sqlalchemy/sql/base.py +2185 -0
  199. sqlalchemy/sql/cache_key.py +1057 -0
  200. sqlalchemy/sql/coercions.py +1405 -0
  201. sqlalchemy/sql/compiler.py +7818 -0
  202. sqlalchemy/sql/crud.py +1669 -0
  203. sqlalchemy/sql/ddl.py +1378 -0
  204. sqlalchemy/sql/default_comparator.py +552 -0
  205. sqlalchemy/sql/dml.py +1817 -0
  206. sqlalchemy/sql/elements.py +5499 -0
  207. sqlalchemy/sql/events.py +455 -0
  208. sqlalchemy/sql/expression.py +162 -0
  209. sqlalchemy/sql/functions.py +2055 -0
  210. sqlalchemy/sql/lambdas.py +1449 -0
  211. sqlalchemy/sql/naming.py +212 -0
  212. sqlalchemy/sql/operators.py +2579 -0
  213. sqlalchemy/sql/roles.py +323 -0
  214. sqlalchemy/sql/schema.py +6158 -0
  215. sqlalchemy/sql/selectable.py +7004 -0
  216. sqlalchemy/sql/sqltypes.py +3827 -0
  217. sqlalchemy/sql/traversals.py +1024 -0
  218. sqlalchemy/sql/type_api.py +2339 -0
  219. sqlalchemy/sql/util.py +1486 -0
  220. sqlalchemy/sql/visitors.py +1165 -0
  221. sqlalchemy/testing/__init__.py +96 -0
  222. sqlalchemy/testing/assertions.py +989 -0
  223. sqlalchemy/testing/assertsql.py +516 -0
  224. sqlalchemy/testing/asyncio.py +135 -0
  225. sqlalchemy/testing/config.py +427 -0
  226. sqlalchemy/testing/engines.py +472 -0
  227. sqlalchemy/testing/entities.py +117 -0
  228. sqlalchemy/testing/exclusions.py +435 -0
  229. sqlalchemy/testing/fixtures/__init__.py +28 -0
  230. sqlalchemy/testing/fixtures/base.py +366 -0
  231. sqlalchemy/testing/fixtures/mypy.py +312 -0
  232. sqlalchemy/testing/fixtures/orm.py +227 -0
  233. sqlalchemy/testing/fixtures/sql.py +503 -0
  234. sqlalchemy/testing/pickleable.py +155 -0
  235. sqlalchemy/testing/plugin/__init__.py +6 -0
  236. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  237. sqlalchemy/testing/plugin/plugin_base.py +779 -0
  238. sqlalchemy/testing/plugin/pytestplugin.py +868 -0
  239. sqlalchemy/testing/profiling.py +324 -0
  240. sqlalchemy/testing/provision.py +496 -0
  241. sqlalchemy/testing/requirements.py +1818 -0
  242. sqlalchemy/testing/schema.py +224 -0
  243. sqlalchemy/testing/suite/__init__.py +19 -0
  244. sqlalchemy/testing/suite/test_cte.py +211 -0
  245. sqlalchemy/testing/suite/test_ddl.py +389 -0
  246. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  247. sqlalchemy/testing/suite/test_dialect.py +740 -0
  248. sqlalchemy/testing/suite/test_insert.py +630 -0
  249. sqlalchemy/testing/suite/test_reflection.py +3225 -0
  250. sqlalchemy/testing/suite/test_results.py +502 -0
  251. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  252. sqlalchemy/testing/suite/test_select.py +1999 -0
  253. sqlalchemy/testing/suite/test_sequence.py +317 -0
  254. sqlalchemy/testing/suite/test_types.py +2141 -0
  255. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  256. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  257. sqlalchemy/testing/util.py +537 -0
  258. sqlalchemy/testing/warnings.py +52 -0
  259. sqlalchemy/types.py +76 -0
  260. sqlalchemy/util/__init__.py +160 -0
  261. sqlalchemy/util/_collections.py +715 -0
  262. sqlalchemy/util/_concurrency_py3k.py +288 -0
  263. sqlalchemy/util/_has_cy.py +40 -0
  264. sqlalchemy/util/_py_collections.py +541 -0
  265. sqlalchemy/util/compat.py +301 -0
  266. sqlalchemy/util/concurrency.py +108 -0
  267. sqlalchemy/util/deprecations.py +401 -0
  268. sqlalchemy/util/langhelpers.py +2218 -0
  269. sqlalchemy/util/preloaded.py +150 -0
  270. sqlalchemy/util/queue.py +322 -0
  271. sqlalchemy/util/tool_support.py +201 -0
  272. sqlalchemy/util/topological.py +120 -0
  273. sqlalchemy/util/typing.py +629 -0
@@ -0,0 +1,537 @@
1
+ # testing/util.py
2
+ # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ # mypy: ignore-errors
8
+
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections import deque
13
+ import contextlib
14
+ import decimal
15
+ import gc
16
+ from itertools import chain
17
+ import random
18
+ import sys
19
+ from sys import getsizeof
20
+ import time
21
+ import types
22
+ from typing import Any
23
+
24
+ from . import config
25
+ from . import mock
26
+ from .. import inspect
27
+ from ..engine import Connection
28
+ from ..schema import Column
29
+ from ..schema import DropConstraint
30
+ from ..schema import DropTable
31
+ from ..schema import ForeignKeyConstraint
32
+ from ..schema import MetaData
33
+ from ..schema import Table
34
+ from ..sql import schema
35
+ from ..sql.sqltypes import Integer
36
+ from ..util import decorator
37
+ from ..util import defaultdict
38
+ from ..util import has_refcount_gc
39
+ from ..util import inspect_getfullargspec
40
+
41
+
42
+ if not has_refcount_gc:
43
+
44
+ def non_refcount_gc_collect(*args):
45
+ gc.collect()
46
+ gc.collect()
47
+
48
+ gc_collect = lazy_gc = non_refcount_gc_collect
49
+ else:
50
+ # assume CPython - straight gc.collect, lazy_gc() is a pass
51
+ gc_collect = gc.collect
52
+
53
+ def lazy_gc():
54
+ pass
55
+
56
+
57
+ def picklers():
58
+ picklers = set()
59
+ import pickle
60
+
61
+ picklers.add(pickle)
62
+
63
+ # yes, this thing needs this much testing
64
+ for pickle_ in picklers:
65
+ for protocol in range(-2, pickle.HIGHEST_PROTOCOL + 1):
66
+ yield pickle_.loads, lambda d: pickle_.dumps(d, protocol)
67
+
68
+
69
+ def random_choices(population, k=1):
70
+ return random.choices(population, k=k)
71
+
72
+
73
+ def round_decimal(value, prec):
74
+ if isinstance(value, float):
75
+ return round(value, prec)
76
+
77
+ # can also use shift() here but that is 2.6 only
78
+ return (value * decimal.Decimal("1" + "0" * prec)).to_integral(
79
+ decimal.ROUND_FLOOR
80
+ ) / pow(10, prec)
81
+
82
+
83
+ class RandomSet(set):
84
+ def __iter__(self):
85
+ l = list(set.__iter__(self))
86
+ random.shuffle(l)
87
+ return iter(l)
88
+
89
+ def pop(self):
90
+ index = random.randint(0, len(self) - 1)
91
+ item = list(set.__iter__(self))[index]
92
+ self.remove(item)
93
+ return item
94
+
95
+ def union(self, other):
96
+ return RandomSet(set.union(self, other))
97
+
98
+ def difference(self, other):
99
+ return RandomSet(set.difference(self, other))
100
+
101
+ def intersection(self, other):
102
+ return RandomSet(set.intersection(self, other))
103
+
104
+ def copy(self):
105
+ return RandomSet(self)
106
+
107
+
108
+ def conforms_partial_ordering(tuples, sorted_elements):
109
+ """True if the given sorting conforms to the given partial ordering."""
110
+
111
+ deps = defaultdict(set)
112
+ for parent, child in tuples:
113
+ deps[parent].add(child)
114
+ for i, node in enumerate(sorted_elements):
115
+ for n in sorted_elements[i:]:
116
+ if node in deps[n]:
117
+ return False
118
+ else:
119
+ return True
120
+
121
+
122
+ def all_partial_orderings(tuples, elements):
123
+ edges = defaultdict(set)
124
+ for parent, child in tuples:
125
+ edges[child].add(parent)
126
+
127
+ def _all_orderings(elements):
128
+ if len(elements) == 1:
129
+ yield list(elements)
130
+ else:
131
+ for elem in elements:
132
+ subset = set(elements).difference([elem])
133
+ if not subset.intersection(edges[elem]):
134
+ for sub_ordering in _all_orderings(subset):
135
+ yield [elem] + sub_ordering
136
+
137
+ return iter(_all_orderings(elements))
138
+
139
+
140
+ def function_named(fn, name):
141
+ """Return a function with a given __name__.
142
+
143
+ Will assign to __name__ and return the original function if possible on
144
+ the Python implementation, otherwise a new function will be constructed.
145
+
146
+ This function should be phased out as much as possible
147
+ in favor of @decorator. Tests that "generate" many named tests
148
+ should be modernized.
149
+
150
+ """
151
+ try:
152
+ fn.__name__ = name
153
+ except TypeError:
154
+ fn = types.FunctionType(
155
+ fn.__code__, fn.__globals__, name, fn.__defaults__, fn.__closure__
156
+ )
157
+ return fn
158
+
159
+
160
+ def run_as_contextmanager(ctx, fn, *arg, **kw):
161
+ """Run the given function under the given contextmanager,
162
+ simulating the behavior of 'with' to support older
163
+ Python versions.
164
+
165
+ This is not necessary anymore as we have placed 2.6
166
+ as minimum Python version, however some tests are still using
167
+ this structure.
168
+
169
+ """
170
+
171
+ obj = ctx.__enter__()
172
+ try:
173
+ result = fn(obj, *arg, **kw)
174
+ ctx.__exit__(None, None, None)
175
+ return result
176
+ except:
177
+ exc_info = sys.exc_info()
178
+ raise_ = ctx.__exit__(*exc_info)
179
+ if not raise_:
180
+ raise
181
+ else:
182
+ return raise_
183
+
184
+
185
+ def rowset(results):
186
+ """Converts the results of sql execution into a plain set of column tuples.
187
+
188
+ Useful for asserting the results of an unordered query.
189
+ """
190
+
191
+ return {tuple(row) for row in results}
192
+
193
+
194
+ def fail(msg):
195
+ assert False, msg
196
+
197
+
198
+ @decorator
199
+ def provide_metadata(fn, *args, **kw):
200
+ """Provide bound MetaData for a single test, dropping afterwards.
201
+
202
+ Legacy; use the "metadata" pytest fixture.
203
+
204
+ """
205
+
206
+ from . import fixtures
207
+
208
+ metadata = schema.MetaData()
209
+ self = args[0]
210
+ prev_meta = getattr(self, "metadata", None)
211
+ self.metadata = metadata
212
+ try:
213
+ return fn(*args, **kw)
214
+ finally:
215
+ # close out some things that get in the way of dropping tables.
216
+ # when using the "metadata" fixture, there is a set ordering
217
+ # of things that makes sure things are cleaned up in order, however
218
+ # the simple "decorator" nature of this legacy function means
219
+ # we have to hardcode some of that cleanup ahead of time.
220
+
221
+ # close ORM sessions
222
+ fixtures.close_all_sessions()
223
+
224
+ # integrate with the "connection" fixture as there are many
225
+ # tests where it is used along with provide_metadata
226
+ cfc = fixtures.base._connection_fixture_connection
227
+ if cfc:
228
+ # TODO: this warning can be used to find all the places
229
+ # this is used with connection fixture
230
+ # warn("mixing legacy provide metadata with connection fixture")
231
+ drop_all_tables_from_metadata(metadata, cfc)
232
+ # as the provide_metadata fixture is often used with "testing.db",
233
+ # when we do the drop we have to commit the transaction so that
234
+ # the DB is actually updated as the CREATE would have been
235
+ # committed
236
+ cfc.get_transaction().commit()
237
+ else:
238
+ drop_all_tables_from_metadata(metadata, config.db)
239
+ self.metadata = prev_meta
240
+
241
+
242
+ def flag_combinations(*combinations):
243
+ """A facade around @testing.combinations() oriented towards boolean
244
+ keyword-based arguments.
245
+
246
+ Basically generates a nice looking identifier based on the keywords
247
+ and also sets up the argument names.
248
+
249
+ E.g.::
250
+
251
+ @testing.flag_combinations(
252
+ dict(lazy=False, passive=False),
253
+ dict(lazy=True, passive=False),
254
+ dict(lazy=False, passive=True),
255
+ dict(lazy=False, passive=True, raiseload=True),
256
+ )
257
+
258
+
259
+ would result in::
260
+
261
+ @testing.combinations(
262
+ ('', False, False, False),
263
+ ('lazy', True, False, False),
264
+ ('lazy_passive', True, True, False),
265
+ ('lazy_passive', True, True, True),
266
+ id_='iaaa',
267
+ argnames='lazy,passive,raiseload'
268
+ )
269
+
270
+ """
271
+
272
+ keys = set()
273
+
274
+ for d in combinations:
275
+ keys.update(d)
276
+
277
+ keys = sorted(keys)
278
+
279
+ return config.combinations(
280
+ *[
281
+ ("_".join(k for k in keys if d.get(k, False)),)
282
+ + tuple(d.get(k, False) for k in keys)
283
+ for d in combinations
284
+ ],
285
+ id_="i" + ("a" * len(keys)),
286
+ argnames=",".join(keys),
287
+ )
288
+
289
+
290
+ def lambda_combinations(lambda_arg_sets, **kw):
291
+ args = inspect_getfullargspec(lambda_arg_sets)
292
+
293
+ arg_sets = lambda_arg_sets(*[mock.Mock() for arg in args[0]])
294
+
295
+ def create_fixture(pos):
296
+ def fixture(**kw):
297
+ return lambda_arg_sets(**kw)[pos]
298
+
299
+ fixture.__name__ = "fixture_%3.3d" % pos
300
+ return fixture
301
+
302
+ return config.combinations(
303
+ *[(create_fixture(i),) for i in range(len(arg_sets))], **kw
304
+ )
305
+
306
+
307
+ def resolve_lambda(__fn, **kw):
308
+ """Given a no-arg lambda and a namespace, return a new lambda that
309
+ has all the values filled in.
310
+
311
+ This is used so that we can have module-level fixtures that
312
+ refer to instance-level variables using lambdas.
313
+
314
+ """
315
+
316
+ pos_args = inspect_getfullargspec(__fn)[0]
317
+ pass_pos_args = {arg: kw.pop(arg) for arg in pos_args}
318
+ glb = dict(__fn.__globals__)
319
+ glb.update(kw)
320
+ new_fn = types.FunctionType(__fn.__code__, glb)
321
+ return new_fn(**pass_pos_args)
322
+
323
+
324
+ def metadata_fixture(ddl="function"):
325
+ """Provide MetaData for a pytest fixture."""
326
+
327
+ def decorate(fn):
328
+ def run_ddl(self):
329
+ metadata = self.metadata = schema.MetaData()
330
+ try:
331
+ result = fn(self, metadata)
332
+ metadata.create_all(config.db)
333
+ # TODO:
334
+ # somehow get a per-function dml erase fixture here
335
+ yield result
336
+ finally:
337
+ metadata.drop_all(config.db)
338
+
339
+ return config.fixture(scope=ddl)(run_ddl)
340
+
341
+ return decorate
342
+
343
+
344
+ def force_drop_names(*names):
345
+ """Force the given table names to be dropped after test complete,
346
+ isolating for foreign key cycles
347
+
348
+ """
349
+
350
+ @decorator
351
+ def go(fn, *args, **kw):
352
+ try:
353
+ return fn(*args, **kw)
354
+ finally:
355
+ drop_all_tables(config.db, inspect(config.db), include_names=names)
356
+
357
+ return go
358
+
359
+
360
+ class adict(dict):
361
+ """Dict keys available as attributes. Shadows."""
362
+
363
+ def __getattribute__(self, key):
364
+ try:
365
+ return self[key]
366
+ except KeyError:
367
+ return dict.__getattribute__(self, key)
368
+
369
+ def __call__(self, *keys):
370
+ return tuple([self[key] for key in keys])
371
+
372
+ get_all = __call__
373
+
374
+
375
+ def drop_all_tables_from_metadata(metadata, engine_or_connection):
376
+ from . import engines
377
+
378
+ def go(connection):
379
+ engines.testing_reaper.prepare_for_drop_tables(connection)
380
+
381
+ if not connection.dialect.supports_alter:
382
+ from . import assertions
383
+
384
+ with assertions.expect_warnings(
385
+ "Can't sort tables", assert_=False
386
+ ):
387
+ metadata.drop_all(connection)
388
+ else:
389
+ metadata.drop_all(connection)
390
+
391
+ if not isinstance(engine_or_connection, Connection):
392
+ with engine_or_connection.begin() as connection:
393
+ go(connection)
394
+ else:
395
+ go(engine_or_connection)
396
+
397
+
398
+ def drop_all_tables(
399
+ engine,
400
+ inspector,
401
+ schema=None,
402
+ consider_schemas=(None,),
403
+ include_names=None,
404
+ ):
405
+ if include_names is not None:
406
+ include_names = set(include_names)
407
+
408
+ if schema is not None:
409
+ assert consider_schemas == (
410
+ None,
411
+ ), "consider_schemas and schema are mutually exclusive"
412
+ consider_schemas = (schema,)
413
+
414
+ with engine.begin() as conn:
415
+ for table_key, fkcs in reversed(
416
+ inspector.sort_tables_on_foreign_key_dependency(
417
+ consider_schemas=consider_schemas
418
+ )
419
+ ):
420
+ if table_key:
421
+ if (
422
+ include_names is not None
423
+ and table_key[1] not in include_names
424
+ ):
425
+ continue
426
+ conn.execute(
427
+ DropTable(
428
+ Table(table_key[1], MetaData(), schema=table_key[0])
429
+ )
430
+ )
431
+ elif fkcs:
432
+ if not engine.dialect.supports_alter:
433
+ continue
434
+ for t_key, fkc in fkcs:
435
+ if (
436
+ include_names is not None
437
+ and t_key[1] not in include_names
438
+ ):
439
+ continue
440
+ tb = Table(
441
+ t_key[1],
442
+ MetaData(),
443
+ Column("x", Integer),
444
+ Column("y", Integer),
445
+ schema=t_key[0],
446
+ )
447
+ conn.execute(
448
+ DropConstraint(
449
+ ForeignKeyConstraint([tb.c.x], [tb.c.y], name=fkc)
450
+ )
451
+ )
452
+
453
+
454
+ def teardown_events(event_cls):
455
+ @decorator
456
+ def decorate(fn, *arg, **kw):
457
+ try:
458
+ return fn(*arg, **kw)
459
+ finally:
460
+ event_cls._clear()
461
+
462
+ return decorate
463
+
464
+
465
+ def total_size(o):
466
+ """Returns the approximate memory footprint an object and all of its
467
+ contents.
468
+
469
+ source: https://code.activestate.com/recipes/577504/
470
+
471
+
472
+ """
473
+
474
+ def dict_handler(d):
475
+ return chain.from_iterable(d.items())
476
+
477
+ all_handlers = {
478
+ tuple: iter,
479
+ list: iter,
480
+ deque: iter,
481
+ dict: dict_handler,
482
+ set: iter,
483
+ frozenset: iter,
484
+ }
485
+ seen = set() # track which object id's have already been seen
486
+ default_size = getsizeof(0) # estimate sizeof object without __sizeof__
487
+
488
+ def sizeof(o):
489
+ if id(o) in seen: # do not double count the same object
490
+ return 0
491
+ seen.add(id(o))
492
+ s = getsizeof(o, default_size)
493
+
494
+ for typ, handler in all_handlers.items():
495
+ if isinstance(o, typ):
496
+ s += sum(map(sizeof, handler(o)))
497
+ break
498
+ return s
499
+
500
+ return sizeof(o)
501
+
502
+
503
+ def count_cache_key_tuples(tup):
504
+ """given a cache key tuple, counts how many instances of actual
505
+ tuples are found.
506
+
507
+ used to alert large jumps in cache key complexity.
508
+
509
+ """
510
+ stack = [tup]
511
+
512
+ sentinel = object()
513
+ num_elements = 0
514
+
515
+ while stack:
516
+ elem = stack.pop(0)
517
+ if elem is sentinel:
518
+ num_elements += 1
519
+ elif isinstance(elem, tuple):
520
+ if elem:
521
+ stack = list(elem) + [sentinel] + stack
522
+ return num_elements
523
+
524
+
525
+ @contextlib.contextmanager
526
+ def skip_if_timeout(seconds: float, cleanup: Any = None):
527
+
528
+ now = time.time()
529
+ yield
530
+ sec = time.time() - now
531
+ if sec > seconds:
532
+ try:
533
+ cleanup()
534
+ finally:
535
+ config.skip_test(
536
+ f"test took too long ({sec:.4f} seconds > {seconds})"
537
+ )
@@ -0,0 +1,52 @@
1
+ # testing/warnings.py
2
+ # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ # 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,76 @@
1
+ # types.py
2
+ # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+
8
+ """Compatibility namespace for sqlalchemy.sql.types.
9
+
10
+ """
11
+
12
+
13
+ from __future__ import annotations
14
+
15
+ from .sql.sqltypes import _Binary as _Binary
16
+ from .sql.sqltypes import ARRAY as ARRAY
17
+ from .sql.sqltypes import BIGINT as BIGINT
18
+ from .sql.sqltypes import BigInteger as BigInteger
19
+ from .sql.sqltypes import BINARY as BINARY
20
+ from .sql.sqltypes import BLOB as BLOB
21
+ from .sql.sqltypes import BOOLEAN as BOOLEAN
22
+ from .sql.sqltypes import Boolean as Boolean
23
+ from .sql.sqltypes import CHAR as CHAR
24
+ from .sql.sqltypes import CLOB as CLOB
25
+ from .sql.sqltypes import Concatenable as Concatenable
26
+ from .sql.sqltypes import DATE as DATE
27
+ from .sql.sqltypes import Date as Date
28
+ from .sql.sqltypes import DATETIME as DATETIME
29
+ from .sql.sqltypes import DateTime as DateTime
30
+ from .sql.sqltypes import DECIMAL as DECIMAL
31
+ from .sql.sqltypes import DOUBLE as DOUBLE
32
+ from .sql.sqltypes import Double as Double
33
+ from .sql.sqltypes import DOUBLE_PRECISION as DOUBLE_PRECISION
34
+ from .sql.sqltypes import Enum as Enum
35
+ from .sql.sqltypes import FLOAT as FLOAT
36
+ from .sql.sqltypes import Float as Float
37
+ from .sql.sqltypes import Indexable as Indexable
38
+ from .sql.sqltypes import INT as INT
39
+ from .sql.sqltypes import INTEGER as INTEGER
40
+ from .sql.sqltypes import Integer as Integer
41
+ from .sql.sqltypes import Interval as Interval
42
+ from .sql.sqltypes import JSON as JSON
43
+ from .sql.sqltypes import LargeBinary as LargeBinary
44
+ from .sql.sqltypes import MatchType as MatchType
45
+ from .sql.sqltypes import NCHAR as NCHAR
46
+ from .sql.sqltypes import NULLTYPE as NULLTYPE
47
+ from .sql.sqltypes import NullType as NullType
48
+ from .sql.sqltypes import NUMERIC as NUMERIC
49
+ from .sql.sqltypes import Numeric as Numeric
50
+ from .sql.sqltypes import NVARCHAR as NVARCHAR
51
+ from .sql.sqltypes import PickleType as PickleType
52
+ from .sql.sqltypes import REAL as REAL
53
+ from .sql.sqltypes import SchemaType as SchemaType
54
+ from .sql.sqltypes import SMALLINT as SMALLINT
55
+ from .sql.sqltypes import SmallInteger as SmallInteger
56
+ from .sql.sqltypes import String as String
57
+ from .sql.sqltypes import STRINGTYPE as STRINGTYPE
58
+ from .sql.sqltypes import TEXT as TEXT
59
+ from .sql.sqltypes import Text as Text
60
+ from .sql.sqltypes import TIME as TIME
61
+ from .sql.sqltypes import Time as Time
62
+ from .sql.sqltypes import TIMESTAMP as TIMESTAMP
63
+ from .sql.sqltypes import TupleType as TupleType
64
+ from .sql.sqltypes import Unicode as Unicode
65
+ from .sql.sqltypes import UnicodeText as UnicodeText
66
+ from .sql.sqltypes import UUID as UUID
67
+ from .sql.sqltypes import Uuid as Uuid
68
+ from .sql.sqltypes import VARBINARY as VARBINARY
69
+ from .sql.sqltypes import VARCHAR as VARCHAR
70
+ from .sql.type_api import adapt_type as adapt_type
71
+ from .sql.type_api import ExternalType as ExternalType
72
+ from .sql.type_api import to_instance as to_instance
73
+ from .sql.type_api import TypeDecorator as TypeDecorator
74
+ from .sql.type_api import TypeEngine as TypeEngine
75
+ from .sql.type_api import UserDefinedType as UserDefinedType
76
+ from .sql.type_api import Variant as Variant