SQLAlchemy 2.1.0b1__cp313-cp313-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. sqlalchemy/__init__.py +295 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +161 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +88 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4110 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +129 -0
  13. sqlalchemy/dialects/mssql/provision.py +185 -0
  14. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  15. sqlalchemy/dialects/mssql/pyodbc.py +758 -0
  16. sqlalchemy/dialects/mysql/__init__.py +106 -0
  17. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  18. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  19. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  20. sqlalchemy/dialects/mysql/base.py +3870 -0
  21. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  22. sqlalchemy/dialects/mysql/dml.py +279 -0
  23. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  24. sqlalchemy/dialects/mysql/expression.py +146 -0
  25. sqlalchemy/dialects/mysql/json.py +91 -0
  26. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  27. sqlalchemy/dialects/mysql/mariadbconnector.py +330 -0
  28. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  29. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  30. sqlalchemy/dialects/mysql/provision.py +147 -0
  31. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  32. sqlalchemy/dialects/mysql/pyodbc.py +156 -0
  33. sqlalchemy/dialects/mysql/reflection.py +724 -0
  34. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  35. sqlalchemy/dialects/mysql/types.py +845 -0
  36. sqlalchemy/dialects/oracle/__init__.py +83 -0
  37. sqlalchemy/dialects/oracle/base.py +3871 -0
  38. sqlalchemy/dialects/oracle/cx_oracle.py +1522 -0
  39. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  40. sqlalchemy/dialects/oracle/oracledb.py +894 -0
  41. sqlalchemy/dialects/oracle/provision.py +288 -0
  42. sqlalchemy/dialects/oracle/types.py +350 -0
  43. sqlalchemy/dialects/oracle/vector.py +368 -0
  44. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  45. sqlalchemy/dialects/postgresql/_psycopg_common.py +193 -0
  46. sqlalchemy/dialects/postgresql/array.py +534 -0
  47. sqlalchemy/dialects/postgresql/asyncpg.py +1331 -0
  48. sqlalchemy/dialects/postgresql/base.py +5729 -0
  49. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  50. sqlalchemy/dialects/postgresql/dml.py +360 -0
  51. sqlalchemy/dialects/postgresql/ext.py +593 -0
  52. sqlalchemy/dialects/postgresql/hstore.py +413 -0
  53. sqlalchemy/dialects/postgresql/json.py +407 -0
  54. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  55. sqlalchemy/dialects/postgresql/operators.py +130 -0
  56. sqlalchemy/dialects/postgresql/pg8000.py +672 -0
  57. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  58. sqlalchemy/dialects/postgresql/provision.py +175 -0
  59. sqlalchemy/dialects/postgresql/psycopg.py +815 -0
  60. sqlalchemy/dialects/postgresql/psycopg2.py +887 -0
  61. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  62. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  63. sqlalchemy/dialects/postgresql/types.py +388 -0
  64. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  65. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  66. sqlalchemy/dialects/sqlite/base.py +3050 -0
  67. sqlalchemy/dialects/sqlite/dml.py +279 -0
  68. sqlalchemy/dialects/sqlite/json.py +89 -0
  69. sqlalchemy/dialects/sqlite/provision.py +223 -0
  70. sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
  71. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  72. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  73. sqlalchemy/engine/__init__.py +62 -0
  74. sqlalchemy/engine/_processors_cy.cp313-win_arm64.pyd +0 -0
  75. sqlalchemy/engine/_processors_cy.py +92 -0
  76. sqlalchemy/engine/_result_cy.cp313-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_result_cy.py +633 -0
  78. sqlalchemy/engine/_row_cy.cp313-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_row_cy.py +232 -0
  80. sqlalchemy/engine/_util_cy.cp313-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_util_cy.py +136 -0
  82. sqlalchemy/engine/base.py +3334 -0
  83. sqlalchemy/engine/characteristics.py +155 -0
  84. sqlalchemy/engine/create.py +869 -0
  85. sqlalchemy/engine/cursor.py +2416 -0
  86. sqlalchemy/engine/default.py +2393 -0
  87. sqlalchemy/engine/events.py +965 -0
  88. sqlalchemy/engine/interfaces.py +3465 -0
  89. sqlalchemy/engine/mock.py +134 -0
  90. sqlalchemy/engine/processors.py +82 -0
  91. sqlalchemy/engine/reflection.py +2100 -0
  92. sqlalchemy/engine/result.py +1932 -0
  93. sqlalchemy/engine/row.py +397 -0
  94. sqlalchemy/engine/strategies.py +16 -0
  95. sqlalchemy/engine/url.py +922 -0
  96. sqlalchemy/engine/util.py +156 -0
  97. sqlalchemy/event/__init__.py +26 -0
  98. sqlalchemy/event/api.py +220 -0
  99. sqlalchemy/event/attr.py +674 -0
  100. sqlalchemy/event/base.py +472 -0
  101. sqlalchemy/event/legacy.py +258 -0
  102. sqlalchemy/event/registry.py +390 -0
  103. sqlalchemy/events.py +17 -0
  104. sqlalchemy/exc.py +922 -0
  105. sqlalchemy/ext/__init__.py +11 -0
  106. sqlalchemy/ext/associationproxy.py +2072 -0
  107. sqlalchemy/ext/asyncio/__init__.py +29 -0
  108. sqlalchemy/ext/asyncio/base.py +281 -0
  109. sqlalchemy/ext/asyncio/engine.py +1475 -0
  110. sqlalchemy/ext/asyncio/exc.py +21 -0
  111. sqlalchemy/ext/asyncio/result.py +994 -0
  112. sqlalchemy/ext/asyncio/scoping.py +1667 -0
  113. sqlalchemy/ext/asyncio/session.py +1993 -0
  114. sqlalchemy/ext/automap.py +1701 -0
  115. sqlalchemy/ext/baked.py +559 -0
  116. sqlalchemy/ext/compiler.py +600 -0
  117. sqlalchemy/ext/declarative/__init__.py +65 -0
  118. sqlalchemy/ext/declarative/extensions.py +560 -0
  119. sqlalchemy/ext/horizontal_shard.py +481 -0
  120. sqlalchemy/ext/hybrid.py +1877 -0
  121. sqlalchemy/ext/indexable.py +364 -0
  122. sqlalchemy/ext/instrumentation.py +450 -0
  123. sqlalchemy/ext/mutable.py +1081 -0
  124. sqlalchemy/ext/orderinglist.py +439 -0
  125. sqlalchemy/ext/serializer.py +185 -0
  126. sqlalchemy/future/__init__.py +16 -0
  127. sqlalchemy/future/engine.py +15 -0
  128. sqlalchemy/inspection.py +174 -0
  129. sqlalchemy/log.py +283 -0
  130. sqlalchemy/orm/__init__.py +175 -0
  131. sqlalchemy/orm/_orm_constructors.py +2694 -0
  132. sqlalchemy/orm/_typing.py +179 -0
  133. sqlalchemy/orm/attributes.py +2868 -0
  134. sqlalchemy/orm/base.py +970 -0
  135. sqlalchemy/orm/bulk_persistence.py +2152 -0
  136. sqlalchemy/orm/clsregistry.py +582 -0
  137. sqlalchemy/orm/collections.py +1568 -0
  138. sqlalchemy/orm/context.py +3471 -0
  139. sqlalchemy/orm/decl_api.py +2257 -0
  140. sqlalchemy/orm/decl_base.py +2304 -0
  141. sqlalchemy/orm/dependency.py +1306 -0
  142. sqlalchemy/orm/descriptor_props.py +1183 -0
  143. sqlalchemy/orm/dynamic.py +300 -0
  144. sqlalchemy/orm/evaluator.py +379 -0
  145. sqlalchemy/orm/events.py +3386 -0
  146. sqlalchemy/orm/exc.py +237 -0
  147. sqlalchemy/orm/identity.py +302 -0
  148. sqlalchemy/orm/instrumentation.py +746 -0
  149. sqlalchemy/orm/interfaces.py +1589 -0
  150. sqlalchemy/orm/loading.py +1684 -0
  151. sqlalchemy/orm/mapped_collection.py +557 -0
  152. sqlalchemy/orm/mapper.py +4406 -0
  153. sqlalchemy/orm/path_registry.py +814 -0
  154. sqlalchemy/orm/persistence.py +1789 -0
  155. sqlalchemy/orm/properties.py +973 -0
  156. sqlalchemy/orm/query.py +3521 -0
  157. sqlalchemy/orm/relationships.py +3570 -0
  158. sqlalchemy/orm/scoping.py +2220 -0
  159. sqlalchemy/orm/session.py +5389 -0
  160. sqlalchemy/orm/state.py +1175 -0
  161. sqlalchemy/orm/state_changes.py +196 -0
  162. sqlalchemy/orm/strategies.py +3480 -0
  163. sqlalchemy/orm/strategy_options.py +2544 -0
  164. sqlalchemy/orm/sync.py +164 -0
  165. sqlalchemy/orm/unitofwork.py +798 -0
  166. sqlalchemy/orm/util.py +2435 -0
  167. sqlalchemy/orm/writeonly.py +694 -0
  168. sqlalchemy/pool/__init__.py +41 -0
  169. sqlalchemy/pool/base.py +1514 -0
  170. sqlalchemy/pool/events.py +372 -0
  171. sqlalchemy/pool/impl.py +582 -0
  172. sqlalchemy/py.typed +0 -0
  173. sqlalchemy/schema.py +72 -0
  174. sqlalchemy/sql/__init__.py +153 -0
  175. sqlalchemy/sql/_dml_constructors.py +132 -0
  176. sqlalchemy/sql/_elements_constructors.py +2147 -0
  177. sqlalchemy/sql/_orm_types.py +20 -0
  178. sqlalchemy/sql/_selectable_constructors.py +773 -0
  179. sqlalchemy/sql/_typing.py +486 -0
  180. sqlalchemy/sql/_util_cy.cp313-win_arm64.pyd +0 -0
  181. sqlalchemy/sql/_util_cy.py +127 -0
  182. sqlalchemy/sql/annotation.py +590 -0
  183. sqlalchemy/sql/base.py +2602 -0
  184. sqlalchemy/sql/cache_key.py +1066 -0
  185. sqlalchemy/sql/coercions.py +1373 -0
  186. sqlalchemy/sql/compiler.py +8259 -0
  187. sqlalchemy/sql/crud.py +1807 -0
  188. sqlalchemy/sql/ddl.py +1928 -0
  189. sqlalchemy/sql/default_comparator.py +654 -0
  190. sqlalchemy/sql/dml.py +1974 -0
  191. sqlalchemy/sql/elements.py +6016 -0
  192. sqlalchemy/sql/events.py +458 -0
  193. sqlalchemy/sql/expression.py +170 -0
  194. sqlalchemy/sql/functions.py +2257 -0
  195. sqlalchemy/sql/lambdas.py +1443 -0
  196. sqlalchemy/sql/naming.py +209 -0
  197. sqlalchemy/sql/operators.py +2897 -0
  198. sqlalchemy/sql/roles.py +332 -0
  199. sqlalchemy/sql/schema.py +6560 -0
  200. sqlalchemy/sql/selectable.py +7497 -0
  201. sqlalchemy/sql/sqltypes.py +4050 -0
  202. sqlalchemy/sql/traversals.py +1042 -0
  203. sqlalchemy/sql/type_api.py +2425 -0
  204. sqlalchemy/sql/util.py +1495 -0
  205. sqlalchemy/sql/visitors.py +1157 -0
  206. sqlalchemy/testing/__init__.py +96 -0
  207. sqlalchemy/testing/assertions.py +1007 -0
  208. sqlalchemy/testing/assertsql.py +519 -0
  209. sqlalchemy/testing/asyncio.py +128 -0
  210. sqlalchemy/testing/config.py +440 -0
  211. sqlalchemy/testing/engines.py +478 -0
  212. sqlalchemy/testing/entities.py +117 -0
  213. sqlalchemy/testing/exclusions.py +476 -0
  214. sqlalchemy/testing/fixtures/__init__.py +30 -0
  215. sqlalchemy/testing/fixtures/base.py +366 -0
  216. sqlalchemy/testing/fixtures/mypy.py +247 -0
  217. sqlalchemy/testing/fixtures/orm.py +227 -0
  218. sqlalchemy/testing/fixtures/sql.py +538 -0
  219. sqlalchemy/testing/pickleable.py +155 -0
  220. sqlalchemy/testing/plugin/__init__.py +6 -0
  221. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  222. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  223. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  224. sqlalchemy/testing/profiling.py +329 -0
  225. sqlalchemy/testing/provision.py +596 -0
  226. sqlalchemy/testing/requirements.py +1973 -0
  227. sqlalchemy/testing/schema.py +198 -0
  228. sqlalchemy/testing/suite/__init__.py +19 -0
  229. sqlalchemy/testing/suite/test_cte.py +237 -0
  230. sqlalchemy/testing/suite/test_ddl.py +420 -0
  231. sqlalchemy/testing/suite/test_dialect.py +776 -0
  232. sqlalchemy/testing/suite/test_insert.py +630 -0
  233. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  234. sqlalchemy/testing/suite/test_results.py +660 -0
  235. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  236. sqlalchemy/testing/suite/test_select.py +2112 -0
  237. sqlalchemy/testing/suite/test_sequence.py +317 -0
  238. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  239. sqlalchemy/testing/suite/test_types.py +2253 -0
  240. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  241. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  242. sqlalchemy/testing/util.py +535 -0
  243. sqlalchemy/testing/warnings.py +52 -0
  244. sqlalchemy/types.py +76 -0
  245. sqlalchemy/util/__init__.py +157 -0
  246. sqlalchemy/util/_collections.py +693 -0
  247. sqlalchemy/util/_collections_cy.cp313-win_arm64.pyd +0 -0
  248. sqlalchemy/util/_collections_cy.pxd +8 -0
  249. sqlalchemy/util/_collections_cy.py +516 -0
  250. sqlalchemy/util/_has_cython.py +46 -0
  251. sqlalchemy/util/_immutabledict_cy.cp313-win_arm64.pyd +0 -0
  252. sqlalchemy/util/_immutabledict_cy.py +240 -0
  253. sqlalchemy/util/compat.py +287 -0
  254. sqlalchemy/util/concurrency.py +322 -0
  255. sqlalchemy/util/cython.py +79 -0
  256. sqlalchemy/util/deprecations.py +401 -0
  257. sqlalchemy/util/langhelpers.py +2256 -0
  258. sqlalchemy/util/preloaded.py +152 -0
  259. sqlalchemy/util/queue.py +304 -0
  260. sqlalchemy/util/tool_support.py +201 -0
  261. sqlalchemy/util/topological.py +120 -0
  262. sqlalchemy/util/typing.py +711 -0
  263. sqlalchemy-2.1.0b1.dist-info/METADATA +267 -0
  264. sqlalchemy-2.1.0b1.dist-info/RECORD +267 -0
  265. sqlalchemy-2.1.0b1.dist-info/WHEEL +5 -0
  266. sqlalchemy-2.1.0b1.dist-info/licenses/LICENSE +19 -0
  267. sqlalchemy-2.1.0b1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,538 @@
1
+ # testing/fixtures/sql.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: ignore-errors
8
+ from __future__ import annotations
9
+
10
+ import itertools
11
+ import random
12
+ import re
13
+
14
+ import sqlalchemy as sa
15
+ from .base import TestBase
16
+ from .. import config
17
+ from .. import mock
18
+ from .. import provision
19
+ from ..assertions import eq_
20
+ from ..assertions import expect_deprecated
21
+ from ..assertions import ne_
22
+ from ..util import adict
23
+ from ..util import drop_all_tables_from_metadata
24
+ from ... import event
25
+ from ... import util
26
+ from ...schema import sort_tables_and_constraints
27
+ from ...sql import visitors
28
+ from ...sql.elements import ClauseElement
29
+
30
+
31
+ class TablesTest(TestBase):
32
+ # 'once', None
33
+ run_setup_bind = "once"
34
+
35
+ # 'once', 'each', None
36
+ run_define_tables = "once"
37
+
38
+ # 'once', 'each', None
39
+ run_create_tables = "once"
40
+
41
+ # 'once', 'each', None
42
+ run_inserts = "each"
43
+
44
+ # 'each', None
45
+ run_deletes = "each"
46
+
47
+ # 'once', None
48
+ run_dispose_bind = None
49
+
50
+ bind = None
51
+ _tables_metadata = None
52
+ tables = None
53
+ other = None
54
+ sequences = None
55
+
56
+ @config.fixture(autouse=True, scope="class")
57
+ def _setup_tables_test_class(self):
58
+ cls = self.__class__
59
+ cls._init_class()
60
+
61
+ cls._setup_once_tables()
62
+
63
+ cls._setup_once_inserts()
64
+
65
+ yield
66
+
67
+ cls._teardown_once_metadata_bind()
68
+
69
+ @config.fixture(autouse=True, scope="function")
70
+ def _setup_tables_test_instance(self):
71
+ self._setup_each_tables()
72
+ self._setup_each_inserts()
73
+
74
+ yield
75
+
76
+ self._teardown_each_tables()
77
+
78
+ @property
79
+ def tables_test_metadata(self):
80
+ return self._tables_metadata
81
+
82
+ @classmethod
83
+ def _init_class(cls):
84
+ if cls.run_define_tables == "each":
85
+ if cls.run_create_tables == "once":
86
+ cls.run_create_tables = "each"
87
+ assert cls.run_inserts in ("each", None)
88
+
89
+ cls.other = adict()
90
+ cls.tables = adict()
91
+ cls.sequences = adict()
92
+
93
+ cls.bind = cls.setup_bind()
94
+ cls._tables_metadata = sa.MetaData()
95
+
96
+ @classmethod
97
+ def _setup_once_inserts(cls):
98
+ if cls.run_inserts == "once":
99
+ cls._load_fixtures()
100
+ with cls.bind.begin() as conn:
101
+ cls.insert_data(conn)
102
+
103
+ @classmethod
104
+ def _setup_once_tables(cls):
105
+ if cls.run_define_tables == "once":
106
+ cls.define_tables(cls._tables_metadata)
107
+ if cls.run_create_tables == "once":
108
+ cls._tables_metadata.create_all(cls.bind)
109
+ cls.tables.update(cls._tables_metadata.tables)
110
+ cls.sequences.update(cls._tables_metadata._sequences)
111
+
112
+ def _setup_each_tables(self):
113
+ if self.run_define_tables == "each":
114
+ self.define_tables(self._tables_metadata)
115
+ if self.run_create_tables == "each":
116
+ self._tables_metadata.create_all(self.bind)
117
+ self.tables.update(self._tables_metadata.tables)
118
+ self.sequences.update(self._tables_metadata._sequences)
119
+ elif self.run_create_tables == "each":
120
+ self._tables_metadata.create_all(self.bind)
121
+
122
+ def _setup_each_inserts(self):
123
+ if self.run_inserts == "each":
124
+ self._load_fixtures()
125
+ with self.bind.begin() as conn:
126
+ self.insert_data(conn)
127
+
128
+ def _teardown_each_tables(self):
129
+ if self.run_define_tables == "each":
130
+ self.tables.clear()
131
+ if self.run_create_tables == "each":
132
+ drop_all_tables_from_metadata(self._tables_metadata, self.bind)
133
+ self._tables_metadata.clear()
134
+ elif self.run_create_tables == "each":
135
+ drop_all_tables_from_metadata(self._tables_metadata, self.bind)
136
+
137
+ # no need to run deletes if tables are recreated on setup
138
+ if (
139
+ self.run_define_tables != "each"
140
+ and self.run_create_tables == "once"
141
+ and self.run_deletes == "each"
142
+ ):
143
+ with self.bind.begin() as conn:
144
+ provision.delete_from_all_tables(
145
+ conn, config, self._tables_metadata
146
+ )
147
+
148
+ @classmethod
149
+ def _teardown_once_metadata_bind(cls):
150
+ if cls.run_create_tables:
151
+ drop_all_tables_from_metadata(cls._tables_metadata, cls.bind)
152
+
153
+ if cls.run_dispose_bind == "once":
154
+ cls.dispose_bind(cls.bind)
155
+
156
+ cls._tables_metadata.bind = None
157
+
158
+ if cls.run_setup_bind is not None:
159
+ cls.bind = None
160
+
161
+ @classmethod
162
+ def setup_bind(cls):
163
+ return config.db
164
+
165
+ @classmethod
166
+ def dispose_bind(cls, bind):
167
+ if hasattr(bind, "dispose"):
168
+ bind.dispose()
169
+ elif hasattr(bind, "close"):
170
+ bind.close()
171
+
172
+ @classmethod
173
+ def define_tables(cls, metadata):
174
+ pass
175
+
176
+ @classmethod
177
+ def fixtures(cls):
178
+ return {}
179
+
180
+ @classmethod
181
+ def insert_data(cls, connection):
182
+ pass
183
+
184
+ def sql_count_(self, count, fn):
185
+ self.assert_sql_count(self.bind, fn, count)
186
+
187
+ def sql_eq_(self, callable_, statements):
188
+ self.assert_sql(self.bind, callable_, statements)
189
+
190
+ @classmethod
191
+ def _load_fixtures(cls):
192
+ """Insert rows as represented by the fixtures() method."""
193
+ headers, rows = {}, {}
194
+ for table, data in cls.fixtures().items():
195
+ if len(data) < 2:
196
+ continue
197
+ if isinstance(table, str):
198
+ table = cls.tables[table]
199
+ headers[table] = data[0]
200
+ rows[table] = data[1:]
201
+ for table, fks in sort_tables_and_constraints(
202
+ cls._tables_metadata.tables.values()
203
+ ):
204
+ if table is None:
205
+ continue
206
+ if table not in headers:
207
+ continue
208
+ with cls.bind.begin() as conn:
209
+ conn.execute(
210
+ table.insert(),
211
+ [
212
+ dict(zip(headers[table], column_values))
213
+ for column_values in rows[table]
214
+ ],
215
+ )
216
+
217
+
218
+ class NoCache:
219
+ @config.fixture(autouse=True, scope="function")
220
+ def _disable_cache(self):
221
+ _cache = config.db._compiled_cache
222
+ config.db._compiled_cache = None
223
+ yield
224
+ config.db._compiled_cache = _cache
225
+
226
+
227
+ class RemovesEvents:
228
+ @util.memoized_property
229
+ def _event_fns(self):
230
+ return set()
231
+
232
+ def event_listen(self, target, name, fn, **kw):
233
+ self._event_fns.add((target, name, fn))
234
+ event.listen(target, name, fn, **kw)
235
+
236
+ @config.fixture(autouse=True, scope="function")
237
+ def _remove_events(self):
238
+ yield
239
+ for key in self._event_fns:
240
+ event.remove(*key)
241
+
242
+
243
+ class ComputedReflectionFixtureTest(TablesTest):
244
+ run_inserts = run_deletes = None
245
+
246
+ __backend__ = True
247
+ __requires__ = ("computed_columns", "table_reflection")
248
+
249
+ regexp = re.compile(r"[\[\]\(\)\s`'\"]*")
250
+
251
+ def normalize(self, text):
252
+ return self.regexp.sub("", text).lower()
253
+
254
+ @classmethod
255
+ def define_tables(cls, metadata):
256
+ from ... import Integer
257
+ from ... import testing
258
+ from ...schema import Column
259
+ from ...schema import Computed
260
+ from ...schema import Table
261
+
262
+ Table(
263
+ "computed_default_table",
264
+ metadata,
265
+ Column("id", Integer, primary_key=True),
266
+ Column("normal", Integer),
267
+ Column("computed_col", Integer, Computed("normal + 42")),
268
+ Column("with_default", Integer, server_default="42"),
269
+ )
270
+
271
+ t = Table(
272
+ "computed_column_table",
273
+ metadata,
274
+ Column("id", Integer, primary_key=True),
275
+ Column("normal", Integer),
276
+ Column("computed_no_flag", Integer, Computed("normal + 42")),
277
+ )
278
+
279
+ if testing.requires.schemas.enabled:
280
+ t2 = Table(
281
+ "computed_column_table",
282
+ metadata,
283
+ Column("id", Integer, primary_key=True),
284
+ Column("normal", Integer),
285
+ Column("computed_no_flag", Integer, Computed("normal / 42")),
286
+ schema=config.test_schema,
287
+ )
288
+
289
+ if testing.requires.computed_columns_virtual.enabled:
290
+ t.append_column(
291
+ Column(
292
+ "computed_virtual",
293
+ Integer,
294
+ Computed("normal + 2", persisted=False),
295
+ )
296
+ )
297
+ if testing.requires.schemas.enabled:
298
+ t2.append_column(
299
+ Column(
300
+ "computed_virtual",
301
+ Integer,
302
+ Computed("normal / 2", persisted=False),
303
+ )
304
+ )
305
+ if testing.requires.computed_columns_stored.enabled:
306
+ t.append_column(
307
+ Column(
308
+ "computed_stored",
309
+ Integer,
310
+ Computed("normal - 42", persisted=True),
311
+ )
312
+ )
313
+ if testing.requires.schemas.enabled:
314
+ t2.append_column(
315
+ Column(
316
+ "computed_stored",
317
+ Integer,
318
+ Computed("normal * 42", persisted=True),
319
+ )
320
+ )
321
+
322
+
323
+ class CacheKeyFixture:
324
+ def _compare_equal(self, a, b, *, compare_values=False):
325
+ a_key = a._generate_cache_key()
326
+ b_key = b._generate_cache_key()
327
+
328
+ if a_key is None:
329
+ assert a._annotations.get("nocache"), (
330
+ "Construct doesn't cache, so test suite should "
331
+ "add the 'nocache' annotation"
332
+ )
333
+
334
+ assert b_key is None
335
+ else:
336
+ eq_(a_key.key, b_key.key)
337
+ eq_(hash(a_key.key), hash(b_key.key))
338
+
339
+ for a_param, b_param in zip(a_key.bindparams, b_key.bindparams):
340
+ assert a_param.compare(b_param, compare_values=compare_values)
341
+ return a_key, b_key
342
+
343
+ def _run_compare_fixture(self, fixture, *, compare_values=False):
344
+ case_a = fixture()
345
+ case_b = fixture()
346
+
347
+ for a, b in itertools.combinations_with_replacement(
348
+ range(len(case_a)), 2
349
+ ):
350
+ if a == b:
351
+ assert case_a[a].compare(
352
+ case_b[b], compare_values=compare_values
353
+ )
354
+ else:
355
+ assert not case_a[a].compare(
356
+ case_b[b], compare_values=compare_values
357
+ )
358
+
359
+ def _run_cache_key_fixture(self, fixture, *, compare_values=False):
360
+ case_a = fixture()
361
+ case_b = fixture()
362
+
363
+ for a, b in itertools.combinations_with_replacement(
364
+ range(len(case_a)), 2
365
+ ):
366
+ if a == b:
367
+ a_key, b_key = self._compare_equal(
368
+ case_a[a], case_b[b], compare_values=compare_values
369
+ )
370
+ if a_key is None:
371
+ continue
372
+ else:
373
+ a_key = case_a[a]._generate_cache_key()
374
+ b_key = case_b[b]._generate_cache_key()
375
+
376
+ if a_key is None or b_key is None:
377
+ if a_key is None:
378
+ assert case_a[a]._annotations.get("nocache")
379
+ if b_key is None:
380
+ assert case_b[b]._annotations.get("nocache")
381
+ continue
382
+
383
+ if a_key.key == b_key.key:
384
+ for a_param, b_param in zip(
385
+ a_key.bindparams, b_key.bindparams
386
+ ):
387
+ if not a_param.compare(
388
+ b_param, compare_values=compare_values
389
+ ):
390
+ break
391
+ else:
392
+ # this fails unconditionally since we could not
393
+ # find bound parameter values that differed.
394
+ # Usually we intended to get two distinct keys here
395
+ # so the failure will be more descriptive using the
396
+ # ne_() assertion.
397
+ ne_(a_key.key, b_key.key)
398
+ else:
399
+ ne_(a_key.key, b_key.key)
400
+
401
+ # ClauseElement-specific test to ensure the cache key
402
+ # collected all the bound parameters that aren't marked
403
+ # as "literal execute"
404
+ if isinstance(case_a[a], ClauseElement) and isinstance(
405
+ case_b[b], ClauseElement
406
+ ):
407
+ assert_a_params = []
408
+ assert_b_params = []
409
+
410
+ for elem in visitors.iterate(case_a[a]):
411
+ if elem.__visit_name__ == "bindparam":
412
+ assert_a_params.append(elem)
413
+
414
+ for elem in visitors.iterate(case_b[b]):
415
+ if elem.__visit_name__ == "bindparam":
416
+ assert_b_params.append(elem)
417
+
418
+ # note we're asserting the order of the params as well as
419
+ # if there are dupes or not. ordering has to be
420
+ # deterministic and matches what a traversal would provide.
421
+ eq_(
422
+ sorted(a_key.bindparams, key=lambda b: b.key),
423
+ sorted(
424
+ util.unique_list(assert_a_params), key=lambda b: b.key
425
+ ),
426
+ )
427
+ eq_(
428
+ sorted(b_key.bindparams, key=lambda b: b.key),
429
+ sorted(
430
+ util.unique_list(assert_b_params), key=lambda b: b.key
431
+ ),
432
+ )
433
+
434
+ def _run_cache_key_equal_fixture(self, fixture, compare_values):
435
+ case_a = fixture()
436
+ case_b = fixture()
437
+
438
+ for a, b in itertools.combinations_with_replacement(
439
+ range(len(case_a)), 2
440
+ ):
441
+ self._compare_equal(
442
+ case_a[a], case_b[b], compare_values=compare_values
443
+ )
444
+
445
+
446
+ class CacheKeySuite(CacheKeyFixture):
447
+ @classmethod
448
+ def run_suite_tests(cls, fn):
449
+ def decorate(self):
450
+ self._run_cache_key_fixture(fn(self), compare_values=False)
451
+ self._run_compare_fixture(fn(self), compare_values=False)
452
+
453
+ decorate.__name__ = fn.__name__
454
+ return decorate
455
+
456
+
457
+ def insertmanyvalues_fixture(
458
+ connection, randomize_rows=False, warn_on_downgraded=False
459
+ ):
460
+ dialect = connection.dialect
461
+ orig_dialect = dialect._deliver_insertmanyvalues_batches
462
+ orig_conn = connection._exec_insertmany_context
463
+
464
+ class RandomCursor:
465
+ __slots__ = ("cursor",)
466
+
467
+ def __init__(self, cursor):
468
+ self.cursor = cursor
469
+
470
+ # only this method is called by the deliver method.
471
+ # by not having the other methods we assert that those aren't being
472
+ # used
473
+
474
+ @property
475
+ def description(self):
476
+ return self.cursor.description
477
+
478
+ def fetchall(self):
479
+ rows = self.cursor.fetchall()
480
+ rows = list(rows)
481
+ random.shuffle(rows)
482
+ return rows
483
+
484
+ def _deliver_insertmanyvalues_batches(
485
+ connection,
486
+ cursor,
487
+ statement,
488
+ parameters,
489
+ generic_setinputsizes,
490
+ context,
491
+ ):
492
+ if randomize_rows:
493
+ cursor = RandomCursor(cursor)
494
+ for batch in orig_dialect(
495
+ connection,
496
+ cursor,
497
+ statement,
498
+ parameters,
499
+ generic_setinputsizes,
500
+ context,
501
+ ):
502
+ if warn_on_downgraded and batch.is_downgraded:
503
+ util.warn("Batches were downgraded for sorted INSERT")
504
+
505
+ yield batch
506
+
507
+ def _exec_insertmany_context(dialect, context):
508
+ with mock.patch.object(
509
+ dialect,
510
+ "_deliver_insertmanyvalues_batches",
511
+ new=_deliver_insertmanyvalues_batches,
512
+ ):
513
+ return orig_conn(dialect, context)
514
+
515
+ connection._exec_insertmany_context = _exec_insertmany_context
516
+
517
+
518
+ class DistinctOnFixture:
519
+ @config.fixture(params=["legacy", "new"])
520
+ def distinct_on_fixture(self, request):
521
+ from sqlalchemy.dialects.postgresql import distinct_on
522
+
523
+ def go(query, *expr):
524
+ if request.param == "legacy":
525
+ if expr:
526
+ with expect_deprecated(
527
+ "Passing expression to ``distinct`` to generate a "
528
+ "DISTINCT "
529
+ "ON clause is deprecated. Use instead the "
530
+ "``postgresql.distinct_on`` function as an extension."
531
+ ):
532
+ return query.distinct(*expr)
533
+ else:
534
+ return query.distinct()
535
+ elif request.param == "new":
536
+ return query.ext(distinct_on(*expr))
537
+
538
+ return go
@@ -0,0 +1,155 @@
1
+ # testing/pickleable.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: ignore-errors
8
+
9
+
10
+ """Classes used in pickling tests, need to be at the module level for
11
+ unpickling.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from .entities import ComparableEntity
17
+ from ..schema import Column
18
+ from ..types import String
19
+
20
+
21
+ class User(ComparableEntity):
22
+ pass
23
+
24
+
25
+ class Order(ComparableEntity):
26
+ pass
27
+
28
+
29
+ class Dingaling(ComparableEntity):
30
+ pass
31
+
32
+
33
+ class EmailUser(User):
34
+ pass
35
+
36
+
37
+ class Address(ComparableEntity):
38
+ pass
39
+
40
+
41
+ # TODO: these are kind of arbitrary....
42
+ class Child1(ComparableEntity):
43
+ pass
44
+
45
+
46
+ class Child2(ComparableEntity):
47
+ pass
48
+
49
+
50
+ class Parent(ComparableEntity):
51
+ pass
52
+
53
+
54
+ class Screen:
55
+ def __init__(self, obj, parent=None):
56
+ self.obj = obj
57
+ self.parent = parent
58
+
59
+
60
+ class Mixin:
61
+ email_address = Column(String)
62
+
63
+
64
+ class AddressWMixin(Mixin, ComparableEntity):
65
+ pass
66
+
67
+
68
+ class Foo:
69
+ def __init__(self, moredata, stuff="im stuff"):
70
+ self.data = "im data"
71
+ self.stuff = stuff
72
+ self.moredata = moredata
73
+
74
+ __hash__ = object.__hash__
75
+
76
+ def __eq__(self, other):
77
+ return (
78
+ other.data == self.data
79
+ and other.stuff == self.stuff
80
+ and other.moredata == self.moredata
81
+ )
82
+
83
+
84
+ class Bar:
85
+ def __init__(self, x, y):
86
+ self.x = x
87
+ self.y = y
88
+
89
+ __hash__ = object.__hash__
90
+
91
+ def __eq__(self, other):
92
+ return (
93
+ other.__class__ is self.__class__
94
+ and other.x == self.x
95
+ and other.y == self.y
96
+ )
97
+
98
+ def __str__(self):
99
+ return "Bar(%d, %d)" % (self.x, self.y)
100
+
101
+
102
+ class OldSchool:
103
+ def __init__(self, x, y):
104
+ self.x = x
105
+ self.y = y
106
+
107
+ def __eq__(self, other):
108
+ return (
109
+ other.__class__ is self.__class__
110
+ and other.x == self.x
111
+ and other.y == self.y
112
+ )
113
+
114
+
115
+ class OldSchoolWithoutCompare:
116
+ def __init__(self, x, y):
117
+ self.x = x
118
+ self.y = y
119
+
120
+
121
+ class BarWithoutCompare:
122
+ def __init__(self, x, y):
123
+ self.x = x
124
+ self.y = y
125
+
126
+ def __str__(self):
127
+ return "Bar(%d, %d)" % (self.x, self.y)
128
+
129
+
130
+ class NotComparable:
131
+ def __init__(self, data):
132
+ self.data = data
133
+
134
+ def __hash__(self):
135
+ return id(self)
136
+
137
+ def __eq__(self, other):
138
+ return NotImplemented
139
+
140
+ def __ne__(self, other):
141
+ return NotImplemented
142
+
143
+
144
+ class BrokenComparable:
145
+ def __init__(self, data):
146
+ self.data = data
147
+
148
+ def __hash__(self):
149
+ return id(self)
150
+
151
+ def __eq__(self, other):
152
+ raise NotImplementedError
153
+
154
+ def __ne__(self, other):
155
+ raise NotImplementedError
@@ -0,0 +1,6 @@
1
+ # testing/plugin/__init__.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