SQLAlchemy 2.0.49__py3-none-any.whl → 2.1.0b2__py3-none-any.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 (228) hide show
  1. sqlalchemy/__init__.py +19 -4
  2. sqlalchemy/connectors/aioodbc.py +10 -33
  3. sqlalchemy/connectors/asyncio.py +80 -33
  4. sqlalchemy/connectors/pyodbc.py +2 -2
  5. sqlalchemy/dialects/mssql/__init__.py +1 -0
  6. sqlalchemy/dialects/mssql/aioodbc.py +2 -2
  7. sqlalchemy/dialects/mssql/base.py +107 -55
  8. sqlalchemy/dialects/mssql/json.py +26 -15
  9. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  10. sqlalchemy/dialects/mssql/provision.py +13 -2
  11. sqlalchemy/dialects/mssql/pyodbc.py +2 -64
  12. sqlalchemy/dialects/mysql/__init__.py +2 -0
  13. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  14. sqlalchemy/dialects/mysql/aiomysql.py +11 -35
  15. sqlalchemy/dialects/mysql/asyncmy.py +15 -32
  16. sqlalchemy/dialects/mysql/base.py +286 -358
  17. sqlalchemy/dialects/mysql/dml.py +73 -19
  18. sqlalchemy/dialects/mysql/enumerated.py +8 -13
  19. sqlalchemy/dialects/mysql/json.py +2 -1
  20. sqlalchemy/dialects/mysql/mariadb.py +8 -13
  21. sqlalchemy/dialects/mysql/mariadbconnector.py +10 -2
  22. sqlalchemy/dialects/mysql/mysqlconnector.py +8 -14
  23. sqlalchemy/dialects/mysql/mysqldb.py +5 -7
  24. sqlalchemy/dialects/mysql/pymysql.py +2 -3
  25. sqlalchemy/dialects/mysql/pyodbc.py +1 -2
  26. sqlalchemy/dialects/mysql/reflection.py +20 -23
  27. sqlalchemy/dialects/mysql/types.py +24 -14
  28. sqlalchemy/dialects/oracle/__init__.py +5 -1
  29. sqlalchemy/dialects/oracle/base.py +197 -26
  30. sqlalchemy/dialects/oracle/cx_oracle.py +104 -58
  31. sqlalchemy/dialects/oracle/json.py +158 -0
  32. sqlalchemy/dialects/oracle/oracledb.py +27 -59
  33. sqlalchemy/dialects/oracle/provision.py +0 -9
  34. sqlalchemy/dialects/oracle/types.py +51 -0
  35. sqlalchemy/dialects/oracle/vector.py +3 -0
  36. sqlalchemy/dialects/postgresql/__init__.py +5 -1
  37. sqlalchemy/dialects/postgresql/_psycopg_common.py +43 -3
  38. sqlalchemy/dialects/postgresql/array.py +17 -2
  39. sqlalchemy/dialects/postgresql/asyncpg.py +219 -180
  40. sqlalchemy/dialects/postgresql/base.py +568 -157
  41. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  42. sqlalchemy/dialects/postgresql/dml.py +39 -18
  43. sqlalchemy/dialects/postgresql/ext.py +69 -16
  44. sqlalchemy/dialects/postgresql/hstore.py +56 -39
  45. sqlalchemy/dialects/postgresql/json.py +12 -8
  46. sqlalchemy/dialects/postgresql/named_types.py +54 -57
  47. sqlalchemy/dialects/postgresql/operators.py +1 -0
  48. sqlalchemy/dialects/postgresql/pg8000.py +11 -10
  49. sqlalchemy/dialects/postgresql/pg_catalog.py +18 -0
  50. sqlalchemy/dialects/postgresql/provision.py +3 -2
  51. sqlalchemy/dialects/postgresql/psycopg.py +112 -175
  52. sqlalchemy/dialects/postgresql/psycopg2.py +2 -34
  53. sqlalchemy/dialects/postgresql/ranges.py +7 -36
  54. sqlalchemy/dialects/postgresql/types.py +87 -12
  55. sqlalchemy/dialects/sqlite/aiosqlite.py +39 -200
  56. sqlalchemy/dialects/sqlite/base.py +45 -38
  57. sqlalchemy/dialects/sqlite/dml.py +34 -18
  58. sqlalchemy/dialects/sqlite/json.py +26 -18
  59. sqlalchemy/dialects/sqlite/pysqlcipher.py +11 -7
  60. sqlalchemy/dialects/sqlite/pysqlite.py +2 -4
  61. sqlalchemy/engine/_processors_cy.py +92 -0
  62. sqlalchemy/engine/_result_cy.py +633 -0
  63. sqlalchemy/engine/_row_cy.py +232 -0
  64. sqlalchemy/engine/_util_cy.py +136 -0
  65. sqlalchemy/engine/base.py +68 -104
  66. sqlalchemy/engine/create.py +7 -29
  67. sqlalchemy/engine/cursor.py +243 -125
  68. sqlalchemy/engine/default.py +30 -22
  69. sqlalchemy/engine/events.py +6 -6
  70. sqlalchemy/engine/interfaces.py +44 -20
  71. sqlalchemy/engine/processors.py +61 -40
  72. sqlalchemy/engine/reflection.py +1 -3
  73. sqlalchemy/engine/result.py +111 -567
  74. sqlalchemy/engine/row.py +43 -46
  75. sqlalchemy/engine/url.py +4 -6
  76. sqlalchemy/engine/util.py +3 -14
  77. sqlalchemy/event/attr.py +1 -3
  78. sqlalchemy/event/base.py +1 -1
  79. sqlalchemy/exc.py +99 -9
  80. sqlalchemy/ext/associationproxy.py +71 -26
  81. sqlalchemy/ext/asyncio/__init__.py +4 -0
  82. sqlalchemy/ext/asyncio/base.py +3 -3
  83. sqlalchemy/ext/asyncio/engine.py +33 -17
  84. sqlalchemy/ext/asyncio/result.py +56 -27
  85. sqlalchemy/ext/asyncio/scoping.py +93 -13
  86. sqlalchemy/ext/asyncio/session.py +76 -16
  87. sqlalchemy/ext/automap.py +13 -13
  88. sqlalchemy/ext/baked.py +0 -11
  89. sqlalchemy/ext/declarative/extensions.py +5 -9
  90. sqlalchemy/ext/horizontal_shard.py +11 -8
  91. sqlalchemy/ext/hybrid.py +410 -68
  92. sqlalchemy/ext/indexable.py +2 -2
  93. sqlalchemy/ext/instrumentation.py +1 -1
  94. sqlalchemy/ext/mutable.py +4 -8
  95. sqlalchemy/ext/orderinglist.py +1 -1
  96. sqlalchemy/ext/serializer.py +2 -2
  97. sqlalchemy/inspection.py +2 -2
  98. sqlalchemy/log.py +7 -12
  99. sqlalchemy/orm/__init__.py +5 -0
  100. sqlalchemy/orm/_orm_constructors.py +54 -21
  101. sqlalchemy/orm/_typing.py +9 -9
  102. sqlalchemy/orm/attributes.py +102 -79
  103. sqlalchemy/orm/base.py +17 -12
  104. sqlalchemy/orm/bulk_persistence.py +54 -37
  105. sqlalchemy/orm/clsregistry.py +37 -26
  106. sqlalchemy/orm/collections.py +10 -69
  107. sqlalchemy/orm/context.py +236 -99
  108. sqlalchemy/orm/decl_api.py +617 -341
  109. sqlalchemy/orm/decl_base.py +755 -638
  110. sqlalchemy/orm/dependency.py +54 -50
  111. sqlalchemy/orm/descriptor_props.py +120 -29
  112. sqlalchemy/orm/dynamic.py +16 -16
  113. sqlalchemy/orm/events.py +209 -75
  114. sqlalchemy/orm/identity.py +1 -1
  115. sqlalchemy/orm/instrumentation.py +5 -13
  116. sqlalchemy/orm/interfaces.py +133 -40
  117. sqlalchemy/orm/loading.py +30 -32
  118. sqlalchemy/orm/mapped_collection.py +1 -1
  119. sqlalchemy/orm/mapper.py +97 -130
  120. sqlalchemy/orm/path_registry.py +56 -51
  121. sqlalchemy/orm/persistence.py +15 -14
  122. sqlalchemy/orm/properties.py +87 -49
  123. sqlalchemy/orm/query.py +108 -46
  124. sqlalchemy/orm/relationships.py +149 -87
  125. sqlalchemy/orm/scoping.py +116 -32
  126. sqlalchemy/orm/session.py +254 -131
  127. sqlalchemy/orm/state.py +20 -13
  128. sqlalchemy/orm/state_changes.py +1 -1
  129. sqlalchemy/orm/strategies.py +69 -59
  130. sqlalchemy/orm/strategy_options.py +23 -47
  131. sqlalchemy/orm/sync.py +6 -6
  132. sqlalchemy/orm/unitofwork.py +27 -25
  133. sqlalchemy/orm/util.py +92 -57
  134. sqlalchemy/orm/writeonly.py +33 -13
  135. sqlalchemy/pool/__init__.py +0 -3
  136. sqlalchemy/pool/base.py +2 -4
  137. sqlalchemy/pool/impl.py +1 -7
  138. sqlalchemy/schema.py +6 -1
  139. sqlalchemy/sql/__init__.py +11 -0
  140. sqlalchemy/sql/_annotated_cols.py +397 -0
  141. sqlalchemy/sql/_elements_constructors.py +341 -49
  142. sqlalchemy/sql/_orm_types.py +1 -1
  143. sqlalchemy/sql/_selectable_constructors.py +135 -58
  144. sqlalchemy/sql/_typing.py +15 -10
  145. sqlalchemy/sql/_util_cy.py +127 -0
  146. sqlalchemy/sql/annotation.py +9 -6
  147. sqlalchemy/sql/base.py +590 -184
  148. sqlalchemy/sql/cache_key.py +32 -23
  149. sqlalchemy/sql/coercions.py +27 -58
  150. sqlalchemy/sql/compiler.py +407 -163
  151. sqlalchemy/sql/crud.py +71 -8
  152. sqlalchemy/sql/ddl.py +548 -64
  153. sqlalchemy/sql/default_comparator.py +239 -136
  154. sqlalchemy/sql/dml.py +206 -82
  155. sqlalchemy/sql/elements.py +806 -362
  156. sqlalchemy/sql/expression.py +13 -0
  157. sqlalchemy/sql/functions.py +140 -34
  158. sqlalchemy/sql/lambdas.py +3 -2
  159. sqlalchemy/sql/operators.py +339 -65
  160. sqlalchemy/sql/roles.py +17 -8
  161. sqlalchemy/sql/schema.py +685 -207
  162. sqlalchemy/sql/selectable.py +534 -246
  163. sqlalchemy/sql/sqltypes.py +364 -201
  164. sqlalchemy/sql/traversals.py +19 -1
  165. sqlalchemy/sql/type_api.py +110 -32
  166. sqlalchemy/sql/util.py +19 -9
  167. sqlalchemy/sql/visitors.py +8 -15
  168. sqlalchemy/testing/assertions.py +14 -1
  169. sqlalchemy/testing/assertsql.py +0 -1
  170. sqlalchemy/testing/asyncio.py +0 -7
  171. sqlalchemy/testing/config.py +10 -4
  172. sqlalchemy/testing/engines.py +4 -4
  173. sqlalchemy/testing/fixtures/__init__.py +2 -0
  174. sqlalchemy/testing/fixtures/mypy.py +23 -111
  175. sqlalchemy/testing/fixtures/sql.py +61 -5
  176. sqlalchemy/testing/plugin/pytestplugin.py +3 -3
  177. sqlalchemy/testing/provision.py +16 -6
  178. sqlalchemy/testing/requirements.py +52 -19
  179. sqlalchemy/testing/suite/__init__.py +1 -1
  180. sqlalchemy/testing/suite/test_ddl.py +31 -0
  181. sqlalchemy/testing/suite/test_reflection.py +15 -15
  182. sqlalchemy/testing/suite/test_results.py +156 -0
  183. sqlalchemy/testing/suite/test_select.py +117 -15
  184. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  185. sqlalchemy/testing/suite/test_types.py +134 -10
  186. sqlalchemy/testing/util.py +1 -1
  187. sqlalchemy/types.py +2 -0
  188. sqlalchemy/util/__init__.py +3 -7
  189. sqlalchemy/util/_collections.py +11 -35
  190. sqlalchemy/{cyextension/immutabledict.pxd → util/_collections_cy.pxd} +3 -3
  191. sqlalchemy/util/_collections_cy.py +516 -0
  192. sqlalchemy/util/_has_cython.py +46 -0
  193. sqlalchemy/util/_immutabledict_cy.py +240 -0
  194. sqlalchemy/util/compat.py +27 -149
  195. sqlalchemy/util/concurrency.py +275 -63
  196. sqlalchemy/util/cython.py +79 -0
  197. sqlalchemy/util/deprecations.py +2 -2
  198. sqlalchemy/util/langhelpers.py +215 -98
  199. sqlalchemy/util/preloaded.py +2 -0
  200. sqlalchemy/util/queue.py +5 -23
  201. sqlalchemy/util/typing.py +43 -66
  202. {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/METADATA +51 -25
  203. sqlalchemy-2.1.0b2.dist-info/RECORD +263 -0
  204. sqlalchemy/cyextension/__init__.py +0 -6
  205. sqlalchemy/cyextension/collections.pyx +0 -409
  206. sqlalchemy/cyextension/immutabledict.pyx +0 -133
  207. sqlalchemy/cyextension/processors.pyx +0 -68
  208. sqlalchemy/cyextension/resultproxy.pyx +0 -102
  209. sqlalchemy/cyextension/util.pyx +0 -90
  210. sqlalchemy/engine/_py_processors.py +0 -136
  211. sqlalchemy/engine/_py_row.py +0 -128
  212. sqlalchemy/engine/_py_util.py +0 -74
  213. sqlalchemy/ext/mypy/__init__.py +0 -6
  214. sqlalchemy/ext/mypy/apply.py +0 -324
  215. sqlalchemy/ext/mypy/decl_class.py +0 -515
  216. sqlalchemy/ext/mypy/infer.py +0 -590
  217. sqlalchemy/ext/mypy/names.py +0 -335
  218. sqlalchemy/ext/mypy/plugin.py +0 -303
  219. sqlalchemy/ext/mypy/util.py +0 -357
  220. sqlalchemy/sql/_py_util.py +0 -75
  221. sqlalchemy/testing/suite/test_deprecations.py +0 -153
  222. sqlalchemy/util/_concurrency_py3k.py +0 -288
  223. sqlalchemy/util/_has_cy.py +0 -40
  224. sqlalchemy/util/_py_collections.py +0 -541
  225. sqlalchemy-2.0.49.dist-info/RECORD +0 -269
  226. {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/WHEEL +0 -0
  227. {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/licenses/LICENSE +0 -0
  228. {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/top_level.txt +0 -0
sqlalchemy/__init__.py CHANGED
@@ -47,9 +47,6 @@ from .engine import URL as URL
47
47
  from .inspection import inspect as inspect
48
48
  from .pool import AssertionPool as AssertionPool
49
49
  from .pool import AsyncAdaptedQueuePool as AsyncAdaptedQueuePool
50
- from .pool import (
51
- FallbackAsyncAdaptedQueuePool as FallbackAsyncAdaptedQueuePool,
52
- )
53
50
  from .pool import NullPool as NullPool
54
51
  from .pool import Pool as Pool
55
52
  from .pool import PoolProxiedConnection as PoolProxiedConnection
@@ -60,13 +57,19 @@ from .pool import StaticPool as StaticPool
60
57
  from .schema import BaseDDLElement as BaseDDLElement
61
58
  from .schema import BLANK_SCHEMA as BLANK_SCHEMA
62
59
  from .schema import CheckConstraint as CheckConstraint
60
+ from .schema import CheckFirst as CheckFirst
63
61
  from .schema import Column as Column
64
62
  from .schema import ColumnDefault as ColumnDefault
65
63
  from .schema import Computed as Computed
66
64
  from .schema import Constraint as Constraint
65
+ from .schema import CreateTable as CreateTable
66
+ from .schema import CreateTableAs as CreateTableAs
67
+ from .schema import CreateView as CreateView
67
68
  from .schema import DDL as DDL
68
69
  from .schema import DDLElement as DDLElement
69
70
  from .schema import DefaultClause as DefaultClause
71
+ from .schema import DropTable as DropTable
72
+ from .schema import DropView as DropView
70
73
  from .schema import ExecutableDDLElement as ExecutableDDLElement
71
74
  from .schema import FetchedValue as FetchedValue
72
75
  from .schema import ForeignKey as ForeignKey
@@ -75,14 +78,18 @@ from .schema import Identity as Identity
75
78
  from .schema import Index as Index
76
79
  from .schema import insert_sentinel as insert_sentinel
77
80
  from .schema import MetaData as MetaData
81
+ from .schema import Named as Named
78
82
  from .schema import PrimaryKeyConstraint as PrimaryKeyConstraint
79
83
  from .schema import Sequence as Sequence
80
84
  from .schema import Table as Table
85
+ from .schema import TypedColumns as TypedColumns
81
86
  from .schema import UniqueConstraint as UniqueConstraint
82
87
  from .sql import ColumnExpressionArgument as ColumnExpressionArgument
83
88
  from .sql import NotNullable as NotNullable
84
89
  from .sql import Nullable as Nullable
85
90
  from .sql import SelectLabelStyle as SelectLabelStyle
91
+ from .sql.expression import aggregate_order_by as aggregate_order_by
92
+ from .sql.expression import AggregateOrderBy as AggregateOrderBy
86
93
  from .sql.expression import Alias as Alias
87
94
  from .sql.expression import alias as alias
88
95
  from .sql.expression import AliasedReturnsRows as AliasedReturnsRows
@@ -127,6 +134,9 @@ from .sql.expression import Extract as Extract
127
134
  from .sql.expression import extract as extract
128
135
  from .sql.expression import false as false
129
136
  from .sql.expression import False_ as False_
137
+ from .sql.expression import FrameClause as FrameClause
138
+ from .sql.expression import FrameClauseType as FrameClauseType
139
+ from .sql.expression import from_dml_column as from_dml_column
130
140
  from .sql.expression import FromClause as FromClause
131
141
  from .sql.expression import FromGrouping as FromGrouping
132
142
  from .sql.expression import func as func
@@ -171,6 +181,7 @@ from .sql.expression import nullsfirst as nullsfirst
171
181
  from .sql.expression import nullslast as nullslast
172
182
  from .sql.expression import Operators as Operators
173
183
  from .sql.expression import or_ as or_
184
+ from .sql.expression import OrderByList as OrderByList
174
185
  from .sql.expression import outerjoin as outerjoin
175
186
  from .sql.expression import outparam as outparam
176
187
  from .sql.expression import Over as Over
@@ -195,6 +206,7 @@ from .sql.expression import TableClause as TableClause
195
206
  from .sql.expression import TableSample as TableSample
196
207
  from .sql.expression import tablesample as tablesample
197
208
  from .sql.expression import TableValuedAlias as TableValuedAlias
209
+ from .sql.expression import TableValuedColumn as TableValuedColumn
198
210
  from .sql.expression import text as text
199
211
  from .sql.expression import TextAsFrom as TextAsFrom
200
212
  from .sql.expression import TextClause as TextClause
@@ -203,6 +215,8 @@ from .sql.expression import true as true
203
215
  from .sql.expression import True_ as True_
204
216
  from .sql.expression import try_cast as try_cast
205
217
  from .sql.expression import TryCast as TryCast
218
+ from .sql.expression import TString as TString
219
+ from .sql.expression import tstring as tstring
206
220
  from .sql.expression import Tuple as Tuple
207
221
  from .sql.expression import tuple_ as tuple_
208
222
  from .sql.expression import type_coerce as type_coerce
@@ -249,6 +263,7 @@ from .types import LargeBinary as LargeBinary
249
263
  from .types import NCHAR as NCHAR
250
264
  from .types import NUMERIC as NUMERIC
251
265
  from .types import Numeric as Numeric
266
+ from .types import NumericCommon as NumericCommon
252
267
  from .types import NVARCHAR as NVARCHAR
253
268
  from .types import PickleType as PickleType
254
269
  from .types import REAL as REAL
@@ -269,7 +284,7 @@ from .types import Uuid as Uuid
269
284
  from .types import VARBINARY as VARBINARY
270
285
  from .types import VARCHAR as VARCHAR
271
286
 
272
- __version__ = "2.0.49"
287
+ __version__ = "2.1.0b2"
273
288
 
274
289
 
275
290
  def __go(lcls: Any) -> None:
@@ -13,13 +13,9 @@ from typing import TYPE_CHECKING
13
13
  from .asyncio import AsyncAdapt_dbapi_connection
14
14
  from .asyncio import AsyncAdapt_dbapi_cursor
15
15
  from .asyncio import AsyncAdapt_dbapi_ss_cursor
16
- from .asyncio import AsyncAdaptFallback_dbapi_connection
17
16
  from .pyodbc import PyODBCConnector
18
- from .. import pool
19
- from .. import util
20
- from ..util.concurrency import await_fallback
21
- from ..util.concurrency import await_only
22
-
17
+ from ..connectors.asyncio import AsyncAdapt_dbapi_module
18
+ from ..util.concurrency import await_
23
19
 
24
20
  if TYPE_CHECKING:
25
21
  from ..engine.interfaces import ConnectArgsType
@@ -34,7 +30,7 @@ class AsyncAdapt_aioodbc_cursor(AsyncAdapt_dbapi_cursor):
34
30
  return self._cursor._impl.setinputsizes(*inputsizes)
35
31
 
36
32
  # how it's supposed to work
37
- # return self.await_(self._cursor.setinputsizes(*inputsizes))
33
+ # return await_(self._cursor.setinputsizes(*inputsizes))
38
34
 
39
35
  @property
40
36
  def fast_executemany(self):
@@ -68,7 +64,7 @@ class AsyncAdapt_aioodbc_connection(AsyncAdapt_dbapi_connection):
68
64
  self._connection._conn.autocommit = value
69
65
 
70
66
  def ping(self, reconnect):
71
- return self.await_(self._connection.ping(reconnect))
67
+ return await_(self._connection.ping(reconnect))
72
68
 
73
69
  def add_output_converter(self, *arg, **kw):
74
70
  self._connection.add_output_converter(*arg, **kw)
@@ -105,14 +101,9 @@ class AsyncAdapt_aioodbc_connection(AsyncAdapt_dbapi_connection):
105
101
  super().close()
106
102
 
107
103
 
108
- class AsyncAdaptFallback_aioodbc_connection(
109
- AsyncAdaptFallback_dbapi_connection, AsyncAdapt_aioodbc_connection
110
- ):
111
- __slots__ = ()
112
-
113
-
114
- class AsyncAdapt_aioodbc_dbapi:
104
+ class AsyncAdapt_aioodbc_dbapi(AsyncAdapt_dbapi_module):
115
105
  def __init__(self, aioodbc, pyodbc):
106
+ super().__init__(aioodbc, dbapi_module=pyodbc)
116
107
  self.aioodbc = aioodbc
117
108
  self.pyodbc = pyodbc
118
109
  self.paramstyle = pyodbc.paramstyle
@@ -147,19 +138,14 @@ class AsyncAdapt_aioodbc_dbapi:
147
138
  setattr(self, name, getattr(self.pyodbc, name))
148
139
 
149
140
  def connect(self, *arg, **kw):
150
- async_fallback = kw.pop("async_fallback", False)
151
141
  creator_fn = kw.pop("async_creator_fn", self.aioodbc.connect)
152
142
 
153
- if util.asbool(async_fallback):
154
- return AsyncAdaptFallback_aioodbc_connection(
143
+ return await_(
144
+ AsyncAdapt_aioodbc_connection.create(
155
145
  self,
156
- await_fallback(creator_fn(*arg, **kw)),
157
- )
158
- else:
159
- return AsyncAdapt_aioodbc_connection(
160
- self,
161
- await_only(creator_fn(*arg, **kw)),
146
+ creator_fn(*arg, **kw),
162
147
  )
148
+ )
163
149
 
164
150
 
165
151
  class aiodbcConnector(PyODBCConnector):
@@ -181,14 +167,5 @@ class aiodbcConnector(PyODBCConnector):
181
167
 
182
168
  return (), kw
183
169
 
184
- @classmethod
185
- def get_pool_class(cls, url):
186
- async_fallback = url.query.get("async_fallback", False)
187
-
188
- if util.asbool(async_fallback):
189
- return pool.FallbackAsyncAdaptedQueuePool
190
- else:
191
- return pool.AsyncAdaptedQueuePool
192
-
193
170
  def get_driver_connection(self, connection):
194
171
  return connection._connection
@@ -12,23 +12,25 @@ from __future__ import annotations
12
12
  import asyncio
13
13
  import collections
14
14
  import sys
15
+ import types
15
16
  from typing import Any
16
17
  from typing import AsyncIterator
18
+ from typing import Awaitable
17
19
  from typing import Deque
18
20
  from typing import Iterator
19
21
  from typing import NoReturn
20
22
  from typing import Optional
23
+ from typing import Protocol
21
24
  from typing import Sequence
22
25
  from typing import Tuple
23
26
  from typing import Type
24
27
  from typing import TYPE_CHECKING
25
28
 
26
29
  from ..engine import AdaptedConnection
30
+ from ..exc import EmulatedDBAPIException
27
31
  from ..util import EMPTY_DICT
28
- from ..util.concurrency import await_fallback
29
- from ..util.concurrency import await_only
32
+ from ..util.concurrency import await_
30
33
  from ..util.concurrency import in_greenlet
31
- from ..util.typing import Protocol
32
34
 
33
35
  if TYPE_CHECKING:
34
36
  from ..engine.interfaces import _DBAPICursorDescription
@@ -124,13 +126,38 @@ class AsyncAdapt_dbapi_module:
124
126
 
125
127
  def __getattr__(self, key: str) -> Any: ...
126
128
 
129
+ def __init__(
130
+ self,
131
+ driver: types.ModuleType,
132
+ *,
133
+ dbapi_module: types.ModuleType | None = None,
134
+ ):
135
+ self.driver = driver
136
+ self.dbapi_module = dbapi_module
137
+
138
+ @property
139
+ def exceptions_module(self) -> types.ModuleType:
140
+ """Return the module which we think will have the exception hierarchy.
141
+
142
+ For an asyncio driver that wraps a plain DBAPI like aiomysql,
143
+ aioodbc, aiosqlite, etc. these exceptions will be from the
144
+ dbapi_module. For a "pure" driver like asyncpg these will come
145
+ from the driver module.
146
+
147
+ .. versionadded:: 2.1
148
+
149
+ """
150
+ if self.dbapi_module is not None:
151
+ return self.dbapi_module
152
+ else:
153
+ return self.driver
154
+
127
155
 
128
156
  class AsyncAdapt_dbapi_cursor:
129
157
  server_side = False
130
158
  __slots__ = (
131
159
  "_adapt_connection",
132
160
  "_connection",
133
- "await_",
134
161
  "_cursor",
135
162
  "_rows",
136
163
  "_soft_closed_memoized",
@@ -147,8 +174,6 @@ class AsyncAdapt_dbapi_cursor:
147
174
  self._adapt_connection = adapt_connection
148
175
  self._connection = adapt_connection._connection
149
176
 
150
- self.await_ = adapt_connection.await_
151
-
152
177
  cursor = self._make_new_cursor(self._connection)
153
178
  self._cursor = self._aenter_cursor(cursor)
154
179
  self._soft_closed_memoized = EMPTY_DICT
@@ -156,7 +181,10 @@ class AsyncAdapt_dbapi_cursor:
156
181
  self._rows = collections.deque()
157
182
 
158
183
  def _aenter_cursor(self, cursor: AsyncIODBAPICursor) -> AsyncIODBAPICursor:
159
- return self.await_(cursor.__aenter__()) # type: ignore[no-any-return]
184
+ try:
185
+ return await_(cursor.__aenter__()) # type: ignore[no-any-return]
186
+ except Exception as error:
187
+ self._adapt_connection._handle_exception(error)
160
188
 
161
189
  def _make_new_cursor(
162
190
  self, connection: AsyncIODBAPIConnection
@@ -217,7 +245,7 @@ class AsyncAdapt_dbapi_cursor:
217
245
  if not self._awaitable_cursor_close:
218
246
  self._cursor.close() # type: ignore[unused-coroutine]
219
247
  elif in_greenlet():
220
- self.await_(self._cursor.close())
248
+ await_(self._cursor.close())
221
249
 
222
250
  def execute(
223
251
  self,
@@ -225,7 +253,7 @@ class AsyncAdapt_dbapi_cursor:
225
253
  parameters: Optional[_DBAPISingleExecuteParams] = None,
226
254
  ) -> Any:
227
255
  try:
228
- return self.await_(self._execute_async(operation, parameters))
256
+ return await_(self._execute_async(operation, parameters))
229
257
  except Exception as error:
230
258
  self._adapt_connection._handle_exception(error)
231
259
 
@@ -235,7 +263,7 @@ class AsyncAdapt_dbapi_cursor:
235
263
  seq_of_parameters: _DBAPIMultiExecuteParams,
236
264
  ) -> Any:
237
265
  try:
238
- return self.await_(
266
+ return await_(
239
267
  self._executemany_async(operation, seq_of_parameters)
240
268
  )
241
269
  except Exception as error:
@@ -263,18 +291,16 @@ class AsyncAdapt_dbapi_cursor:
263
291
  return await self._cursor.executemany(operation, seq_of_parameters)
264
292
 
265
293
  def nextset(self) -> None:
266
- self.await_(self._cursor.nextset())
294
+ await_(self._cursor.nextset())
267
295
  if self._cursor.description and not self.server_side:
268
- self._rows = collections.deque(
269
- self.await_(self._cursor.fetchall())
270
- )
296
+ self._rows = collections.deque(await_(self._cursor.fetchall()))
271
297
 
272
298
  def setinputsizes(self, *inputsizes: Any) -> None:
273
299
  # NOTE: this is overridden in aioodbc due to
274
300
  # see https://github.com/aio-libs/aioodbc/issues/451
275
301
  # right now
276
302
 
277
- return self.await_(self._cursor.setinputsizes(*inputsizes))
303
+ return await_(self._cursor.setinputsizes(*inputsizes))
278
304
 
279
305
  def __enter__(self) -> Self:
280
306
  return self
@@ -310,23 +336,23 @@ class AsyncAdapt_dbapi_ss_cursor(AsyncAdapt_dbapi_cursor):
310
336
 
311
337
  def close(self) -> None:
312
338
  if self._cursor is not None:
313
- self.await_(self._cursor.close())
339
+ await_(self._cursor.close())
314
340
  self._cursor = None # type: ignore
315
341
 
316
342
  def fetchone(self) -> Optional[Any]:
317
- return self.await_(self._cursor.fetchone())
343
+ return await_(self._cursor.fetchone())
318
344
 
319
345
  def fetchmany(self, size: Optional[int] = None) -> Any:
320
- return self.await_(self._cursor.fetchmany(size=size))
346
+ return await_(self._cursor.fetchmany(size=size))
321
347
 
322
348
  def fetchall(self) -> Sequence[Any]:
323
- return self.await_(self._cursor.fetchall())
349
+ return await_(self._cursor.fetchall())
324
350
 
325
351
  def __iter__(self) -> Iterator[Any]:
326
352
  iterator = self._cursor.__aiter__()
327
353
  while True:
328
354
  try:
329
- yield self.await_(iterator.__anext__())
355
+ yield await_(iterator.__anext__())
330
356
  except StopAsyncIteration:
331
357
  break
332
358
 
@@ -335,12 +361,24 @@ class AsyncAdapt_dbapi_connection(AdaptedConnection):
335
361
  _cursor_cls = AsyncAdapt_dbapi_cursor
336
362
  _ss_cursor_cls = AsyncAdapt_dbapi_ss_cursor
337
363
 
338
- await_ = staticmethod(await_only)
339
-
340
364
  __slots__ = ("dbapi", "_execute_mutex")
341
365
 
342
366
  _connection: AsyncIODBAPIConnection
343
367
 
368
+ @classmethod
369
+ async def create(
370
+ cls,
371
+ dbapi: Any,
372
+ connection_awaitable: Awaitable[AsyncIODBAPIConnection],
373
+ **kw: Any,
374
+ ) -> Self:
375
+ try:
376
+ connection = await connection_awaitable
377
+ except Exception as error:
378
+ cls._handle_exception_no_connection(dbapi, error)
379
+ else:
380
+ return cls(dbapi, connection, **kw)
381
+
344
382
  def __init__(self, dbapi: Any, connection: AsyncIODBAPIConnection):
345
383
  self.dbapi = dbapi
346
384
  self._connection = connection
@@ -362,31 +400,31 @@ class AsyncAdapt_dbapi_connection(AdaptedConnection):
362
400
  cursor.execute(operation, parameters)
363
401
  return cursor
364
402
 
365
- def _handle_exception(self, error: Exception) -> NoReturn:
403
+ @classmethod
404
+ def _handle_exception_no_connection(
405
+ cls, dbapi: Any, error: Exception
406
+ ) -> NoReturn:
366
407
  exc_info = sys.exc_info()
367
408
 
368
409
  raise error.with_traceback(exc_info[2])
369
410
 
411
+ def _handle_exception(self, error: Exception) -> NoReturn:
412
+ self._handle_exception_no_connection(self.dbapi, error)
413
+
370
414
  def rollback(self) -> None:
371
415
  try:
372
- self.await_(self._connection.rollback())
416
+ await_(self._connection.rollback())
373
417
  except Exception as error:
374
418
  self._handle_exception(error)
375
419
 
376
420
  def commit(self) -> None:
377
421
  try:
378
- self.await_(self._connection.commit())
422
+ await_(self._connection.commit())
379
423
  except Exception as error:
380
424
  self._handle_exception(error)
381
425
 
382
426
  def close(self) -> None:
383
- self.await_(self._connection.close())
384
-
385
-
386
- class AsyncAdaptFallback_dbapi_connection(AsyncAdapt_dbapi_connection):
387
- __slots__ = ()
388
-
389
- await_ = staticmethod(await_fallback)
427
+ await_(self._connection.close())
390
428
 
391
429
 
392
430
  class AsyncAdapt_terminate:
@@ -399,7 +437,7 @@ class AsyncAdapt_terminate:
399
437
  # in a greenlet; this is the connection was invalidated case.
400
438
  try:
401
439
  # try to gracefully close; see #10717
402
- self.await_(asyncio.shield(self._terminate_graceful_close())) # type: ignore[attr-defined] # noqa: E501
440
+ await_(asyncio.shield(self._terminate_graceful_close()))
403
441
  except self._terminate_handled_exceptions() as e:
404
442
  # in the case where we are recycling an old connection
405
443
  # that may have already been disconnected, close() will
@@ -427,3 +465,12 @@ class AsyncAdapt_terminate:
427
465
  def _terminate_force_close(self) -> None:
428
466
  """Terminate the connection"""
429
467
  raise NotImplementedError
468
+
469
+
470
+ class AsyncAdapt_Error(EmulatedDBAPIException):
471
+ """Provide for the base of DBAPI ``Error`` base class for dialects
472
+ that need to emulate the DBAPI exception hierarchy.
473
+
474
+ .. versionadded:: 2.1
475
+
476
+ """
@@ -15,7 +15,6 @@ from typing import List
15
15
  from typing import Optional
16
16
  from typing import Tuple
17
17
  from typing import Union
18
- from urllib.parse import unquote_plus
19
18
 
20
19
  from . import Connector
21
20
  from .. import ExecutionContext
@@ -73,7 +72,8 @@ class PyODBCConnector(Connector):
73
72
  connect_args[param] = util.asbool(keys.pop(param))
74
73
 
75
74
  if "odbc_connect" in keys:
76
- connectors = [unquote_plus(keys.pop("odbc_connect"))]
75
+ # (potential breaking change for issue #11250)
76
+ connectors = [keys.pop("odbc_connect")]
77
77
  else:
78
78
 
79
79
  def check_quote(token: str) -> str:
@@ -8,6 +8,7 @@
8
8
 
9
9
  from . import aioodbc # noqa
10
10
  from . import base # noqa
11
+ from . import mssqlpython # noqa
11
12
  from . import pymssql # noqa
12
13
  from . import pyodbc # noqa
13
14
  from .base import BIGINT
@@ -42,12 +42,12 @@ styles are otherwise equivalent to those documented in the pyodbc section::
42
42
 
43
43
  from __future__ import annotations
44
44
 
45
+ from .base import MSExecutionContext
45
46
  from .pyodbc import MSDialect_pyodbc
46
- from .pyodbc import MSExecutionContext_pyodbc
47
47
  from ...connectors.aioodbc import aiodbcConnector
48
48
 
49
49
 
50
- class MSExecutionContext_aioodbc(MSExecutionContext_pyodbc):
50
+ class MSExecutionContext_aioodbc(MSExecutionContext):
51
51
  def create_server_side_cursor(self):
52
52
  return self._dbapi_connection.cursor(server_side=True)
53
53