SQLAlchemy 2.1.0b2__cp313-cp313t-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 (270) hide show
  1. sqlalchemy/__init__.py +298 -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 +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +89 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4166 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +698 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  21. sqlalchemy/dialects/mysql/base.py +3877 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +106 -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 +330 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +156 -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 +3977 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1601 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +158 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +909 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +368 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +229 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1323 -0
  50. sqlalchemy/dialects/postgresql/base.py +5789 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +593 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +423 -0
  55. sqlalchemy/dialects/postgresql/json.py +408 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  57. sqlalchemy/dialects/postgresql/operators.py +130 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +670 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  60. sqlalchemy/dialects/postgresql/provision.py +184 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +799 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  68. sqlalchemy/dialects/sqlite/base.py +3063 -0
  69. sqlalchemy/dialects/sqlite/dml.py +279 -0
  70. sqlalchemy/dialects/sqlite/json.py +100 -0
  71. sqlalchemy/dialects/sqlite/provision.py +229 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +161 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp313t-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp313t-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +633 -0
  80. sqlalchemy/engine/_row_cy.cp313t-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp313t-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3354 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2421 -0
  88. sqlalchemy/engine/default.py +2402 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3495 -0
  91. sqlalchemy/engine/mock.py +134 -0
  92. sqlalchemy/engine/processors.py +82 -0
  93. sqlalchemy/engine/reflection.py +2100 -0
  94. sqlalchemy/engine/result.py +1966 -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 +156 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +674 -0
  102. sqlalchemy/event/base.py +472 -0
  103. sqlalchemy/event/legacy.py +258 -0
  104. sqlalchemy/event/registry.py +390 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +922 -0
  107. sqlalchemy/ext/__init__.py +11 -0
  108. sqlalchemy/ext/associationproxy.py +2072 -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 +2007 -0
  116. sqlalchemy/ext/automap.py +1701 -0
  117. sqlalchemy/ext/baked.py +559 -0
  118. sqlalchemy/ext/compiler.py +600 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +560 -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 +439 -0
  127. sqlalchemy/ext/serializer.py +185 -0
  128. sqlalchemy/future/__init__.py +16 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +174 -0
  131. sqlalchemy/log.py +283 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +179 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +976 -0
  137. sqlalchemy/orm/bulk_persistence.py +2152 -0
  138. sqlalchemy/orm/clsregistry.py +582 -0
  139. sqlalchemy/orm/collections.py +1568 -0
  140. sqlalchemy/orm/context.py +3471 -0
  141. sqlalchemy/orm/decl_api.py +2280 -0
  142. sqlalchemy/orm/decl_base.py +2309 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +307 -0
  146. sqlalchemy/orm/evaluator.py +379 -0
  147. sqlalchemy/orm/events.py +3386 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +746 -0
  151. sqlalchemy/orm/interfaces.py +1589 -0
  152. sqlalchemy/orm/loading.py +1684 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4411 -0
  155. sqlalchemy/orm/path_registry.py +829 -0
  156. sqlalchemy/orm/persistence.py +1789 -0
  157. sqlalchemy/orm/properties.py +973 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3570 -0
  160. sqlalchemy/orm/scoping.py +2232 -0
  161. sqlalchemy/orm/session.py +5403 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3492 -0
  165. sqlalchemy/orm/strategy_options.py +2562 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +798 -0
  168. sqlalchemy/orm/util.py +2438 -0
  169. sqlalchemy/orm/writeonly.py +694 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1522 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +582 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +74 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +397 -0
  178. sqlalchemy/sql/_dml_constructors.py +132 -0
  179. sqlalchemy/sql/_elements_constructors.py +2164 -0
  180. sqlalchemy/sql/_orm_types.py +20 -0
  181. sqlalchemy/sql/_selectable_constructors.py +840 -0
  182. sqlalchemy/sql/_typing.py +487 -0
  183. sqlalchemy/sql/_util_cy.cp313t-win_arm64.pyd +0 -0
  184. sqlalchemy/sql/_util_cy.py +127 -0
  185. sqlalchemy/sql/annotation.py +590 -0
  186. sqlalchemy/sql/base.py +2699 -0
  187. sqlalchemy/sql/cache_key.py +1066 -0
  188. sqlalchemy/sql/coercions.py +1373 -0
  189. sqlalchemy/sql/compiler.py +8327 -0
  190. sqlalchemy/sql/crud.py +1815 -0
  191. sqlalchemy/sql/ddl.py +1928 -0
  192. sqlalchemy/sql/default_comparator.py +654 -0
  193. sqlalchemy/sql/dml.py +1977 -0
  194. sqlalchemy/sql/elements.py +6033 -0
  195. sqlalchemy/sql/events.py +458 -0
  196. sqlalchemy/sql/expression.py +172 -0
  197. sqlalchemy/sql/functions.py +2305 -0
  198. sqlalchemy/sql/lambdas.py +1443 -0
  199. sqlalchemy/sql/naming.py +209 -0
  200. sqlalchemy/sql/operators.py +2897 -0
  201. sqlalchemy/sql/roles.py +332 -0
  202. sqlalchemy/sql/schema.py +6703 -0
  203. sqlalchemy/sql/selectable.py +7553 -0
  204. sqlalchemy/sql/sqltypes.py +4093 -0
  205. sqlalchemy/sql/traversals.py +1042 -0
  206. sqlalchemy/sql/type_api.py +2446 -0
  207. sqlalchemy/sql/util.py +1495 -0
  208. sqlalchemy/sql/visitors.py +1157 -0
  209. sqlalchemy/testing/__init__.py +96 -0
  210. sqlalchemy/testing/assertions.py +1007 -0
  211. sqlalchemy/testing/assertsql.py +519 -0
  212. sqlalchemy/testing/asyncio.py +128 -0
  213. sqlalchemy/testing/config.py +440 -0
  214. sqlalchemy/testing/engines.py +483 -0
  215. sqlalchemy/testing/entities.py +117 -0
  216. sqlalchemy/testing/exclusions.py +476 -0
  217. sqlalchemy/testing/fixtures/__init__.py +30 -0
  218. sqlalchemy/testing/fixtures/base.py +384 -0
  219. sqlalchemy/testing/fixtures/mypy.py +247 -0
  220. sqlalchemy/testing/fixtures/orm.py +227 -0
  221. sqlalchemy/testing/fixtures/sql.py +538 -0
  222. sqlalchemy/testing/pickleable.py +155 -0
  223. sqlalchemy/testing/plugin/__init__.py +6 -0
  224. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  225. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  226. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  227. sqlalchemy/testing/profiling.py +329 -0
  228. sqlalchemy/testing/provision.py +613 -0
  229. sqlalchemy/testing/requirements.py +1978 -0
  230. sqlalchemy/testing/schema.py +198 -0
  231. sqlalchemy/testing/suite/__init__.py +19 -0
  232. sqlalchemy/testing/suite/test_cte.py +237 -0
  233. sqlalchemy/testing/suite/test_ddl.py +420 -0
  234. sqlalchemy/testing/suite/test_dialect.py +776 -0
  235. sqlalchemy/testing/suite/test_insert.py +630 -0
  236. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  237. sqlalchemy/testing/suite/test_results.py +660 -0
  238. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  239. sqlalchemy/testing/suite/test_select.py +2112 -0
  240. sqlalchemy/testing/suite/test_sequence.py +317 -0
  241. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  242. sqlalchemy/testing/suite/test_types.py +2271 -0
  243. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  244. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  245. sqlalchemy/testing/util.py +535 -0
  246. sqlalchemy/testing/warnings.py +52 -0
  247. sqlalchemy/types.py +76 -0
  248. sqlalchemy/util/__init__.py +158 -0
  249. sqlalchemy/util/_collections.py +688 -0
  250. sqlalchemy/util/_collections_cy.cp313t-win_arm64.pyd +0 -0
  251. sqlalchemy/util/_collections_cy.pxd +8 -0
  252. sqlalchemy/util/_collections_cy.py +516 -0
  253. sqlalchemy/util/_has_cython.py +46 -0
  254. sqlalchemy/util/_immutabledict_cy.cp313t-win_arm64.pyd +0 -0
  255. sqlalchemy/util/_immutabledict_cy.py +240 -0
  256. sqlalchemy/util/compat.py +299 -0
  257. sqlalchemy/util/concurrency.py +322 -0
  258. sqlalchemy/util/cython.py +79 -0
  259. sqlalchemy/util/deprecations.py +401 -0
  260. sqlalchemy/util/langhelpers.py +2320 -0
  261. sqlalchemy/util/preloaded.py +152 -0
  262. sqlalchemy/util/queue.py +304 -0
  263. sqlalchemy/util/tool_support.py +201 -0
  264. sqlalchemy/util/topological.py +120 -0
  265. sqlalchemy/util/typing.py +711 -0
  266. sqlalchemy-2.1.0b2.dist-info/METADATA +269 -0
  267. sqlalchemy-2.1.0b2.dist-info/RECORD +270 -0
  268. sqlalchemy-2.1.0b2.dist-info/WHEEL +5 -0
  269. sqlalchemy-2.1.0b2.dist-info/licenses/LICENSE +19 -0
  270. sqlalchemy-2.1.0b2.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,226 @@
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
+ from __future__ import annotations
32
+
33
+ from types import ModuleType
34
+ from typing import Any
35
+ from typing import Optional
36
+ from typing import TYPE_CHECKING
37
+ from typing import Union
38
+
39
+ from .pymysql import MySQLDialect_pymysql
40
+ from ...connectors.asyncio import AsyncAdapt_dbapi_connection
41
+ from ...connectors.asyncio import AsyncAdapt_dbapi_cursor
42
+ from ...connectors.asyncio import AsyncAdapt_dbapi_module
43
+ from ...connectors.asyncio import AsyncAdapt_dbapi_ss_cursor
44
+ from ...connectors.asyncio import AsyncAdapt_terminate
45
+ from ...util.concurrency import await_
46
+
47
+ if TYPE_CHECKING:
48
+
49
+ from ...connectors.asyncio import AsyncIODBAPIConnection
50
+ from ...connectors.asyncio import AsyncIODBAPICursor
51
+ from ...engine.interfaces import ConnectArgsType
52
+ from ...engine.interfaces import DBAPIConnection
53
+ from ...engine.interfaces import DBAPICursor
54
+ from ...engine.interfaces import DBAPIModule
55
+ from ...engine.interfaces import PoolProxiedConnection
56
+ from ...engine.url import URL
57
+
58
+
59
+ class AsyncAdapt_aiomysql_cursor(AsyncAdapt_dbapi_cursor):
60
+ __slots__ = ()
61
+
62
+ def _make_new_cursor(
63
+ self, connection: AsyncIODBAPIConnection
64
+ ) -> AsyncIODBAPICursor:
65
+ return connection.cursor(self._adapt_connection.dbapi.Cursor)
66
+
67
+
68
+ class AsyncAdapt_aiomysql_ss_cursor(
69
+ AsyncAdapt_dbapi_ss_cursor, AsyncAdapt_aiomysql_cursor
70
+ ):
71
+ __slots__ = ()
72
+
73
+ def _make_new_cursor(
74
+ self, connection: AsyncIODBAPIConnection
75
+ ) -> AsyncIODBAPICursor:
76
+ return connection.cursor(
77
+ self._adapt_connection.dbapi.aiomysql.cursors.SSCursor
78
+ )
79
+
80
+
81
+ class AsyncAdapt_aiomysql_connection(
82
+ AsyncAdapt_terminate, AsyncAdapt_dbapi_connection
83
+ ):
84
+ __slots__ = ()
85
+
86
+ _cursor_cls = AsyncAdapt_aiomysql_cursor
87
+ _ss_cursor_cls = AsyncAdapt_aiomysql_ss_cursor
88
+
89
+ def ping(self, reconnect: bool) -> None:
90
+ assert not reconnect
91
+ await_(self._connection.ping(reconnect))
92
+
93
+ def character_set_name(self) -> Optional[str]:
94
+ return self._connection.character_set_name() # type: ignore[no-any-return] # noqa: E501
95
+
96
+ def autocommit(self, value: Any) -> None:
97
+ await_(self._connection.autocommit(value))
98
+
99
+ def get_autocommit(self) -> bool:
100
+ return self._connection.get_autocommit() # type: ignore
101
+
102
+ def close(self) -> None:
103
+ await_(self._connection.ensure_closed())
104
+
105
+ async def _terminate_graceful_close(self) -> None:
106
+ await self._connection.ensure_closed()
107
+
108
+ def _terminate_force_close(self) -> None:
109
+ # it's not awaitable.
110
+ self._connection.close()
111
+
112
+
113
+ class AsyncAdapt_aiomysql_dbapi(AsyncAdapt_dbapi_module):
114
+ def __init__(self, aiomysql: ModuleType, pymysql: ModuleType):
115
+ super().__init__(aiomysql, dbapi_module=pymysql)
116
+ self.aiomysql = aiomysql
117
+ self.pymysql = pymysql
118
+ self.paramstyle = "format"
119
+ self._init_dbapi_attributes()
120
+ self.Cursor, self.SSCursor = self._init_cursors_subclasses()
121
+
122
+ def _init_dbapi_attributes(self) -> None:
123
+ for name in (
124
+ "Warning",
125
+ "Error",
126
+ "InterfaceError",
127
+ "DataError",
128
+ "DatabaseError",
129
+ "OperationalError",
130
+ "InterfaceError",
131
+ "IntegrityError",
132
+ "ProgrammingError",
133
+ "InternalError",
134
+ "NotSupportedError",
135
+ ):
136
+ setattr(self, name, getattr(self.aiomysql, name))
137
+
138
+ for name in (
139
+ "NUMBER",
140
+ "STRING",
141
+ "DATETIME",
142
+ "BINARY",
143
+ "TIMESTAMP",
144
+ "Binary",
145
+ ):
146
+ setattr(self, name, getattr(self.pymysql, name))
147
+
148
+ def connect(self, *arg: Any, **kw: Any) -> AsyncAdapt_aiomysql_connection:
149
+ creator_fn = kw.pop("async_creator_fn", self.aiomysql.connect)
150
+
151
+ return await_(
152
+ AsyncAdapt_aiomysql_connection.create(
153
+ self,
154
+ creator_fn(*arg, **kw),
155
+ )
156
+ )
157
+
158
+ def _init_cursors_subclasses(
159
+ self,
160
+ ) -> tuple[AsyncIODBAPICursor, AsyncIODBAPICursor]:
161
+ # suppress unconditional warning emitted by aiomysql
162
+ class Cursor(self.aiomysql.Cursor): # type: ignore[misc, name-defined]
163
+ async def _show_warnings(
164
+ self, conn: AsyncIODBAPIConnection
165
+ ) -> None:
166
+ pass
167
+
168
+ class SSCursor(self.aiomysql.SSCursor): # type: ignore[misc, name-defined] # noqa: E501
169
+ async def _show_warnings(
170
+ self, conn: AsyncIODBAPIConnection
171
+ ) -> None:
172
+ pass
173
+
174
+ return Cursor, SSCursor # type: ignore[return-value]
175
+
176
+
177
+ class MySQLDialect_aiomysql(MySQLDialect_pymysql):
178
+ driver = "aiomysql"
179
+ supports_statement_cache = True
180
+
181
+ supports_server_side_cursors = True
182
+ _sscursor = AsyncAdapt_aiomysql_ss_cursor
183
+
184
+ is_async = True
185
+ has_terminate = True
186
+
187
+ @classmethod
188
+ def import_dbapi(cls) -> AsyncAdapt_aiomysql_dbapi:
189
+ return AsyncAdapt_aiomysql_dbapi(
190
+ __import__("aiomysql"), __import__("pymysql")
191
+ )
192
+
193
+ def do_terminate(self, dbapi_connection: DBAPIConnection) -> None:
194
+ dbapi_connection.terminate()
195
+
196
+ def create_connect_args(
197
+ self, url: URL, _translate_args: Optional[dict[str, Any]] = None
198
+ ) -> ConnectArgsType:
199
+ return super().create_connect_args(
200
+ url, _translate_args=dict(username="user", database="db")
201
+ )
202
+
203
+ def is_disconnect(
204
+ self,
205
+ e: DBAPIModule.Error,
206
+ connection: Optional[Union[PoolProxiedConnection, DBAPIConnection]],
207
+ cursor: Optional[DBAPICursor],
208
+ ) -> bool:
209
+ if super().is_disconnect(e, connection, cursor):
210
+ return True
211
+ else:
212
+ str_e = str(e).lower()
213
+ return "not connected" in str_e
214
+
215
+ def _found_rows_client_flag(self) -> int:
216
+ from pymysql.constants import CLIENT # type: ignore
217
+
218
+ return CLIENT.FOUND_ROWS # type: ignore[no-any-return]
219
+
220
+ def get_driver_connection(
221
+ self, connection: DBAPIConnection
222
+ ) -> AsyncIODBAPIConnection:
223
+ return connection._connection # type: ignore[no-any-return]
224
+
225
+
226
+ dialect = MySQLDialect_aiomysql