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,224 @@
1
+ # testing/schema.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 sys
12
+
13
+ from . import config
14
+ from . import exclusions
15
+ from .. import event
16
+ from .. import schema
17
+ from .. import types as sqltypes
18
+ from ..orm import mapped_column as _orm_mapped_column
19
+ from ..util import OrderedDict
20
+
21
+ __all__ = ["Table", "Column"]
22
+
23
+ table_options = {}
24
+
25
+
26
+ def Table(*args, **kw) -> schema.Table:
27
+ """A schema.Table wrapper/hook for dialect-specific tweaks."""
28
+
29
+ test_opts = {k: kw.pop(k) for k in list(kw) if k.startswith("test_")}
30
+
31
+ kw.update(table_options)
32
+
33
+ if exclusions.against(config._current, "mysql"):
34
+ if (
35
+ "mysql_engine" not in kw
36
+ and "mysql_type" not in kw
37
+ and "autoload_with" not in kw
38
+ ):
39
+ if "test_needs_fk" in test_opts or "test_needs_acid" in test_opts:
40
+ kw["mysql_engine"] = "InnoDB"
41
+ else:
42
+ # there are in fact test fixtures that rely upon MyISAM,
43
+ # due to MySQL / MariaDB having poor FK behavior under innodb,
44
+ # such as a self-referential table can't be deleted from at
45
+ # once without attending to per-row dependencies. We'd need to
46
+ # add special steps to some fixtures if we want to not
47
+ # explicitly state MyISAM here
48
+ kw["mysql_engine"] = "MyISAM"
49
+ elif exclusions.against(config._current, "mariadb"):
50
+ if (
51
+ "mariadb_engine" not in kw
52
+ and "mariadb_type" not in kw
53
+ and "autoload_with" not in kw
54
+ ):
55
+ if "test_needs_fk" in test_opts or "test_needs_acid" in test_opts:
56
+ kw["mariadb_engine"] = "InnoDB"
57
+ else:
58
+ kw["mariadb_engine"] = "MyISAM"
59
+
60
+ return schema.Table(*args, **kw)
61
+
62
+
63
+ def mapped_column(*args, **kw):
64
+ """An orm.mapped_column wrapper/hook for dialect-specific tweaks."""
65
+
66
+ return _schema_column(_orm_mapped_column, args, kw)
67
+
68
+
69
+ def Column(*args, **kw):
70
+ """A schema.Column wrapper/hook for dialect-specific tweaks."""
71
+
72
+ return _schema_column(schema.Column, args, kw)
73
+
74
+
75
+ def _schema_column(factory, args, kw):
76
+ test_opts = {k: kw.pop(k) for k in list(kw) if k.startswith("test_")}
77
+
78
+ if not config.requirements.foreign_key_ddl.enabled_for_config(config):
79
+ args = [arg for arg in args if not isinstance(arg, schema.ForeignKey)]
80
+
81
+ construct = factory(*args, **kw)
82
+
83
+ if factory is schema.Column:
84
+ col = construct
85
+ else:
86
+ col = construct.column
87
+
88
+ if test_opts.get("test_needs_autoincrement", False) and kw.get(
89
+ "primary_key", False
90
+ ):
91
+ if col.default is None and col.server_default is None:
92
+ col.autoincrement = True
93
+
94
+ # allow any test suite to pick up on this
95
+ col.info["test_needs_autoincrement"] = True
96
+
97
+ # hardcoded rule for oracle; this should
98
+ # be moved out
99
+ if exclusions.against(config._current, "oracle"):
100
+
101
+ def add_seq(c, tbl):
102
+ c._init_items(
103
+ schema.Sequence(
104
+ _truncate_name(
105
+ config.db.dialect, tbl.name + "_" + c.name + "_seq"
106
+ ),
107
+ optional=True,
108
+ )
109
+ )
110
+
111
+ event.listen(col, "after_parent_attach", add_seq, propagate=True)
112
+ return construct
113
+
114
+
115
+ class eq_type_affinity:
116
+ """Helper to compare types inside of datastructures based on affinity.
117
+
118
+ E.g.::
119
+
120
+ eq_(
121
+ inspect(connection).get_columns("foo"),
122
+ [
123
+ {
124
+ "name": "id",
125
+ "type": testing.eq_type_affinity(sqltypes.INTEGER),
126
+ "nullable": False,
127
+ "default": None,
128
+ "autoincrement": False,
129
+ },
130
+ {
131
+ "name": "data",
132
+ "type": testing.eq_type_affinity(sqltypes.NullType),
133
+ "nullable": True,
134
+ "default": None,
135
+ "autoincrement": False,
136
+ },
137
+ ],
138
+ )
139
+
140
+ """
141
+
142
+ def __init__(self, target):
143
+ self.target = sqltypes.to_instance(target)
144
+
145
+ def __eq__(self, other):
146
+ return self.target._type_affinity is other._type_affinity
147
+
148
+ def __ne__(self, other):
149
+ return self.target._type_affinity is not other._type_affinity
150
+
151
+
152
+ class eq_compile_type:
153
+ """similar to eq_type_affinity but uses compile"""
154
+
155
+ def __init__(self, target):
156
+ self.target = target
157
+
158
+ def __eq__(self, other):
159
+ return self.target == other.compile()
160
+
161
+ def __ne__(self, other):
162
+ return self.target != other.compile()
163
+
164
+
165
+ class eq_clause_element:
166
+ """Helper to compare SQL structures based on compare()"""
167
+
168
+ def __init__(self, target):
169
+ self.target = target
170
+
171
+ def __eq__(self, other):
172
+ return self.target.compare(other)
173
+
174
+ def __ne__(self, other):
175
+ return not self.target.compare(other)
176
+
177
+
178
+ def _truncate_name(dialect, name):
179
+ if len(name) > dialect.max_identifier_length:
180
+ return (
181
+ name[0 : max(dialect.max_identifier_length - 6, 0)]
182
+ + "_"
183
+ + hex(hash(name) % 64)[2:]
184
+ )
185
+ else:
186
+ return name
187
+
188
+
189
+ def pep435_enum(name):
190
+ # Implements PEP 435 in the minimal fashion needed by SQLAlchemy
191
+ __members__ = OrderedDict()
192
+
193
+ def __init__(self, name, value, alias=None):
194
+ self.name = name
195
+ self.value = value
196
+ self.__members__[name] = self
197
+ value_to_member[value] = self
198
+ setattr(self.__class__, name, self)
199
+ if alias:
200
+ self.__members__[alias] = self
201
+ setattr(self.__class__, alias, self)
202
+
203
+ value_to_member = {}
204
+
205
+ @classmethod
206
+ def get(cls, value):
207
+ return value_to_member[value]
208
+
209
+ someenum = type(
210
+ name,
211
+ (object,),
212
+ {"__members__": __members__, "__init__": __init__, "get": get},
213
+ )
214
+
215
+ # getframe() trick for pickling I don't understand courtesy
216
+ # Python namedtuple()
217
+ try:
218
+ module = sys._getframe(1).f_globals.get("__name__", "__main__")
219
+ except (AttributeError, ValueError):
220
+ pass
221
+ if module is not None:
222
+ someenum.__module__ = module
223
+
224
+ return someenum
@@ -0,0 +1,19 @@
1
+ # testing/suite/__init__.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
+ from .test_cte import * # noqa
8
+ from .test_ddl import * # noqa
9
+ from .test_deprecations import * # noqa
10
+ from .test_dialect import * # noqa
11
+ from .test_insert import * # noqa
12
+ from .test_reflection import * # noqa
13
+ from .test_results import * # noqa
14
+ from .test_rowcount import * # noqa
15
+ from .test_select import * # noqa
16
+ from .test_sequence import * # noqa
17
+ from .test_types import * # noqa
18
+ from .test_unicode_ddl import * # noqa
19
+ from .test_update_delete import * # noqa
@@ -0,0 +1,211 @@
1
+ # testing/suite/test_cte.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 .. import fixtures
10
+ from ..assertions import eq_
11
+ from ..schema import Column
12
+ from ..schema import Table
13
+ from ... import ForeignKey
14
+ from ... import Integer
15
+ from ... import select
16
+ from ... import String
17
+ from ... import testing
18
+
19
+
20
+ class CTETest(fixtures.TablesTest):
21
+ __backend__ = True
22
+ __requires__ = ("ctes",)
23
+
24
+ run_inserts = "each"
25
+ run_deletes = "each"
26
+
27
+ @classmethod
28
+ def define_tables(cls, metadata):
29
+ Table(
30
+ "some_table",
31
+ metadata,
32
+ Column("id", Integer, primary_key=True),
33
+ Column("data", String(50)),
34
+ Column("parent_id", ForeignKey("some_table.id")),
35
+ )
36
+
37
+ Table(
38
+ "some_other_table",
39
+ metadata,
40
+ Column("id", Integer, primary_key=True),
41
+ Column("data", String(50)),
42
+ Column("parent_id", Integer),
43
+ )
44
+
45
+ @classmethod
46
+ def insert_data(cls, connection):
47
+ connection.execute(
48
+ cls.tables.some_table.insert(),
49
+ [
50
+ {"id": 1, "data": "d1", "parent_id": None},
51
+ {"id": 2, "data": "d2", "parent_id": 1},
52
+ {"id": 3, "data": "d3", "parent_id": 1},
53
+ {"id": 4, "data": "d4", "parent_id": 3},
54
+ {"id": 5, "data": "d5", "parent_id": 3},
55
+ ],
56
+ )
57
+
58
+ def test_select_nonrecursive_round_trip(self, connection):
59
+ some_table = self.tables.some_table
60
+
61
+ cte = (
62
+ select(some_table)
63
+ .where(some_table.c.data.in_(["d2", "d3", "d4"]))
64
+ .cte("some_cte")
65
+ )
66
+ result = connection.execute(
67
+ select(cte.c.data).where(cte.c.data.in_(["d4", "d5"]))
68
+ )
69
+ eq_(result.fetchall(), [("d4",)])
70
+
71
+ def test_select_recursive_round_trip(self, connection):
72
+ some_table = self.tables.some_table
73
+
74
+ cte = (
75
+ select(some_table)
76
+ .where(some_table.c.data.in_(["d2", "d3", "d4"]))
77
+ .cte("some_cte", recursive=True)
78
+ )
79
+
80
+ cte_alias = cte.alias("c1")
81
+ st1 = some_table.alias()
82
+ # note that SQL Server requires this to be UNION ALL,
83
+ # can't be UNION
84
+ cte = cte.union_all(
85
+ select(st1).where(st1.c.id == cte_alias.c.parent_id)
86
+ )
87
+ result = connection.execute(
88
+ select(cte.c.data)
89
+ .where(cte.c.data != "d2")
90
+ .order_by(cte.c.data.desc())
91
+ )
92
+ eq_(
93
+ result.fetchall(),
94
+ [("d4",), ("d3",), ("d3",), ("d1",), ("d1",), ("d1",)],
95
+ )
96
+
97
+ def test_insert_from_select_round_trip(self, connection):
98
+ some_table = self.tables.some_table
99
+ some_other_table = self.tables.some_other_table
100
+
101
+ cte = (
102
+ select(some_table)
103
+ .where(some_table.c.data.in_(["d2", "d3", "d4"]))
104
+ .cte("some_cte")
105
+ )
106
+ connection.execute(
107
+ some_other_table.insert().from_select(
108
+ ["id", "data", "parent_id"], select(cte)
109
+ )
110
+ )
111
+ eq_(
112
+ connection.execute(
113
+ select(some_other_table).order_by(some_other_table.c.id)
114
+ ).fetchall(),
115
+ [(2, "d2", 1), (3, "d3", 1), (4, "d4", 3)],
116
+ )
117
+
118
+ @testing.requires.ctes_with_update_delete
119
+ @testing.requires.update_from
120
+ def test_update_from_round_trip(self, connection):
121
+ some_table = self.tables.some_table
122
+ some_other_table = self.tables.some_other_table
123
+
124
+ connection.execute(
125
+ some_other_table.insert().from_select(
126
+ ["id", "data", "parent_id"], select(some_table)
127
+ )
128
+ )
129
+
130
+ cte = (
131
+ select(some_table)
132
+ .where(some_table.c.data.in_(["d2", "d3", "d4"]))
133
+ .cte("some_cte")
134
+ )
135
+ connection.execute(
136
+ some_other_table.update()
137
+ .values(parent_id=5)
138
+ .where(some_other_table.c.data == cte.c.data)
139
+ )
140
+ eq_(
141
+ connection.execute(
142
+ select(some_other_table).order_by(some_other_table.c.id)
143
+ ).fetchall(),
144
+ [
145
+ (1, "d1", None),
146
+ (2, "d2", 5),
147
+ (3, "d3", 5),
148
+ (4, "d4", 5),
149
+ (5, "d5", 3),
150
+ ],
151
+ )
152
+
153
+ @testing.requires.ctes_with_update_delete
154
+ @testing.requires.delete_from
155
+ def test_delete_from_round_trip(self, connection):
156
+ some_table = self.tables.some_table
157
+ some_other_table = self.tables.some_other_table
158
+
159
+ connection.execute(
160
+ some_other_table.insert().from_select(
161
+ ["id", "data", "parent_id"], select(some_table)
162
+ )
163
+ )
164
+
165
+ cte = (
166
+ select(some_table)
167
+ .where(some_table.c.data.in_(["d2", "d3", "d4"]))
168
+ .cte("some_cte")
169
+ )
170
+ connection.execute(
171
+ some_other_table.delete().where(
172
+ some_other_table.c.data == cte.c.data
173
+ )
174
+ )
175
+ eq_(
176
+ connection.execute(
177
+ select(some_other_table).order_by(some_other_table.c.id)
178
+ ).fetchall(),
179
+ [(1, "d1", None), (5, "d5", 3)],
180
+ )
181
+
182
+ @testing.requires.ctes_with_update_delete
183
+ def test_delete_scalar_subq_round_trip(self, connection):
184
+ some_table = self.tables.some_table
185
+ some_other_table = self.tables.some_other_table
186
+
187
+ connection.execute(
188
+ some_other_table.insert().from_select(
189
+ ["id", "data", "parent_id"], select(some_table)
190
+ )
191
+ )
192
+
193
+ cte = (
194
+ select(some_table)
195
+ .where(some_table.c.data.in_(["d2", "d3", "d4"]))
196
+ .cte("some_cte")
197
+ )
198
+ connection.execute(
199
+ some_other_table.delete().where(
200
+ some_other_table.c.data
201
+ == select(cte.c.data)
202
+ .where(cte.c.id == some_other_table.c.id)
203
+ .scalar_subquery()
204
+ )
205
+ )
206
+ eq_(
207
+ connection.execute(
208
+ select(some_other_table).order_by(some_other_table.c.id)
209
+ ).fetchall(),
210
+ [(1, "d1", None), (5, "d5", 3)],
211
+ )