SQLAlchemy 2.1.0rc1__cp315-cp315-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 (276) hide show
  1. sqlalchemy/__init__.py +299 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +248 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +29 -0
  8. sqlalchemy/dialects/mssql/__init__.py +88 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4833 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +345 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +242 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +130 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +697 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +260 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +241 -0
  21. sqlalchemy/dialects/mysql/base.py +3896 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +107 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +314 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +291 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +318 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +188 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3847 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1736 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +157 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +898 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +366 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +170 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +232 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1318 -0
  50. sqlalchemy/dialects/postgresql/base.py +5935 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +599 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +422 -0
  55. sqlalchemy/dialects/postgresql/json.py +411 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +535 -0
  57. sqlalchemy/dialects/postgresql/operators.py +129 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +655 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +345 -0
  60. sqlalchemy/dialects/postgresql/provision.py +202 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +800 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +62 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +59 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +375 -0
  68. sqlalchemy/dialects/sqlite/base.py +3103 -0
  69. sqlalchemy/dialects/sqlite/dml.py +314 -0
  70. sqlalchemy/dialects/sqlite/json.py +134 -0
  71. sqlalchemy/dialects/sqlite/provision.py +237 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +166 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +959 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp315-win_amd64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp315-win_amd64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +711 -0
  80. sqlalchemy/engine/_row_cy.cp315-win_amd64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp315-win_amd64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3357 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2425 -0
  88. sqlalchemy/engine/default.py +2627 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3636 -0
  91. sqlalchemy/engine/mock.py +133 -0
  92. sqlalchemy/engine/processors.py +83 -0
  93. sqlalchemy/engine/reflection.py +2141 -0
  94. sqlalchemy/engine/result.py +2012 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +164 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +675 -0
  102. sqlalchemy/event/base.py +473 -0
  103. sqlalchemy/event/legacy.py +259 -0
  104. sqlalchemy/event/registry.py +391 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +939 -0
  107. sqlalchemy/ext/__init__.py +10 -0
  108. sqlalchemy/ext/associationproxy.py +2073 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2006 -0
  116. sqlalchemy/ext/automap.py +1702 -0
  117. sqlalchemy/ext/baked.py +558 -0
  118. sqlalchemy/ext/compiler.py +601 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +561 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +440 -0
  127. sqlalchemy/ext/serializer.py +184 -0
  128. sqlalchemy/future/__init__.py +17 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +188 -0
  131. sqlalchemy/log.py +279 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +180 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +991 -0
  137. sqlalchemy/orm/bulk_persistence.py +2168 -0
  138. sqlalchemy/orm/clsregistry.py +630 -0
  139. sqlalchemy/orm/collections.py +1569 -0
  140. sqlalchemy/orm/context.py +3475 -0
  141. sqlalchemy/orm/decl_api.py +2283 -0
  142. sqlalchemy/orm/decl_base.py +2320 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +306 -0
  146. sqlalchemy/orm/evaluator.py +378 -0
  147. sqlalchemy/orm/events.py +3387 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +749 -0
  151. sqlalchemy/orm/interfaces.py +1595 -0
  152. sqlalchemy/orm/loading.py +1712 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4465 -0
  155. sqlalchemy/orm/path_registry.py +907 -0
  156. sqlalchemy/orm/persistence.py +1790 -0
  157. sqlalchemy/orm/properties.py +972 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3608 -0
  160. sqlalchemy/orm/scoping.py +2233 -0
  161. sqlalchemy/orm/session.py +5468 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3552 -0
  165. sqlalchemy/orm/strategy_options.py +2648 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +797 -0
  168. sqlalchemy/orm/util.py +2461 -0
  169. sqlalchemy/orm/writeonly.py +701 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1540 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +583 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +75 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +402 -0
  178. sqlalchemy/sql/_cache_key_cy.cp315-win_amd64.pyd +0 -0
  179. sqlalchemy/sql/_cache_key_cy.py +363 -0
  180. sqlalchemy/sql/_dml_constructors.py +132 -0
  181. sqlalchemy/sql/_elements_constructors.py +2190 -0
  182. sqlalchemy/sql/_orm_types.py +19 -0
  183. sqlalchemy/sql/_selectable_constructors.py +840 -0
  184. sqlalchemy/sql/_typing.py +500 -0
  185. sqlalchemy/sql/_util_cy.cp315-win_amd64.pyd +0 -0
  186. sqlalchemy/sql/_util_cy.pxd +11 -0
  187. sqlalchemy/sql/_util_cy.py +127 -0
  188. sqlalchemy/sql/annotation.py +590 -0
  189. sqlalchemy/sql/base.py +2702 -0
  190. sqlalchemy/sql/cache_key.py +915 -0
  191. sqlalchemy/sql/coercions.py +1373 -0
  192. sqlalchemy/sql/compiler.py +8453 -0
  193. sqlalchemy/sql/crud.py +1816 -0
  194. sqlalchemy/sql/ddl.py +1962 -0
  195. sqlalchemy/sql/default_comparator.py +660 -0
  196. sqlalchemy/sql/dml.py +2018 -0
  197. sqlalchemy/sql/elements.py +6057 -0
  198. sqlalchemy/sql/events.py +458 -0
  199. sqlalchemy/sql/expression.py +171 -0
  200. sqlalchemy/sql/functions.py +2380 -0
  201. sqlalchemy/sql/lambdas.py +1442 -0
  202. sqlalchemy/sql/naming.py +204 -0
  203. sqlalchemy/sql/operators.py +2909 -0
  204. sqlalchemy/sql/roles.py +332 -0
  205. sqlalchemy/sql/schema.py +7075 -0
  206. sqlalchemy/sql/selectable.py +7634 -0
  207. sqlalchemy/sql/sqltypes.py +4130 -0
  208. sqlalchemy/sql/traversals.py +1041 -0
  209. sqlalchemy/sql/type_api.py +2450 -0
  210. sqlalchemy/sql/util.py +1496 -0
  211. sqlalchemy/sql/visitors.py +1153 -0
  212. sqlalchemy/testing/__init__.py +97 -0
  213. sqlalchemy/testing/assertions.py +1007 -0
  214. sqlalchemy/testing/assertsql.py +519 -0
  215. sqlalchemy/testing/asyncio.py +128 -0
  216. sqlalchemy/testing/cancellation.py +237 -0
  217. sqlalchemy/testing/config.py +440 -0
  218. sqlalchemy/testing/engines.py +482 -0
  219. sqlalchemy/testing/entities.py +117 -0
  220. sqlalchemy/testing/exclusions.py +501 -0
  221. sqlalchemy/testing/fixtures/__init__.py +30 -0
  222. sqlalchemy/testing/fixtures/base.py +426 -0
  223. sqlalchemy/testing/fixtures/mypy.py +247 -0
  224. sqlalchemy/testing/fixtures/orm.py +227 -0
  225. sqlalchemy/testing/fixtures/sql.py +538 -0
  226. sqlalchemy/testing/pickleable.py +155 -0
  227. sqlalchemy/testing/plugin/__init__.py +6 -0
  228. sqlalchemy/testing/plugin/bootstrap.py +50 -0
  229. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  230. sqlalchemy/testing/plugin/pytestplugin.py +896 -0
  231. sqlalchemy/testing/profiles_file.py +350 -0
  232. sqlalchemy/testing/profiling.py +294 -0
  233. sqlalchemy/testing/provision.py +633 -0
  234. sqlalchemy/testing/requirements.py +1971 -0
  235. sqlalchemy/testing/schema.py +198 -0
  236. sqlalchemy/testing/suite/__init__.py +19 -0
  237. sqlalchemy/testing/suite/test_cte.py +237 -0
  238. sqlalchemy/testing/suite/test_ddl.py +420 -0
  239. sqlalchemy/testing/suite/test_dialect.py +776 -0
  240. sqlalchemy/testing/suite/test_insert.py +630 -0
  241. sqlalchemy/testing/suite/test_reflection.py +3815 -0
  242. sqlalchemy/testing/suite/test_results.py +660 -0
  243. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  244. sqlalchemy/testing/suite/test_select.py +2112 -0
  245. sqlalchemy/testing/suite/test_sequence.py +317 -0
  246. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  247. sqlalchemy/testing/suite/test_types.py +2271 -0
  248. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  249. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  250. sqlalchemy/testing/util.py +575 -0
  251. sqlalchemy/testing/warnings.py +52 -0
  252. sqlalchemy/types.py +75 -0
  253. sqlalchemy/util/__init__.py +165 -0
  254. sqlalchemy/util/_collections.py +688 -0
  255. sqlalchemy/util/_collections_cy.cp315-win_amd64.pyd +0 -0
  256. sqlalchemy/util/_collections_cy.pxd +8 -0
  257. sqlalchemy/util/_collections_cy.py +516 -0
  258. sqlalchemy/util/_has_cython.py +48 -0
  259. sqlalchemy/util/_immutabledict_cy.cp315-win_amd64.pyd +0 -0
  260. sqlalchemy/util/_immutabledict_cy.py +240 -0
  261. sqlalchemy/util/compat.py +298 -0
  262. sqlalchemy/util/concurrency.py +272 -0
  263. sqlalchemy/util/cython.py +95 -0
  264. sqlalchemy/util/deprecations.py +401 -0
  265. sqlalchemy/util/langhelpers.py +2797 -0
  266. sqlalchemy/util/preloaded.py +153 -0
  267. sqlalchemy/util/queue.py +304 -0
  268. sqlalchemy/util/tool_support.py +202 -0
  269. sqlalchemy/util/topological.py +120 -0
  270. sqlalchemy/util/typing.py +709 -0
  271. sqlalchemy-2.1.0rc1.dist-info/METADATA +270 -0
  272. sqlalchemy-2.1.0rc1.dist-info/RECORD +276 -0
  273. sqlalchemy-2.1.0rc1.dist-info/WHEEL +5 -0
  274. sqlalchemy-2.1.0rc1.dist-info/licenses/AUTHORS +30 -0
  275. sqlalchemy-2.1.0rc1.dist-info/licenses/LICENSE +19 -0
  276. sqlalchemy-2.1.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,106 @@
1
+ # dialects/mysql/__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
7
+ # mypy: ignore-errors
8
+
9
+
10
+ from . import aiomysql # noqa
11
+ from . import asyncmy # noqa
12
+ from . import base # noqa
13
+ from . import cymysql # noqa
14
+ from . import mariadbconnector # noqa
15
+ from . import mysqlconnector # noqa
16
+ from . import mysqldb # noqa
17
+ from . import pymysql # noqa
18
+ from . import pyodbc # noqa
19
+ from .base import BIGINT
20
+ from .base import BINARY
21
+ from .base import BIT
22
+ from .base import BLOB
23
+ from .base import BOOLEAN
24
+ from .base import CHAR
25
+ from .base import DATE
26
+ from .base import DATETIME
27
+ from .base import DECIMAL
28
+ from .base import DOUBLE
29
+ from .base import ENUM
30
+ from .base import FLOAT
31
+ from .base import INTEGER
32
+ from .base import JSON
33
+ from .base import LONGBLOB
34
+ from .base import LONGTEXT
35
+ from .base import MEDIUMBLOB
36
+ from .base import MEDIUMINT
37
+ from .base import MEDIUMTEXT
38
+ from .base import NCHAR
39
+ from .base import NUMERIC
40
+ from .base import NVARCHAR
41
+ from .base import REAL
42
+ from .base import SET
43
+ from .base import SMALLINT
44
+ from .base import TEXT
45
+ from .base import TIME
46
+ from .base import TIMESTAMP
47
+ from .base import TINYBLOB
48
+ from .base import TINYINT
49
+ from .base import TINYTEXT
50
+ from .base import VARBINARY
51
+ from .base import VARCHAR
52
+ from .base import YEAR
53
+ from .dml import Insert
54
+ from .dml import insert
55
+ from .dml import limit
56
+ from .expression import match
57
+ from .mariadb import INET4
58
+ from .mariadb import INET6
59
+
60
+ # default dialect
61
+ base.dialect = dialect = mysqldb.dialect
62
+
63
+ __all__ = (
64
+ "BIGINT",
65
+ "BINARY",
66
+ "BIT",
67
+ "BLOB",
68
+ "BOOLEAN",
69
+ "CHAR",
70
+ "DATE",
71
+ "DATETIME",
72
+ "DECIMAL",
73
+ "DOUBLE",
74
+ "ENUM",
75
+ "FLOAT",
76
+ "INET4",
77
+ "INET6",
78
+ "INTEGER",
79
+ "INTEGER",
80
+ "JSON",
81
+ "LONGBLOB",
82
+ "LONGTEXT",
83
+ "MEDIUMBLOB",
84
+ "MEDIUMINT",
85
+ "MEDIUMTEXT",
86
+ "NCHAR",
87
+ "NVARCHAR",
88
+ "NUMERIC",
89
+ "SET",
90
+ "SMALLINT",
91
+ "REAL",
92
+ "TEXT",
93
+ "TIME",
94
+ "TIMESTAMP",
95
+ "TINYBLOB",
96
+ "TINYINT",
97
+ "TINYTEXT",
98
+ "VARBINARY",
99
+ "VARCHAR",
100
+ "YEAR",
101
+ "dialect",
102
+ "insert",
103
+ "Insert",
104
+ "match",
105
+ "limit",
106
+ )
@@ -0,0 +1,312 @@
1
+ # dialects/mysql/_mariadb_shim.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
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+ from typing import cast
12
+ from typing import Optional
13
+ from typing import Type
14
+ from typing import TYPE_CHECKING
15
+
16
+ from .reserved_words import RESERVED_WORDS_MARIADB
17
+ from ... import exc
18
+ from ... import schema as sa_schema
19
+ from ... import util
20
+ from ...engine import cursor as _cursor
21
+ from ...engine import default
22
+ from ...engine.default import DefaultDialect
23
+ from ...engine.interfaces import TypeCompiler
24
+ from ...sql import elements
25
+ from ...sql import sqltypes
26
+ from ...sql.compiler import DDLCompiler
27
+ from ...sql.compiler import IdentifierPreparer
28
+ from ...sql.compiler import SQLCompiler
29
+ from ...sql.schema import SchemaConst
30
+ from ...sql.sqltypes import _UUID_RETURN
31
+ from ...sql.sqltypes import UUID
32
+ from ...sql.sqltypes import Uuid
33
+
34
+ if TYPE_CHECKING:
35
+ from .base import MySQLIdentifierPreparer
36
+ from .mariadb import INET4
37
+ from .mariadb import INET6
38
+ from ...engine import URL
39
+ from ...engine.base import Connection
40
+ from ...sql import ddl
41
+ from ...sql.schema import IdentityOptions
42
+ from ...sql.schema import Sequence as Sequence_SchemaItem
43
+ from ...sql.type_api import _BindProcessorType
44
+
45
+
46
+ class _MariaDBUUID(UUID[_UUID_RETURN]):
47
+ def __init__(self, as_uuid: bool = True, native_uuid: bool = True):
48
+ self.as_uuid = as_uuid
49
+
50
+ # the _MariaDBUUID internal type is only invoked for a Uuid() with
51
+ # native_uuid=True. for non-native uuid type, the plain Uuid
52
+ # returns itself due to the workings of the Emulated superclass.
53
+ assert native_uuid
54
+
55
+ # for internal type, force string conversion for result_processor() as
56
+ # current drivers are returning a string, not a Python UUID object
57
+ self.native_uuid = False
58
+
59
+ @property
60
+ def native(self) -> bool: # type: ignore[override]
61
+ # override to return True, this is a native type, just turning
62
+ # off native_uuid for internal data handling
63
+ return True
64
+
65
+ def bind_processor(self, dialect: MariaDBShim) -> Optional[_BindProcessorType[_UUID_RETURN]]: # type: ignore[override] # noqa: E501
66
+ if not dialect.supports_native_uuid or not dialect._allows_uuid_binds:
67
+ return super().bind_processor(dialect) # type: ignore[return-value] # noqa: E501
68
+ else:
69
+ return None
70
+
71
+
72
+ class MariaDBTypeCompilerShim(TypeCompiler):
73
+ def visit_INET4(self, type_: INET4, **kwargs: Any) -> str:
74
+ return "INET4"
75
+
76
+ def visit_INET6(self, type_: INET6, **kwargs: Any) -> str:
77
+ return "INET6"
78
+
79
+
80
+ class MariadbExecutionContextShim(default.DefaultExecutionContext):
81
+ def post_exec(self) -> None:
82
+ if (
83
+ self.isdelete
84
+ and cast(SQLCompiler, self.compiled).effective_returning
85
+ and not self.cursor.description
86
+ ):
87
+ # All MySQL/mariadb drivers appear to not include
88
+ # cursor.description for DELETE..RETURNING with no rows if the
89
+ # WHERE criteria is a straight "false" condition such as our EMPTY
90
+ # IN condition. manufacture an empty result in this case (issue
91
+ # #10505)
92
+ #
93
+ # taken from cx_Oracle implementation
94
+ self.cursor_fetch_strategy = (
95
+ _cursor.FullyBufferedCursorFetchStrategy(
96
+ self.cursor,
97
+ [
98
+ (entry.keyname, None) # type: ignore[misc]
99
+ for entry in cast(
100
+ SQLCompiler, self.compiled
101
+ )._result_columns
102
+ ],
103
+ [],
104
+ )
105
+ )
106
+
107
+ def fire_sequence(
108
+ self, seq: Sequence_SchemaItem, type_: sqltypes.Integer
109
+ ) -> int:
110
+ return self._execute_scalar( # type: ignore[no-any-return]
111
+ (
112
+ "select nextval(%s)"
113
+ % self.identifier_preparer.format_sequence(seq)
114
+ ),
115
+ type_,
116
+ )
117
+
118
+
119
+ class MariaDBIdentifierPreparerShim(IdentifierPreparer):
120
+ def _set_mariadb(self) -> None:
121
+ self.reserved_words = RESERVED_WORDS_MARIADB
122
+
123
+
124
+ class MariaDBSQLCompilerShim(SQLCompiler):
125
+ def visit_sequence(self, sequence: sa_schema.Sequence, **kw: Any) -> str:
126
+ return "nextval(%s)" % self.preparer.format_sequence(sequence)
127
+
128
+ def _mariadb_regexp_flags(
129
+ self, flags: str, pattern: elements.ColumnElement[Any], **kw: Any
130
+ ) -> str:
131
+ return "CONCAT('(?', %s, ')', %s)" % (
132
+ self.render_literal_value(flags, sqltypes.STRINGTYPE),
133
+ self.process(pattern, **kw),
134
+ )
135
+
136
+ def _mariadb_regexp_match(
137
+ self,
138
+ op_string: str,
139
+ binary: elements.BinaryExpression[Any],
140
+ operator: Any,
141
+ **kw: Any,
142
+ ) -> str:
143
+ flags = binary.modifiers["flags"]
144
+ return "%s%s%s" % (
145
+ self.process(binary.left, **kw),
146
+ op_string,
147
+ self._mariadb_regexp_flags(flags, binary.right),
148
+ )
149
+
150
+ def _mariadb_regexp_replace_op_binary(
151
+ self, binary: elements.BinaryExpression[Any], operator: Any, **kw: Any
152
+ ) -> str:
153
+ flags = binary.modifiers["flags"]
154
+ return "REGEXP_REPLACE(%s, %s, %s)" % (
155
+ self.process(binary.left, **kw),
156
+ self._mariadb_regexp_flags(flags, binary.right.clauses[0]),
157
+ self.process(binary.right.clauses[1], **kw),
158
+ )
159
+
160
+ def _mariadb_visit_drop_check_constraint(
161
+ self, drop: ddl.DropConstraint, **kw: Any
162
+ ) -> str:
163
+ constraint = drop.element
164
+ qual = "CONSTRAINT "
165
+ const = self.preparer.format_constraint(constraint)
166
+ return "ALTER TABLE %s DROP %s%s" % (
167
+ self.preparer.format_table(constraint.table),
168
+ qual,
169
+ const,
170
+ )
171
+
172
+
173
+ class MariaDBDDLCompilerShim(DDLCompiler):
174
+ dialect: MariaDBShim
175
+
176
+ def _mariadb_get_column_specification(
177
+ self, column: sa_schema.Column[Any], **kw: Any
178
+ ) -> str:
179
+
180
+ if (
181
+ column.computed is not None
182
+ and column._user_defined_nullable is SchemaConst.NULL_UNSPECIFIED
183
+ ):
184
+ kw["_force_column_to_nullable"] = True
185
+
186
+ return self._mysql_get_column_specification(column, **kw)
187
+
188
+ def _mysql_get_column_specification(
189
+ self,
190
+ column: sa_schema.Column[Any],
191
+ *,
192
+ _force_column_to_nullable: bool = False,
193
+ **kw: Any,
194
+ ) -> str:
195
+ raise NotImplementedError()
196
+
197
+ def get_identity_options(self, identity_options: IdentityOptions) -> str:
198
+ text = super().get_identity_options(identity_options)
199
+ text = text.replace("NO CYCLE", "NOCYCLE")
200
+ return text
201
+
202
+ def _mariadb_visit_drop_check_constraint(
203
+ self, drop: ddl.DropConstraint, **kw: Any
204
+ ) -> str:
205
+ constraint = drop.element
206
+ qual = "CONSTRAINT "
207
+ const = self.preparer.format_constraint(constraint)
208
+ return "ALTER TABLE %s DROP %s%s" % (
209
+ self.preparer.format_table(constraint.table),
210
+ qual,
211
+ const,
212
+ )
213
+
214
+
215
+ class MariaDBShim(DefaultDialect):
216
+ server_version_info: tuple[int, ...]
217
+ is_mariadb: bool
218
+ _allows_uuid_binds = False
219
+
220
+ identifier_preparer: MySQLIdentifierPreparer
221
+ preparer: Type[MySQLIdentifierPreparer]
222
+
223
+ def _set_mariadb(
224
+ self, is_mariadb: Optional[bool], server_version_info: tuple[int, ...]
225
+ ) -> None:
226
+ if is_mariadb is None:
227
+ return
228
+
229
+ if not is_mariadb and self.is_mariadb:
230
+ raise exc.InvalidRequestError(
231
+ "MySQL version %s is not a MariaDB variant."
232
+ % (".".join(map(str, server_version_info)),)
233
+ )
234
+ if is_mariadb:
235
+ assert isinstance(self.colspecs, dict)
236
+ self.colspecs = util.update_copy(
237
+ self.colspecs, {Uuid: _MariaDBUUID}
238
+ )
239
+
240
+ self.identifier_preparer = self.preparer(self)
241
+ self.identifier_preparer._set_mariadb()
242
+
243
+ # this will be updated on first connect in initialize()
244
+ # if using older mariadb version
245
+ self.delete_returning = True
246
+ self.insert_returning = True
247
+
248
+ self.is_mariadb = is_mariadb
249
+
250
+ @property
251
+ def _mariadb_normalized_version_info(self) -> tuple[int, ...]:
252
+ return self.server_version_info
253
+
254
+ @property
255
+ def _is_mariadb(self) -> bool:
256
+ return self.is_mariadb
257
+
258
+ @classmethod
259
+ def _is_mariadb_from_url(cls, url: URL) -> bool:
260
+ dbapi = cls.import_dbapi()
261
+ dialect = cls(dbapi=dbapi)
262
+
263
+ cargs, cparams = dialect.create_connect_args(url)
264
+ conn = dialect.connect(*cargs, **cparams)
265
+ try:
266
+ cursor = conn.cursor()
267
+ cursor.execute("SELECT VERSION() LIKE '%MariaDB%'")
268
+ val = cursor.fetchone()[0] # type: ignore[index]
269
+ except:
270
+ raise
271
+ else:
272
+ return bool(val)
273
+ finally:
274
+ conn.close()
275
+
276
+ def _initialize_mariadb(self, connection: Connection) -> None:
277
+ assert self.is_mariadb
278
+
279
+ self.supports_sequences = self.server_version_info >= (10, 3)
280
+
281
+ self.delete_returning = self.server_version_info >= (10, 0, 5)
282
+
283
+ self.insert_returning = self.server_version_info >= (10, 5)
284
+
285
+ self._warn_for_known_db_issues()
286
+
287
+ self.supports_native_uuid = (
288
+ self.server_version_info is not None
289
+ and self.server_version_info >= (10, 7)
290
+ )
291
+ self._allows_uuid_binds = True
292
+
293
+ # ref https://mariadb.com/kb/en/mariadb-1021-release-notes/
294
+ self._support_default_function = self.server_version_info >= (10, 2, 1)
295
+
296
+ # ref https://mariadb.com/kb/en/mariadb-1045-release-notes/
297
+ self._support_float_cast = self.server_version_info >= (10, 4, 5)
298
+
299
+ def _warn_for_known_db_issues(self) -> None:
300
+ if self.is_mariadb:
301
+ mdb_version = self.server_version_info
302
+ assert mdb_version is not None
303
+ if mdb_version > (10, 2) and mdb_version < (10, 2, 9):
304
+ util.warn(
305
+ "MariaDB %r before 10.2.9 has known issues regarding "
306
+ "CHECK constraints, which impact handling of NULL values "
307
+ "with SQLAlchemy's boolean datatype (MDEV-13596). An "
308
+ "additional issue prevents proper migrations of columns "
309
+ "with CHECK constraints (MDEV-11114). Please upgrade to "
310
+ "MariaDB 10.2.9 or greater, or use the MariaDB 10.1 "
311
+ "series, to avoid these issues." % (mdb_version,)
312
+ )
@@ -0,0 +1,260 @@
1
+ # dialects/mysql/aiomysql.py
2
+ # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors <see AUTHORS
3
+ # 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
+ r"""
9
+ .. dialect:: mysql+aiomysql
10
+ :name: aiomysql
11
+ :dbapi: aiomysql
12
+ :connectstring: mysql+aiomysql://user:password@host:port/dbname[?key=value&key=value...]
13
+ :url: https://github.com/aio-libs/aiomysql
14
+
15
+ The aiomysql dialect is SQLAlchemy's second Python asyncio dialect.
16
+
17
+ Using a special asyncio mediation layer, the aiomysql dialect is usable
18
+ as the backend for the :ref:`SQLAlchemy asyncio <asyncio_toplevel>`
19
+ extension package.
20
+
21
+ This dialect should normally be used only with the
22
+ :func:`_asyncio.create_async_engine` engine creation function::
23
+
24
+ from sqlalchemy.ext.asyncio import create_async_engine
25
+
26
+ engine = create_async_engine(
27
+ "mysql+aiomysql://user:pass@hostname/dbname?charset=utf8mb4"
28
+ )
29
+
30
+ """ # noqa
31
+
32
+ from __future__ import annotations
33
+
34
+ from types import ModuleType
35
+ from typing import Any
36
+ from typing import Optional
37
+ from typing import TYPE_CHECKING
38
+ from typing import Union
39
+
40
+ from .pymysql import _connection_ping_reconnects_true
41
+ from .pymysql import MySQLDialect_pymysql
42
+ from ... import util
43
+ from ...connectors.asyncio import AsyncAdapt_dbapi_connection
44
+ from ...connectors.asyncio import AsyncAdapt_dbapi_cursor
45
+ from ...connectors.asyncio import AsyncAdapt_dbapi_module
46
+ from ...connectors.asyncio import AsyncAdapt_dbapi_ss_cursor
47
+ from ...connectors.asyncio import AsyncAdapt_terminate
48
+ from ...util import langhelpers
49
+ from ...util.concurrency import await_
50
+
51
+ if TYPE_CHECKING:
52
+
53
+ from ...connectors.asyncio import AsyncIODBAPIConnection
54
+ from ...connectors.asyncio import AsyncIODBAPICursor
55
+ from ...engine.interfaces import ConnectArgsType
56
+ from ...engine.interfaces import DBAPIConnection
57
+ from ...engine.interfaces import DBAPICursor
58
+ from ...engine.interfaces import DBAPIModule
59
+ from ...engine.interfaces import PoolProxiedConnection
60
+ from ...engine.url import URL
61
+
62
+
63
+ class AsyncAdapt_aiomysql_cursor(AsyncAdapt_dbapi_cursor):
64
+ __slots__ = ()
65
+
66
+ def _make_new_cursor(
67
+ self, connection: AsyncIODBAPIConnection
68
+ ) -> AsyncIODBAPICursor:
69
+ return connection.cursor(self._adapt_connection.dbapi.Cursor)
70
+
71
+
72
+ class AsyncAdapt_aiomysql_ss_cursor(
73
+ AsyncAdapt_dbapi_ss_cursor, AsyncAdapt_aiomysql_cursor
74
+ ):
75
+ __slots__ = ()
76
+
77
+ def _make_new_cursor(
78
+ self, connection: AsyncIODBAPIConnection
79
+ ) -> AsyncIODBAPICursor:
80
+ return connection.cursor(
81
+ self._adapt_connection.dbapi.aiomysql.cursors.SSCursor
82
+ )
83
+
84
+
85
+ class AsyncAdapt_aiomysql_connection(
86
+ AsyncAdapt_terminate, AsyncAdapt_dbapi_connection
87
+ ):
88
+ __slots__ = ()
89
+
90
+ _cursor_cls = AsyncAdapt_aiomysql_cursor
91
+ _ss_cursor_cls = AsyncAdapt_aiomysql_ss_cursor
92
+
93
+ def ping(self, reconnect: bool = False) -> None:
94
+ assert not reconnect
95
+
96
+ if self.dbapi._send_false_to_ping:
97
+ await_(self._connection.ping(reconnect=False))
98
+ else:
99
+ await_(self._connection.ping())
100
+
101
+ def character_set_name(self) -> Optional[str]:
102
+ return self._connection.character_set_name() # type: ignore[no-any-return] # noqa: E501
103
+
104
+ def autocommit(self, value: Any) -> None:
105
+ await_(self._connection.autocommit(value))
106
+
107
+ def get_autocommit(self) -> bool:
108
+ return self._connection.get_autocommit() # type: ignore[no-any-return]
109
+
110
+ def close(self) -> None:
111
+ await_(self._connection.ensure_closed())
112
+
113
+ async def _terminate_graceful_close(self) -> None:
114
+ await self._connection.ensure_closed()
115
+
116
+ def _terminate_force_close(self) -> None:
117
+ # it's not awaitable.
118
+ self._connection.close()
119
+
120
+
121
+ class AsyncAdapt_aiomysql_dbapi(AsyncAdapt_dbapi_module):
122
+ def __init__(self, aiomysql: ModuleType, pymysql: ModuleType):
123
+ super().__init__(aiomysql, dbapi_module=pymysql)
124
+ self.aiomysql = aiomysql
125
+ self.pymysql = pymysql
126
+ self.paramstyle = "format"
127
+ self._init_dbapi_attributes()
128
+ self.Cursor, self.SSCursor = self._init_cursors_subclasses()
129
+
130
+ def _init_dbapi_attributes(self) -> None:
131
+ for name in (
132
+ "Warning",
133
+ "Error",
134
+ "InterfaceError",
135
+ "DataError",
136
+ "DatabaseError",
137
+ "OperationalError",
138
+ "InterfaceError",
139
+ "IntegrityError",
140
+ "ProgrammingError",
141
+ "InternalError",
142
+ "NotSupportedError",
143
+ ):
144
+ setattr(self, name, getattr(self.aiomysql, name))
145
+
146
+ for name in (
147
+ "NUMBER",
148
+ "STRING",
149
+ "DATETIME",
150
+ "BINARY",
151
+ "TIMESTAMP",
152
+ "Binary",
153
+ ):
154
+ setattr(self, name, getattr(self.pymysql, name))
155
+
156
+ def connect(self, *arg: Any, **kw: Any) -> AsyncAdapt_aiomysql_connection:
157
+ creator_fn = kw.pop("async_creator_fn", self.aiomysql.connect)
158
+
159
+ return await_(
160
+ AsyncAdapt_aiomysql_connection.create(
161
+ self,
162
+ creator_fn(*arg, **kw),
163
+ )
164
+ )
165
+
166
+ @langhelpers.memoized_property
167
+ def _send_false_to_ping(self) -> bool:
168
+ """determine if aiomysql has deprecated, changed the default of,
169
+ or removed the 'reconnect' argument of connection.ping().
170
+
171
+ See #13306 and #10492
172
+
173
+ """ # noqa: E501
174
+
175
+ try:
176
+ Connection = __import__(
177
+ "aiomysql.connection"
178
+ ).connection.Connection
179
+ except (ImportError, AttributeError):
180
+ return True
181
+ else:
182
+ return _connection_ping_reconnects_true(Connection)
183
+
184
+ def _init_cursors_subclasses(
185
+ self,
186
+ ) -> tuple[AsyncIODBAPICursor, AsyncIODBAPICursor]:
187
+ # suppress unconditional warning emitted by aiomysql
188
+ class Cursor(self.aiomysql.Cursor): # type: ignore[misc, name-defined]
189
+ async def _show_warnings(
190
+ self, conn: AsyncIODBAPIConnection
191
+ ) -> None:
192
+ pass
193
+
194
+ class SSCursor(self.aiomysql.SSCursor): # type: ignore[misc, name-defined] # noqa: E501
195
+ async def _show_warnings(
196
+ self, conn: AsyncIODBAPIConnection
197
+ ) -> None:
198
+ pass
199
+
200
+ return Cursor, SSCursor # type: ignore[return-value]
201
+
202
+
203
+ class MySQLDialect_aiomysql(MySQLDialect_pymysql):
204
+ driver = "aiomysql"
205
+ supports_statement_cache = True
206
+
207
+ supports_server_side_cursors = True
208
+ _sscursor = AsyncAdapt_aiomysql_ss_cursor
209
+
210
+ is_async = True
211
+ has_terminate = True
212
+
213
+ @classmethod
214
+ def import_dbapi(cls) -> AsyncAdapt_aiomysql_dbapi:
215
+ return AsyncAdapt_aiomysql_dbapi(
216
+ __import__("aiomysql"), __import__("pymysql")
217
+ )
218
+
219
+ def retrieve_dbapi_version(self, dbapi: DBAPIModule) -> util.VersionInfo:
220
+ # the version of aiomysql itself, rather than that of the pymysql
221
+ # module it makes use of
222
+ aiomysql = getattr(dbapi, "aiomysql", None)
223
+ return util.parse_version_string(
224
+ getattr(aiomysql, "__version__", None)
225
+ )
226
+
227
+ def do_terminate(self, dbapi_connection: DBAPIConnection) -> None:
228
+ dbapi_connection.terminate()
229
+
230
+ def create_connect_args(
231
+ self, url: URL, _translate_args: Optional[dict[str, Any]] = None
232
+ ) -> ConnectArgsType:
233
+ return super().create_connect_args(
234
+ url, _translate_args=dict(username="user", database="db")
235
+ )
236
+
237
+ def is_disconnect(
238
+ self,
239
+ e: DBAPIModule.Error,
240
+ connection: Optional[Union[PoolProxiedConnection, DBAPIConnection]],
241
+ cursor: Optional[DBAPICursor],
242
+ ) -> bool:
243
+ if super().is_disconnect(e, connection, cursor):
244
+ return True
245
+ else:
246
+ str_e = str(e).lower()
247
+ return "not connected" in str_e
248
+
249
+ def _found_rows_client_flag(self) -> int:
250
+ from pymysql.constants import CLIENT # type: ignore[import-untyped]
251
+
252
+ return CLIENT.FOUND_ROWS # type: ignore[no-any-return]
253
+
254
+ def get_driver_connection(
255
+ self, connection: DBAPIConnection
256
+ ) -> AsyncIODBAPIConnection:
257
+ return connection._connection # type: ignore[no-any-return]
258
+
259
+
260
+ dialect = MySQLDialect_aiomysql