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.
- sqlalchemy/__init__.py +19 -4
- sqlalchemy/connectors/aioodbc.py +10 -33
- sqlalchemy/connectors/asyncio.py +80 -33
- sqlalchemy/connectors/pyodbc.py +2 -2
- sqlalchemy/dialects/mssql/__init__.py +1 -0
- sqlalchemy/dialects/mssql/aioodbc.py +2 -2
- sqlalchemy/dialects/mssql/base.py +107 -55
- sqlalchemy/dialects/mssql/json.py +26 -15
- sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
- sqlalchemy/dialects/mssql/provision.py +13 -2
- sqlalchemy/dialects/mssql/pyodbc.py +2 -64
- sqlalchemy/dialects/mysql/__init__.py +2 -0
- sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
- sqlalchemy/dialects/mysql/aiomysql.py +11 -35
- sqlalchemy/dialects/mysql/asyncmy.py +15 -32
- sqlalchemy/dialects/mysql/base.py +286 -358
- sqlalchemy/dialects/mysql/dml.py +73 -19
- sqlalchemy/dialects/mysql/enumerated.py +8 -13
- sqlalchemy/dialects/mysql/json.py +2 -1
- sqlalchemy/dialects/mysql/mariadb.py +8 -13
- sqlalchemy/dialects/mysql/mariadbconnector.py +10 -2
- sqlalchemy/dialects/mysql/mysqlconnector.py +8 -14
- sqlalchemy/dialects/mysql/mysqldb.py +5 -7
- sqlalchemy/dialects/mysql/pymysql.py +2 -3
- sqlalchemy/dialects/mysql/pyodbc.py +1 -2
- sqlalchemy/dialects/mysql/reflection.py +20 -23
- sqlalchemy/dialects/mysql/types.py +24 -14
- sqlalchemy/dialects/oracle/__init__.py +5 -1
- sqlalchemy/dialects/oracle/base.py +197 -26
- sqlalchemy/dialects/oracle/cx_oracle.py +104 -58
- sqlalchemy/dialects/oracle/json.py +158 -0
- sqlalchemy/dialects/oracle/oracledb.py +27 -59
- sqlalchemy/dialects/oracle/provision.py +0 -9
- sqlalchemy/dialects/oracle/types.py +51 -0
- sqlalchemy/dialects/oracle/vector.py +3 -0
- sqlalchemy/dialects/postgresql/__init__.py +5 -1
- sqlalchemy/dialects/postgresql/_psycopg_common.py +43 -3
- sqlalchemy/dialects/postgresql/array.py +17 -2
- sqlalchemy/dialects/postgresql/asyncpg.py +219 -180
- sqlalchemy/dialects/postgresql/base.py +568 -157
- sqlalchemy/dialects/postgresql/bitstring.py +327 -0
- sqlalchemy/dialects/postgresql/dml.py +39 -18
- sqlalchemy/dialects/postgresql/ext.py +69 -16
- sqlalchemy/dialects/postgresql/hstore.py +56 -39
- sqlalchemy/dialects/postgresql/json.py +12 -8
- sqlalchemy/dialects/postgresql/named_types.py +54 -57
- sqlalchemy/dialects/postgresql/operators.py +1 -0
- sqlalchemy/dialects/postgresql/pg8000.py +11 -10
- sqlalchemy/dialects/postgresql/pg_catalog.py +18 -0
- sqlalchemy/dialects/postgresql/provision.py +3 -2
- sqlalchemy/dialects/postgresql/psycopg.py +112 -175
- sqlalchemy/dialects/postgresql/psycopg2.py +2 -34
- sqlalchemy/dialects/postgresql/ranges.py +7 -36
- sqlalchemy/dialects/postgresql/types.py +87 -12
- sqlalchemy/dialects/sqlite/aiosqlite.py +39 -200
- sqlalchemy/dialects/sqlite/base.py +45 -38
- sqlalchemy/dialects/sqlite/dml.py +34 -18
- sqlalchemy/dialects/sqlite/json.py +26 -18
- sqlalchemy/dialects/sqlite/pysqlcipher.py +11 -7
- sqlalchemy/dialects/sqlite/pysqlite.py +2 -4
- sqlalchemy/engine/_processors_cy.py +92 -0
- sqlalchemy/engine/_result_cy.py +633 -0
- sqlalchemy/engine/_row_cy.py +232 -0
- sqlalchemy/engine/_util_cy.py +136 -0
- sqlalchemy/engine/base.py +68 -104
- sqlalchemy/engine/create.py +7 -29
- sqlalchemy/engine/cursor.py +243 -125
- sqlalchemy/engine/default.py +30 -22
- sqlalchemy/engine/events.py +6 -6
- sqlalchemy/engine/interfaces.py +44 -20
- sqlalchemy/engine/processors.py +61 -40
- sqlalchemy/engine/reflection.py +1 -3
- sqlalchemy/engine/result.py +111 -567
- sqlalchemy/engine/row.py +43 -46
- sqlalchemy/engine/url.py +4 -6
- sqlalchemy/engine/util.py +3 -14
- sqlalchemy/event/attr.py +1 -3
- sqlalchemy/event/base.py +1 -1
- sqlalchemy/exc.py +99 -9
- sqlalchemy/ext/associationproxy.py +71 -26
- sqlalchemy/ext/asyncio/__init__.py +4 -0
- sqlalchemy/ext/asyncio/base.py +3 -3
- sqlalchemy/ext/asyncio/engine.py +33 -17
- sqlalchemy/ext/asyncio/result.py +56 -27
- sqlalchemy/ext/asyncio/scoping.py +93 -13
- sqlalchemy/ext/asyncio/session.py +76 -16
- sqlalchemy/ext/automap.py +13 -13
- sqlalchemy/ext/baked.py +0 -11
- sqlalchemy/ext/declarative/extensions.py +5 -9
- sqlalchemy/ext/horizontal_shard.py +11 -8
- sqlalchemy/ext/hybrid.py +410 -68
- sqlalchemy/ext/indexable.py +2 -2
- sqlalchemy/ext/instrumentation.py +1 -1
- sqlalchemy/ext/mutable.py +4 -8
- sqlalchemy/ext/orderinglist.py +1 -1
- sqlalchemy/ext/serializer.py +2 -2
- sqlalchemy/inspection.py +2 -2
- sqlalchemy/log.py +7 -12
- sqlalchemy/orm/__init__.py +5 -0
- sqlalchemy/orm/_orm_constructors.py +54 -21
- sqlalchemy/orm/_typing.py +9 -9
- sqlalchemy/orm/attributes.py +102 -79
- sqlalchemy/orm/base.py +17 -12
- sqlalchemy/orm/bulk_persistence.py +54 -37
- sqlalchemy/orm/clsregistry.py +37 -26
- sqlalchemy/orm/collections.py +10 -69
- sqlalchemy/orm/context.py +236 -99
- sqlalchemy/orm/decl_api.py +617 -341
- sqlalchemy/orm/decl_base.py +755 -638
- sqlalchemy/orm/dependency.py +54 -50
- sqlalchemy/orm/descriptor_props.py +120 -29
- sqlalchemy/orm/dynamic.py +16 -16
- sqlalchemy/orm/events.py +209 -75
- sqlalchemy/orm/identity.py +1 -1
- sqlalchemy/orm/instrumentation.py +5 -13
- sqlalchemy/orm/interfaces.py +133 -40
- sqlalchemy/orm/loading.py +30 -32
- sqlalchemy/orm/mapped_collection.py +1 -1
- sqlalchemy/orm/mapper.py +97 -130
- sqlalchemy/orm/path_registry.py +56 -51
- sqlalchemy/orm/persistence.py +15 -14
- sqlalchemy/orm/properties.py +87 -49
- sqlalchemy/orm/query.py +108 -46
- sqlalchemy/orm/relationships.py +149 -87
- sqlalchemy/orm/scoping.py +116 -32
- sqlalchemy/orm/session.py +254 -131
- sqlalchemy/orm/state.py +20 -13
- sqlalchemy/orm/state_changes.py +1 -1
- sqlalchemy/orm/strategies.py +69 -59
- sqlalchemy/orm/strategy_options.py +23 -47
- sqlalchemy/orm/sync.py +6 -6
- sqlalchemy/orm/unitofwork.py +27 -25
- sqlalchemy/orm/util.py +92 -57
- sqlalchemy/orm/writeonly.py +33 -13
- sqlalchemy/pool/__init__.py +0 -3
- sqlalchemy/pool/base.py +2 -4
- sqlalchemy/pool/impl.py +1 -7
- sqlalchemy/schema.py +6 -1
- sqlalchemy/sql/__init__.py +11 -0
- sqlalchemy/sql/_annotated_cols.py +397 -0
- sqlalchemy/sql/_elements_constructors.py +341 -49
- sqlalchemy/sql/_orm_types.py +1 -1
- sqlalchemy/sql/_selectable_constructors.py +135 -58
- sqlalchemy/sql/_typing.py +15 -10
- sqlalchemy/sql/_util_cy.py +127 -0
- sqlalchemy/sql/annotation.py +9 -6
- sqlalchemy/sql/base.py +590 -184
- sqlalchemy/sql/cache_key.py +32 -23
- sqlalchemy/sql/coercions.py +27 -58
- sqlalchemy/sql/compiler.py +407 -163
- sqlalchemy/sql/crud.py +71 -8
- sqlalchemy/sql/ddl.py +548 -64
- sqlalchemy/sql/default_comparator.py +239 -136
- sqlalchemy/sql/dml.py +206 -82
- sqlalchemy/sql/elements.py +806 -362
- sqlalchemy/sql/expression.py +13 -0
- sqlalchemy/sql/functions.py +140 -34
- sqlalchemy/sql/lambdas.py +3 -2
- sqlalchemy/sql/operators.py +339 -65
- sqlalchemy/sql/roles.py +17 -8
- sqlalchemy/sql/schema.py +685 -207
- sqlalchemy/sql/selectable.py +534 -246
- sqlalchemy/sql/sqltypes.py +364 -201
- sqlalchemy/sql/traversals.py +19 -1
- sqlalchemy/sql/type_api.py +110 -32
- sqlalchemy/sql/util.py +19 -9
- sqlalchemy/sql/visitors.py +8 -15
- sqlalchemy/testing/assertions.py +14 -1
- sqlalchemy/testing/assertsql.py +0 -1
- sqlalchemy/testing/asyncio.py +0 -7
- sqlalchemy/testing/config.py +10 -4
- sqlalchemy/testing/engines.py +4 -4
- sqlalchemy/testing/fixtures/__init__.py +2 -0
- sqlalchemy/testing/fixtures/mypy.py +23 -111
- sqlalchemy/testing/fixtures/sql.py +61 -5
- sqlalchemy/testing/plugin/pytestplugin.py +3 -3
- sqlalchemy/testing/provision.py +16 -6
- sqlalchemy/testing/requirements.py +52 -19
- sqlalchemy/testing/suite/__init__.py +1 -1
- sqlalchemy/testing/suite/test_ddl.py +31 -0
- sqlalchemy/testing/suite/test_reflection.py +15 -15
- sqlalchemy/testing/suite/test_results.py +156 -0
- sqlalchemy/testing/suite/test_select.py +117 -15
- sqlalchemy/testing/suite/test_table_via_select.py +686 -0
- sqlalchemy/testing/suite/test_types.py +134 -10
- sqlalchemy/testing/util.py +1 -1
- sqlalchemy/types.py +2 -0
- sqlalchemy/util/__init__.py +3 -7
- sqlalchemy/util/_collections.py +11 -35
- sqlalchemy/{cyextension/immutabledict.pxd → util/_collections_cy.pxd} +3 -3
- sqlalchemy/util/_collections_cy.py +516 -0
- sqlalchemy/util/_has_cython.py +46 -0
- sqlalchemy/util/_immutabledict_cy.py +240 -0
- sqlalchemy/util/compat.py +27 -149
- sqlalchemy/util/concurrency.py +275 -63
- sqlalchemy/util/cython.py +79 -0
- sqlalchemy/util/deprecations.py +2 -2
- sqlalchemy/util/langhelpers.py +215 -98
- sqlalchemy/util/preloaded.py +2 -0
- sqlalchemy/util/queue.py +5 -23
- sqlalchemy/util/typing.py +43 -66
- {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/METADATA +51 -25
- sqlalchemy-2.1.0b2.dist-info/RECORD +263 -0
- sqlalchemy/cyextension/__init__.py +0 -6
- sqlalchemy/cyextension/collections.pyx +0 -409
- sqlalchemy/cyextension/immutabledict.pyx +0 -133
- sqlalchemy/cyextension/processors.pyx +0 -68
- sqlalchemy/cyextension/resultproxy.pyx +0 -102
- sqlalchemy/cyextension/util.pyx +0 -90
- sqlalchemy/engine/_py_processors.py +0 -136
- sqlalchemy/engine/_py_row.py +0 -128
- sqlalchemy/engine/_py_util.py +0 -74
- sqlalchemy/ext/mypy/__init__.py +0 -6
- sqlalchemy/ext/mypy/apply.py +0 -324
- sqlalchemy/ext/mypy/decl_class.py +0 -515
- sqlalchemy/ext/mypy/infer.py +0 -590
- sqlalchemy/ext/mypy/names.py +0 -335
- sqlalchemy/ext/mypy/plugin.py +0 -303
- sqlalchemy/ext/mypy/util.py +0 -357
- sqlalchemy/sql/_py_util.py +0 -75
- sqlalchemy/testing/suite/test_deprecations.py +0 -153
- sqlalchemy/util/_concurrency_py3k.py +0 -288
- sqlalchemy/util/_has_cy.py +0 -40
- sqlalchemy/util/_py_collections.py +0 -541
- sqlalchemy-2.0.49.dist-info/RECORD +0 -269
- {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/WHEEL +0 -0
- {sqlalchemy-2.0.49.dist-info → sqlalchemy-2.1.0b2.dist-info}/licenses/LICENSE +0 -0
- {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.
|
|
287
|
+
__version__ = "2.1.0b2"
|
|
273
288
|
|
|
274
289
|
|
|
275
290
|
def __go(lcls: Any) -> None:
|
sqlalchemy/connectors/aioodbc.py
CHANGED
|
@@ -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
|
|
19
|
-
from .. import
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
154
|
-
|
|
143
|
+
return await_(
|
|
144
|
+
AsyncAdapt_aioodbc_connection.create(
|
|
155
145
|
self,
|
|
156
|
-
|
|
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
|
sqlalchemy/connectors/asyncio.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
339
|
+
await_(self._cursor.close())
|
|
314
340
|
self._cursor = None # type: ignore
|
|
315
341
|
|
|
316
342
|
def fetchone(self) -> Optional[Any]:
|
|
317
|
-
return
|
|
343
|
+
return await_(self._cursor.fetchone())
|
|
318
344
|
|
|
319
345
|
def fetchmany(self, size: Optional[int] = None) -> Any:
|
|
320
|
-
return
|
|
346
|
+
return await_(self._cursor.fetchmany(size=size))
|
|
321
347
|
|
|
322
348
|
def fetchall(self) -> Sequence[Any]:
|
|
323
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
"""
|
sqlalchemy/connectors/pyodbc.py
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
@@ -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(
|
|
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
|
|