SQLAlchemy 2.0.47__cp313-cp313t-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlalchemy/__init__.py +283 -0
- sqlalchemy/connectors/__init__.py +18 -0
- sqlalchemy/connectors/aioodbc.py +184 -0
- sqlalchemy/connectors/asyncio.py +429 -0
- sqlalchemy/connectors/pyodbc.py +250 -0
- sqlalchemy/cyextension/__init__.py +6 -0
- sqlalchemy/cyextension/collections.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/collections.pyx +409 -0
- sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/immutabledict.pxd +8 -0
- sqlalchemy/cyextension/immutabledict.pyx +133 -0
- sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/processors.pyx +68 -0
- sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/resultproxy.pyx +102 -0
- sqlalchemy/cyextension/util.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/util.pyx +90 -0
- sqlalchemy/dialects/__init__.py +62 -0
- sqlalchemy/dialects/_typing.py +30 -0
- sqlalchemy/dialects/mssql/__init__.py +88 -0
- sqlalchemy/dialects/mssql/aioodbc.py +63 -0
- sqlalchemy/dialects/mssql/base.py +4093 -0
- sqlalchemy/dialects/mssql/information_schema.py +285 -0
- sqlalchemy/dialects/mssql/json.py +129 -0
- sqlalchemy/dialects/mssql/provision.py +185 -0
- sqlalchemy/dialects/mssql/pymssql.py +126 -0
- sqlalchemy/dialects/mssql/pyodbc.py +760 -0
- sqlalchemy/dialects/mysql/__init__.py +104 -0
- sqlalchemy/dialects/mysql/aiomysql.py +250 -0
- sqlalchemy/dialects/mysql/asyncmy.py +231 -0
- sqlalchemy/dialects/mysql/base.py +3949 -0
- sqlalchemy/dialects/mysql/cymysql.py +106 -0
- sqlalchemy/dialects/mysql/dml.py +225 -0
- sqlalchemy/dialects/mysql/enumerated.py +282 -0
- sqlalchemy/dialects/mysql/expression.py +146 -0
- sqlalchemy/dialects/mysql/json.py +91 -0
- sqlalchemy/dialects/mysql/mariadb.py +72 -0
- sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
- sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
- sqlalchemy/dialects/mysql/mysqldb.py +314 -0
- sqlalchemy/dialects/mysql/provision.py +153 -0
- sqlalchemy/dialects/mysql/pymysql.py +158 -0
- sqlalchemy/dialects/mysql/pyodbc.py +157 -0
- sqlalchemy/dialects/mysql/reflection.py +727 -0
- sqlalchemy/dialects/mysql/reserved_words.py +570 -0
- sqlalchemy/dialects/mysql/types.py +835 -0
- sqlalchemy/dialects/oracle/__init__.py +81 -0
- sqlalchemy/dialects/oracle/base.py +3802 -0
- sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
- sqlalchemy/dialects/oracle/dictionary.py +507 -0
- sqlalchemy/dialects/oracle/oracledb.py +941 -0
- sqlalchemy/dialects/oracle/provision.py +297 -0
- sqlalchemy/dialects/oracle/types.py +316 -0
- sqlalchemy/dialects/oracle/vector.py +365 -0
- sqlalchemy/dialects/postgresql/__init__.py +167 -0
- sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
- sqlalchemy/dialects/postgresql/array.py +519 -0
- sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
- sqlalchemy/dialects/postgresql/base.py +5378 -0
- sqlalchemy/dialects/postgresql/dml.py +339 -0
- sqlalchemy/dialects/postgresql/ext.py +540 -0
- sqlalchemy/dialects/postgresql/hstore.py +406 -0
- sqlalchemy/dialects/postgresql/json.py +404 -0
- sqlalchemy/dialects/postgresql/named_types.py +524 -0
- sqlalchemy/dialects/postgresql/operators.py +129 -0
- sqlalchemy/dialects/postgresql/pg8000.py +669 -0
- sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
- sqlalchemy/dialects/postgresql/provision.py +183 -0
- sqlalchemy/dialects/postgresql/psycopg.py +862 -0
- sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
- sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
- sqlalchemy/dialects/postgresql/ranges.py +1031 -0
- sqlalchemy/dialects/postgresql/types.py +313 -0
- sqlalchemy/dialects/sqlite/__init__.py +57 -0
- sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
- sqlalchemy/dialects/sqlite/base.py +3056 -0
- sqlalchemy/dialects/sqlite/dml.py +263 -0
- sqlalchemy/dialects/sqlite/json.py +92 -0
- sqlalchemy/dialects/sqlite/provision.py +229 -0
- sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
- sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
- sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
- sqlalchemy/engine/__init__.py +62 -0
- sqlalchemy/engine/_py_processors.py +136 -0
- sqlalchemy/engine/_py_row.py +128 -0
- sqlalchemy/engine/_py_util.py +74 -0
- sqlalchemy/engine/base.py +3390 -0
- sqlalchemy/engine/characteristics.py +155 -0
- sqlalchemy/engine/create.py +893 -0
- sqlalchemy/engine/cursor.py +2298 -0
- sqlalchemy/engine/default.py +2394 -0
- sqlalchemy/engine/events.py +965 -0
- sqlalchemy/engine/interfaces.py +3471 -0
- sqlalchemy/engine/mock.py +134 -0
- sqlalchemy/engine/processors.py +61 -0
- sqlalchemy/engine/reflection.py +2102 -0
- sqlalchemy/engine/result.py +2399 -0
- sqlalchemy/engine/row.py +400 -0
- sqlalchemy/engine/strategies.py +16 -0
- sqlalchemy/engine/url.py +924 -0
- sqlalchemy/engine/util.py +167 -0
- sqlalchemy/event/__init__.py +26 -0
- sqlalchemy/event/api.py +220 -0
- sqlalchemy/event/attr.py +676 -0
- sqlalchemy/event/base.py +472 -0
- sqlalchemy/event/legacy.py +258 -0
- sqlalchemy/event/registry.py +390 -0
- sqlalchemy/events.py +17 -0
- sqlalchemy/exc.py +832 -0
- sqlalchemy/ext/__init__.py +11 -0
- sqlalchemy/ext/associationproxy.py +2027 -0
- sqlalchemy/ext/asyncio/__init__.py +25 -0
- sqlalchemy/ext/asyncio/base.py +281 -0
- sqlalchemy/ext/asyncio/engine.py +1471 -0
- sqlalchemy/ext/asyncio/exc.py +21 -0
- sqlalchemy/ext/asyncio/result.py +965 -0
- sqlalchemy/ext/asyncio/scoping.py +1599 -0
- sqlalchemy/ext/asyncio/session.py +1947 -0
- sqlalchemy/ext/automap.py +1701 -0
- sqlalchemy/ext/baked.py +570 -0
- sqlalchemy/ext/compiler.py +600 -0
- sqlalchemy/ext/declarative/__init__.py +65 -0
- sqlalchemy/ext/declarative/extensions.py +564 -0
- sqlalchemy/ext/horizontal_shard.py +478 -0
- sqlalchemy/ext/hybrid.py +1535 -0
- sqlalchemy/ext/indexable.py +364 -0
- sqlalchemy/ext/instrumentation.py +450 -0
- sqlalchemy/ext/mutable.py +1085 -0
- sqlalchemy/ext/mypy/__init__.py +6 -0
- sqlalchemy/ext/mypy/apply.py +324 -0
- sqlalchemy/ext/mypy/decl_class.py +515 -0
- sqlalchemy/ext/mypy/infer.py +590 -0
- sqlalchemy/ext/mypy/names.py +335 -0
- sqlalchemy/ext/mypy/plugin.py +303 -0
- sqlalchemy/ext/mypy/util.py +357 -0
- sqlalchemy/ext/orderinglist.py +439 -0
- sqlalchemy/ext/serializer.py +185 -0
- sqlalchemy/future/__init__.py +16 -0
- sqlalchemy/future/engine.py +15 -0
- sqlalchemy/inspection.py +174 -0
- sqlalchemy/log.py +288 -0
- sqlalchemy/orm/__init__.py +171 -0
- sqlalchemy/orm/_orm_constructors.py +2661 -0
- sqlalchemy/orm/_typing.py +179 -0
- sqlalchemy/orm/attributes.py +2845 -0
- sqlalchemy/orm/base.py +971 -0
- sqlalchemy/orm/bulk_persistence.py +2135 -0
- sqlalchemy/orm/clsregistry.py +571 -0
- sqlalchemy/orm/collections.py +1627 -0
- sqlalchemy/orm/context.py +3334 -0
- sqlalchemy/orm/decl_api.py +2004 -0
- sqlalchemy/orm/decl_base.py +2192 -0
- sqlalchemy/orm/dependency.py +1302 -0
- sqlalchemy/orm/descriptor_props.py +1092 -0
- sqlalchemy/orm/dynamic.py +300 -0
- sqlalchemy/orm/evaluator.py +379 -0
- sqlalchemy/orm/events.py +3252 -0
- sqlalchemy/orm/exc.py +237 -0
- sqlalchemy/orm/identity.py +302 -0
- sqlalchemy/orm/instrumentation.py +754 -0
- sqlalchemy/orm/interfaces.py +1496 -0
- sqlalchemy/orm/loading.py +1686 -0
- sqlalchemy/orm/mapped_collection.py +557 -0
- sqlalchemy/orm/mapper.py +4444 -0
- sqlalchemy/orm/path_registry.py +809 -0
- sqlalchemy/orm/persistence.py +1788 -0
- sqlalchemy/orm/properties.py +935 -0
- sqlalchemy/orm/query.py +3459 -0
- sqlalchemy/orm/relationships.py +3508 -0
- sqlalchemy/orm/scoping.py +2148 -0
- sqlalchemy/orm/session.py +5280 -0
- sqlalchemy/orm/state.py +1168 -0
- sqlalchemy/orm/state_changes.py +196 -0
- sqlalchemy/orm/strategies.py +3470 -0
- sqlalchemy/orm/strategy_options.py +2568 -0
- sqlalchemy/orm/sync.py +164 -0
- sqlalchemy/orm/unitofwork.py +796 -0
- sqlalchemy/orm/util.py +2403 -0
- sqlalchemy/orm/writeonly.py +674 -0
- sqlalchemy/pool/__init__.py +44 -0
- sqlalchemy/pool/base.py +1524 -0
- sqlalchemy/pool/events.py +375 -0
- sqlalchemy/pool/impl.py +588 -0
- sqlalchemy/py.typed +0 -0
- sqlalchemy/schema.py +69 -0
- sqlalchemy/sql/__init__.py +145 -0
- sqlalchemy/sql/_dml_constructors.py +132 -0
- sqlalchemy/sql/_elements_constructors.py +1872 -0
- sqlalchemy/sql/_orm_types.py +20 -0
- sqlalchemy/sql/_py_util.py +75 -0
- sqlalchemy/sql/_selectable_constructors.py +763 -0
- sqlalchemy/sql/_typing.py +482 -0
- sqlalchemy/sql/annotation.py +587 -0
- sqlalchemy/sql/base.py +2293 -0
- sqlalchemy/sql/cache_key.py +1057 -0
- sqlalchemy/sql/coercions.py +1404 -0
- sqlalchemy/sql/compiler.py +8081 -0
- sqlalchemy/sql/crud.py +1752 -0
- sqlalchemy/sql/ddl.py +1444 -0
- sqlalchemy/sql/default_comparator.py +551 -0
- sqlalchemy/sql/dml.py +1850 -0
- sqlalchemy/sql/elements.py +5589 -0
- sqlalchemy/sql/events.py +458 -0
- sqlalchemy/sql/expression.py +159 -0
- sqlalchemy/sql/functions.py +2158 -0
- sqlalchemy/sql/lambdas.py +1442 -0
- sqlalchemy/sql/naming.py +209 -0
- sqlalchemy/sql/operators.py +2623 -0
- sqlalchemy/sql/roles.py +323 -0
- sqlalchemy/sql/schema.py +6222 -0
- sqlalchemy/sql/selectable.py +7265 -0
- sqlalchemy/sql/sqltypes.py +3930 -0
- sqlalchemy/sql/traversals.py +1024 -0
- sqlalchemy/sql/type_api.py +2368 -0
- sqlalchemy/sql/util.py +1485 -0
- sqlalchemy/sql/visitors.py +1164 -0
- sqlalchemy/testing/__init__.py +96 -0
- sqlalchemy/testing/assertions.py +994 -0
- sqlalchemy/testing/assertsql.py +520 -0
- sqlalchemy/testing/asyncio.py +135 -0
- sqlalchemy/testing/config.py +434 -0
- sqlalchemy/testing/engines.py +483 -0
- sqlalchemy/testing/entities.py +117 -0
- sqlalchemy/testing/exclusions.py +476 -0
- sqlalchemy/testing/fixtures/__init__.py +28 -0
- sqlalchemy/testing/fixtures/base.py +384 -0
- sqlalchemy/testing/fixtures/mypy.py +332 -0
- sqlalchemy/testing/fixtures/orm.py +227 -0
- sqlalchemy/testing/fixtures/sql.py +482 -0
- sqlalchemy/testing/pickleable.py +155 -0
- sqlalchemy/testing/plugin/__init__.py +6 -0
- sqlalchemy/testing/plugin/bootstrap.py +51 -0
- sqlalchemy/testing/plugin/plugin_base.py +828 -0
- sqlalchemy/testing/plugin/pytestplugin.py +892 -0
- sqlalchemy/testing/profiling.py +329 -0
- sqlalchemy/testing/provision.py +603 -0
- sqlalchemy/testing/requirements.py +1945 -0
- sqlalchemy/testing/schema.py +198 -0
- sqlalchemy/testing/suite/__init__.py +19 -0
- sqlalchemy/testing/suite/test_cte.py +237 -0
- sqlalchemy/testing/suite/test_ddl.py +389 -0
- sqlalchemy/testing/suite/test_deprecations.py +153 -0
- sqlalchemy/testing/suite/test_dialect.py +776 -0
- sqlalchemy/testing/suite/test_insert.py +630 -0
- sqlalchemy/testing/suite/test_reflection.py +3557 -0
- sqlalchemy/testing/suite/test_results.py +504 -0
- sqlalchemy/testing/suite/test_rowcount.py +258 -0
- sqlalchemy/testing/suite/test_select.py +2010 -0
- sqlalchemy/testing/suite/test_sequence.py +317 -0
- sqlalchemy/testing/suite/test_types.py +2147 -0
- sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
- sqlalchemy/testing/suite/test_update_delete.py +139 -0
- sqlalchemy/testing/util.py +535 -0
- sqlalchemy/testing/warnings.py +52 -0
- sqlalchemy/types.py +74 -0
- sqlalchemy/util/__init__.py +162 -0
- sqlalchemy/util/_collections.py +712 -0
- sqlalchemy/util/_concurrency_py3k.py +288 -0
- sqlalchemy/util/_has_cy.py +40 -0
- sqlalchemy/util/_py_collections.py +541 -0
- sqlalchemy/util/compat.py +421 -0
- sqlalchemy/util/concurrency.py +110 -0
- sqlalchemy/util/deprecations.py +401 -0
- sqlalchemy/util/langhelpers.py +2203 -0
- sqlalchemy/util/preloaded.py +150 -0
- sqlalchemy/util/queue.py +322 -0
- sqlalchemy/util/tool_support.py +201 -0
- sqlalchemy/util/topological.py +120 -0
- sqlalchemy/util/typing.py +734 -0
- sqlalchemy-2.0.47.dist-info/METADATA +243 -0
- sqlalchemy-2.0.47.dist-info/RECORD +274 -0
- sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
- sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
- sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
Rules for Migrating TypeEngine classes to 0.6
|
|
2
|
+
---------------------------------------------
|
|
3
|
+
|
|
4
|
+
1. the TypeEngine classes are used for:
|
|
5
|
+
|
|
6
|
+
a. Specifying behavior which needs to occur for bind parameters
|
|
7
|
+
or result row columns.
|
|
8
|
+
|
|
9
|
+
b. Specifying types that are entirely specific to the database
|
|
10
|
+
in use and have no analogue in the sqlalchemy.types package.
|
|
11
|
+
|
|
12
|
+
c. Specifying types where there is an analogue in sqlalchemy.types,
|
|
13
|
+
but the database in use takes vendor-specific flags for those
|
|
14
|
+
types.
|
|
15
|
+
|
|
16
|
+
d. If a TypeEngine class doesn't provide any of this, it should be
|
|
17
|
+
*removed* from the dialect.
|
|
18
|
+
|
|
19
|
+
2. the TypeEngine classes are *no longer* used for generating DDL. Dialects
|
|
20
|
+
now have a TypeCompiler subclass which uses the same visit_XXX model as
|
|
21
|
+
other compilers.
|
|
22
|
+
|
|
23
|
+
3. the "ischema_names" and "colspecs" dictionaries are now required members on
|
|
24
|
+
the Dialect class.
|
|
25
|
+
|
|
26
|
+
4. The names of types within dialects are now important. If a dialect-specific type
|
|
27
|
+
is a subclass of an existing generic type and is only provided for bind/result behavior,
|
|
28
|
+
the current mixed case naming can remain, i.e. _PGNumeric for Numeric - in this case,
|
|
29
|
+
end users would never need to use _PGNumeric directly. However, if a dialect-specific
|
|
30
|
+
type is specifying a type *or* arguments that are not present generically, it should
|
|
31
|
+
match the real name of the type on that backend, in uppercase. E.g. postgresql.INET,
|
|
32
|
+
mysql.ENUM, postgresql.ARRAY.
|
|
33
|
+
|
|
34
|
+
Or follow this handy flowchart:
|
|
35
|
+
|
|
36
|
+
is the type meant to provide bind/result is the type the same name as an
|
|
37
|
+
behavior to a generic type (i.e. MixedCase) ---- no ---> UPPERCASE type in types.py ?
|
|
38
|
+
type in types.py ? | |
|
|
39
|
+
| no yes
|
|
40
|
+
yes | |
|
|
41
|
+
| | does your type need special
|
|
42
|
+
| +<--- yes --- behavior or arguments ?
|
|
43
|
+
| | |
|
|
44
|
+
| | no
|
|
45
|
+
name the type using | |
|
|
46
|
+
_MixedCase, i.e. v V
|
|
47
|
+
_OracleBoolean. it name the type don't make a
|
|
48
|
+
stays private to the dialect identically as that type, make sure the dialect's
|
|
49
|
+
and is invoked *only* via within the DB, base.py imports the types.py
|
|
50
|
+
the colspecs dict. using UPPERCASE UPPERCASE name into its namespace
|
|
51
|
+
| (i.e. BIT, NCHAR, INTERVAL).
|
|
52
|
+
| Users can import it.
|
|
53
|
+
| |
|
|
54
|
+
v v
|
|
55
|
+
subclass the closest is the name of this type
|
|
56
|
+
MixedCase type types.py, identical to an UPPERCASE
|
|
57
|
+
i.e. <--- no ------- name in types.py ?
|
|
58
|
+
class _DateTime(types.DateTime),
|
|
59
|
+
class DATETIME2(types.DateTime), |
|
|
60
|
+
class BIT(types.TypeEngine). yes
|
|
61
|
+
|
|
|
62
|
+
v
|
|
63
|
+
the type should
|
|
64
|
+
subclass the
|
|
65
|
+
UPPERCASE
|
|
66
|
+
type in types.py
|
|
67
|
+
(i.e. class BLOB(types.BLOB))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Example 1. pysqlite needs bind/result processing for the DateTime type in types.py,
|
|
71
|
+
which applies to all DateTimes and subclasses. It's named _SLDateTime and
|
|
72
|
+
subclasses types.DateTime.
|
|
73
|
+
|
|
74
|
+
Example 2. MS-SQL has a TIME type which takes a non-standard "precision" argument
|
|
75
|
+
that is rendered within DDL. So it's named TIME in the MS-SQL dialect's base.py,
|
|
76
|
+
and subclasses types.TIME. Users can then say mssql.TIME(precision=10).
|
|
77
|
+
|
|
78
|
+
Example 3. MS-SQL dialects also need special bind/result processing for date
|
|
79
|
+
But its DATE type doesn't render DDL differently than that of a plain
|
|
80
|
+
DATE, i.e. it takes no special arguments. Therefore we are just adding behavior
|
|
81
|
+
to types.Date, so it's named _MSDate in the MS-SQL dialect's base.py, and subclasses
|
|
82
|
+
types.Date.
|
|
83
|
+
|
|
84
|
+
Example 4. MySQL has a SET type, there's no analogue for this in types.py. So
|
|
85
|
+
MySQL names it SET in the dialect's base.py, and it subclasses types.String, since
|
|
86
|
+
it ultimately deals with strings.
|
|
87
|
+
|
|
88
|
+
Example 5. PostgreSQL has a DATETIME type. The DBAPIs handle dates correctly,
|
|
89
|
+
and no special arguments are used in PG's DDL beyond what types.py provides.
|
|
90
|
+
PostgreSQL dialect therefore imports types.DATETIME into its base.py.
|
|
91
|
+
|
|
92
|
+
Ideally one should be able to specify a schema using names imported completely from a
|
|
93
|
+
dialect, all matching the real name on that backend:
|
|
94
|
+
|
|
95
|
+
from sqlalchemy.dialects.postgresql import base as pg
|
|
96
|
+
|
|
97
|
+
t = Table('mytable', metadata,
|
|
98
|
+
Column('id', pg.INTEGER, primary_key=True),
|
|
99
|
+
Column('name', pg.VARCHAR(300)),
|
|
100
|
+
Column('inetaddr', pg.INET)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
where above, the INTEGER and VARCHAR types are ultimately from sqlalchemy.types,
|
|
104
|
+
but the PG dialect makes them available in its own namespace.
|
|
105
|
+
|
|
106
|
+
5. "colspecs" now is a dictionary of generic or uppercased types from sqlalchemy.types
|
|
107
|
+
linked to types specified in the dialect. Again, if a type in the dialect does not
|
|
108
|
+
specify any special behavior for bind_processor() or result_processor() and does not
|
|
109
|
+
indicate a special type only available in this database, it must be *removed* from the
|
|
110
|
+
module and from this dictionary.
|
|
111
|
+
|
|
112
|
+
6. "ischema_names" indicates string descriptions of types as returned from the database
|
|
113
|
+
linked to TypeEngine classes.
|
|
114
|
+
|
|
115
|
+
a. The string name should be matched to the most specific type possible within
|
|
116
|
+
sqlalchemy.types, unless there is no matching type within sqlalchemy.types in which
|
|
117
|
+
case it points to a dialect type. *It doesn't matter* if the dialect has its
|
|
118
|
+
own subclass of that type with special bind/result behavior - reflect to the types.py
|
|
119
|
+
UPPERCASE type as much as possible. With very few exceptions, all types
|
|
120
|
+
should reflect to an UPPERCASE type.
|
|
121
|
+
|
|
122
|
+
b. If the dialect contains a matching dialect-specific type that takes extra arguments
|
|
123
|
+
which the generic one does not, then point to the dialect-specific type. E.g.
|
|
124
|
+
mssql.VARCHAR takes a "collation" parameter which should be preserved.
|
|
125
|
+
|
|
126
|
+
5. DDL, or what was formerly issued by "get_col_spec()", is now handled exclusively by
|
|
127
|
+
a subclass of compiler.GenericTypeCompiler.
|
|
128
|
+
|
|
129
|
+
a. your TypeCompiler class will receive generic and uppercase types from
|
|
130
|
+
sqlalchemy.types. Do not assume the presence of dialect-specific attributes on
|
|
131
|
+
these types.
|
|
132
|
+
|
|
133
|
+
b. the visit_UPPERCASE methods on GenericTypeCompiler should *not* be overridden with
|
|
134
|
+
methods that produce a different DDL name. Uppercase types don't do any kind of
|
|
135
|
+
"guessing" - if visit_TIMESTAMP is called, the DDL should render as TIMESTAMP in
|
|
136
|
+
all cases, regardless of whether or not that type is legal on the backend database.
|
|
137
|
+
|
|
138
|
+
c. the visit_UPPERCASE methods *should* be overridden with methods that add additional
|
|
139
|
+
arguments and flags to those types.
|
|
140
|
+
|
|
141
|
+
d. the visit_lowercase methods are overridden to provide an interpretation of a generic
|
|
142
|
+
type. E.g. visit_large_binary() might be overridden to say "return self.visit_BIT(type_)".
|
|
143
|
+
|
|
144
|
+
e. visit_lowercase methods should *never* render strings directly - it should always
|
|
145
|
+
be via calling a visit_UPPERCASE() method.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# engine/__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
|
+
|
|
8
|
+
"""SQL connections, SQL execution and high-level DB-API interface.
|
|
9
|
+
|
|
10
|
+
The engine package defines the basic components used to interface
|
|
11
|
+
DB-API modules with higher-level statement construction,
|
|
12
|
+
connection-management, execution and result contexts. The primary
|
|
13
|
+
"entry point" class into this package is the Engine and its public
|
|
14
|
+
constructor ``create_engine()``.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from . import events as events
|
|
19
|
+
from . import util as util
|
|
20
|
+
from .base import Connection as Connection
|
|
21
|
+
from .base import Engine as Engine
|
|
22
|
+
from .base import NestedTransaction as NestedTransaction
|
|
23
|
+
from .base import RootTransaction as RootTransaction
|
|
24
|
+
from .base import Transaction as Transaction
|
|
25
|
+
from .base import TwoPhaseTransaction as TwoPhaseTransaction
|
|
26
|
+
from .create import create_engine as create_engine
|
|
27
|
+
from .create import create_pool_from_url as create_pool_from_url
|
|
28
|
+
from .create import engine_from_config as engine_from_config
|
|
29
|
+
from .cursor import CursorResult as CursorResult
|
|
30
|
+
from .cursor import ResultProxy as ResultProxy
|
|
31
|
+
from .interfaces import AdaptedConnection as AdaptedConnection
|
|
32
|
+
from .interfaces import BindTyping as BindTyping
|
|
33
|
+
from .interfaces import Compiled as Compiled
|
|
34
|
+
from .interfaces import Connectable as Connectable
|
|
35
|
+
from .interfaces import ConnectArgsType as ConnectArgsType
|
|
36
|
+
from .interfaces import ConnectionEventsTarget as ConnectionEventsTarget
|
|
37
|
+
from .interfaces import CreateEnginePlugin as CreateEnginePlugin
|
|
38
|
+
from .interfaces import Dialect as Dialect
|
|
39
|
+
from .interfaces import ExceptionContext as ExceptionContext
|
|
40
|
+
from .interfaces import ExecutionContext as ExecutionContext
|
|
41
|
+
from .interfaces import TypeCompiler as TypeCompiler
|
|
42
|
+
from .mock import create_mock_engine as create_mock_engine
|
|
43
|
+
from .reflection import Inspector as Inspector
|
|
44
|
+
from .reflection import ObjectKind as ObjectKind
|
|
45
|
+
from .reflection import ObjectScope as ObjectScope
|
|
46
|
+
from .result import ChunkedIteratorResult as ChunkedIteratorResult
|
|
47
|
+
from .result import FilterResult as FilterResult
|
|
48
|
+
from .result import FrozenResult as FrozenResult
|
|
49
|
+
from .result import IteratorResult as IteratorResult
|
|
50
|
+
from .result import MappingResult as MappingResult
|
|
51
|
+
from .result import MergedResult as MergedResult
|
|
52
|
+
from .result import Result as Result
|
|
53
|
+
from .result import result_tuple as result_tuple
|
|
54
|
+
from .result import ScalarResult as ScalarResult
|
|
55
|
+
from .result import TupleResult as TupleResult
|
|
56
|
+
from .row import BaseRow as BaseRow
|
|
57
|
+
from .row import Row as Row
|
|
58
|
+
from .row import RowMapping as RowMapping
|
|
59
|
+
from .url import make_url as make_url
|
|
60
|
+
from .url import URL as URL
|
|
61
|
+
from .util import connection_memoize as connection_memoize
|
|
62
|
+
from ..sql import ddl as ddl
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# engine/_py_processors.py
|
|
2
|
+
# Copyright (C) 2010-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
# Copyright (C) 2010 Gaetan de Menten gdementen@gmail.com
|
|
5
|
+
#
|
|
6
|
+
# This module is part of SQLAlchemy and is released under
|
|
7
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
8
|
+
|
|
9
|
+
"""defines generic type conversion functions, as used in bind and result
|
|
10
|
+
processors.
|
|
11
|
+
|
|
12
|
+
They all share one common characteristic: None is passed through unchanged.
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import datetime
|
|
19
|
+
from datetime import date as date_cls
|
|
20
|
+
from datetime import datetime as datetime_cls
|
|
21
|
+
from datetime import time as time_cls
|
|
22
|
+
from decimal import Decimal
|
|
23
|
+
import typing
|
|
24
|
+
from typing import Any
|
|
25
|
+
from typing import Callable
|
|
26
|
+
from typing import Optional
|
|
27
|
+
from typing import Type
|
|
28
|
+
from typing import TypeVar
|
|
29
|
+
from typing import Union
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_DT = TypeVar(
|
|
33
|
+
"_DT", bound=Union[datetime.datetime, datetime.time, datetime.date]
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def str_to_datetime_processor_factory(
|
|
38
|
+
regexp: typing.Pattern[str], type_: Callable[..., _DT]
|
|
39
|
+
) -> Callable[[Optional[str]], Optional[_DT]]:
|
|
40
|
+
rmatch = regexp.match
|
|
41
|
+
# Even on python2.6 datetime.strptime is both slower than this code
|
|
42
|
+
# and it does not support microseconds.
|
|
43
|
+
has_named_groups = bool(regexp.groupindex)
|
|
44
|
+
|
|
45
|
+
def process(value: Optional[str]) -> Optional[_DT]:
|
|
46
|
+
if value is None:
|
|
47
|
+
return None
|
|
48
|
+
else:
|
|
49
|
+
try:
|
|
50
|
+
m = rmatch(value)
|
|
51
|
+
except TypeError as err:
|
|
52
|
+
raise ValueError(
|
|
53
|
+
"Couldn't parse %s string '%r' "
|
|
54
|
+
"- value is not a string." % (type_.__name__, value)
|
|
55
|
+
) from err
|
|
56
|
+
|
|
57
|
+
if m is None:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"Couldn't parse %s string: "
|
|
60
|
+
"'%s'" % (type_.__name__, value)
|
|
61
|
+
)
|
|
62
|
+
if has_named_groups:
|
|
63
|
+
groups = m.groupdict(0)
|
|
64
|
+
return type_(
|
|
65
|
+
**dict(
|
|
66
|
+
list(
|
|
67
|
+
zip(
|
|
68
|
+
iter(groups.keys()),
|
|
69
|
+
list(map(int, iter(groups.values()))),
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
return type_(*list(map(int, m.groups(0))))
|
|
76
|
+
|
|
77
|
+
return process
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def to_decimal_processor_factory(
|
|
81
|
+
target_class: Type[Decimal], scale: int
|
|
82
|
+
) -> Callable[[Optional[float]], Optional[Decimal]]:
|
|
83
|
+
fstring = "%%.%df" % scale
|
|
84
|
+
|
|
85
|
+
def process(value: Optional[float]) -> Optional[Decimal]:
|
|
86
|
+
if value is None:
|
|
87
|
+
return None
|
|
88
|
+
else:
|
|
89
|
+
return target_class(fstring % value)
|
|
90
|
+
|
|
91
|
+
return process
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def to_float(value: Optional[Union[int, float]]) -> Optional[float]:
|
|
95
|
+
if value is None:
|
|
96
|
+
return None
|
|
97
|
+
else:
|
|
98
|
+
return float(value)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def to_str(value: Optional[Any]) -> Optional[str]:
|
|
102
|
+
if value is None:
|
|
103
|
+
return None
|
|
104
|
+
else:
|
|
105
|
+
return str(value)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def int_to_boolean(value: Optional[int]) -> Optional[bool]:
|
|
109
|
+
if value is None:
|
|
110
|
+
return None
|
|
111
|
+
else:
|
|
112
|
+
return bool(value)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def str_to_datetime(value: Optional[str]) -> Optional[datetime.datetime]:
|
|
116
|
+
if value is not None:
|
|
117
|
+
dt_value = datetime_cls.fromisoformat(value)
|
|
118
|
+
else:
|
|
119
|
+
dt_value = None
|
|
120
|
+
return dt_value
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def str_to_time(value: Optional[str]) -> Optional[datetime.time]:
|
|
124
|
+
if value is not None:
|
|
125
|
+
dt_value = time_cls.fromisoformat(value)
|
|
126
|
+
else:
|
|
127
|
+
dt_value = None
|
|
128
|
+
return dt_value
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def str_to_date(value: Optional[str]) -> Optional[datetime.date]:
|
|
132
|
+
if value is not None:
|
|
133
|
+
dt_value = date_cls.fromisoformat(value)
|
|
134
|
+
else:
|
|
135
|
+
dt_value = None
|
|
136
|
+
return dt_value
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# engine/_py_row.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
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import operator
|
|
10
|
+
import typing
|
|
11
|
+
from typing import Any
|
|
12
|
+
from typing import Callable
|
|
13
|
+
from typing import Dict
|
|
14
|
+
from typing import Iterator
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import Mapping
|
|
17
|
+
from typing import Optional
|
|
18
|
+
from typing import Tuple
|
|
19
|
+
from typing import Type
|
|
20
|
+
|
|
21
|
+
if typing.TYPE_CHECKING:
|
|
22
|
+
from .result import _KeyType
|
|
23
|
+
from .result import _ProcessorsType
|
|
24
|
+
from .result import _RawRowType
|
|
25
|
+
from .result import _TupleGetterType
|
|
26
|
+
from .result import ResultMetaData
|
|
27
|
+
|
|
28
|
+
MD_INDEX = 0 # integer index in cursor.description
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BaseRow:
|
|
32
|
+
__slots__ = ("_parent", "_data", "_key_to_index")
|
|
33
|
+
|
|
34
|
+
_parent: ResultMetaData
|
|
35
|
+
_key_to_index: Mapping[_KeyType, int]
|
|
36
|
+
_data: _RawRowType
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
parent: ResultMetaData,
|
|
41
|
+
processors: Optional[_ProcessorsType],
|
|
42
|
+
key_to_index: Mapping[_KeyType, int],
|
|
43
|
+
data: _RawRowType,
|
|
44
|
+
):
|
|
45
|
+
"""Row objects are constructed by CursorResult objects."""
|
|
46
|
+
object.__setattr__(self, "_parent", parent)
|
|
47
|
+
|
|
48
|
+
object.__setattr__(self, "_key_to_index", key_to_index)
|
|
49
|
+
|
|
50
|
+
if processors:
|
|
51
|
+
object.__setattr__(
|
|
52
|
+
self,
|
|
53
|
+
"_data",
|
|
54
|
+
tuple(
|
|
55
|
+
[
|
|
56
|
+
proc(value) if proc else value
|
|
57
|
+
for proc, value in zip(processors, data)
|
|
58
|
+
]
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
object.__setattr__(self, "_data", tuple(data))
|
|
63
|
+
|
|
64
|
+
def __reduce__(self) -> Tuple[Callable[..., BaseRow], Tuple[Any, ...]]:
|
|
65
|
+
return (
|
|
66
|
+
rowproxy_reconstructor,
|
|
67
|
+
(self.__class__, self.__getstate__()),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def __getstate__(self) -> Dict[str, Any]:
|
|
71
|
+
return {"_parent": self._parent, "_data": self._data}
|
|
72
|
+
|
|
73
|
+
def __setstate__(self, state: Dict[str, Any]) -> None:
|
|
74
|
+
parent = state["_parent"]
|
|
75
|
+
object.__setattr__(self, "_parent", parent)
|
|
76
|
+
object.__setattr__(self, "_data", state["_data"])
|
|
77
|
+
object.__setattr__(self, "_key_to_index", parent._key_to_index)
|
|
78
|
+
|
|
79
|
+
def _values_impl(self) -> List[Any]:
|
|
80
|
+
return list(self)
|
|
81
|
+
|
|
82
|
+
def __iter__(self) -> Iterator[Any]:
|
|
83
|
+
return iter(self._data)
|
|
84
|
+
|
|
85
|
+
def __len__(self) -> int:
|
|
86
|
+
return len(self._data)
|
|
87
|
+
|
|
88
|
+
def __hash__(self) -> int:
|
|
89
|
+
return hash(self._data)
|
|
90
|
+
|
|
91
|
+
def __getitem__(self, key: Any) -> Any:
|
|
92
|
+
return self._data[key]
|
|
93
|
+
|
|
94
|
+
def _get_by_key_impl_mapping(self, key: str) -> Any:
|
|
95
|
+
try:
|
|
96
|
+
return self._data[self._key_to_index[key]]
|
|
97
|
+
except KeyError:
|
|
98
|
+
pass
|
|
99
|
+
self._parent._key_not_found(key, False)
|
|
100
|
+
|
|
101
|
+
def __getattr__(self, name: str) -> Any:
|
|
102
|
+
try:
|
|
103
|
+
return self._data[self._key_to_index[name]]
|
|
104
|
+
except KeyError:
|
|
105
|
+
pass
|
|
106
|
+
self._parent._key_not_found(name, True)
|
|
107
|
+
|
|
108
|
+
def _to_tuple_instance(self) -> Tuple[Any, ...]:
|
|
109
|
+
return self._data
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# This reconstructor is necessary so that pickles with the Cy extension or
|
|
113
|
+
# without use the same Binary format.
|
|
114
|
+
def rowproxy_reconstructor(
|
|
115
|
+
cls: Type[BaseRow], state: Dict[str, Any]
|
|
116
|
+
) -> BaseRow:
|
|
117
|
+
obj = cls.__new__(cls)
|
|
118
|
+
obj.__setstate__(state)
|
|
119
|
+
return obj
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def tuplegetter(*indexes: int) -> _TupleGetterType:
|
|
123
|
+
if len(indexes) != 1:
|
|
124
|
+
for i in range(1, len(indexes)):
|
|
125
|
+
if indexes[i - 1] != indexes[i] - 1:
|
|
126
|
+
return operator.itemgetter(*indexes)
|
|
127
|
+
# slice form is faster but returns a list if input is list
|
|
128
|
+
return operator.itemgetter(slice(indexes[0], indexes[-1] + 1))
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# engine/_py_util.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
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import typing
|
|
10
|
+
from typing import Any
|
|
11
|
+
from typing import Mapping
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from typing import Tuple
|
|
14
|
+
|
|
15
|
+
from .. import exc
|
|
16
|
+
|
|
17
|
+
if typing.TYPE_CHECKING:
|
|
18
|
+
from .interfaces import _CoreAnyExecuteParams
|
|
19
|
+
from .interfaces import _CoreMultiExecuteParams
|
|
20
|
+
from .interfaces import _DBAPIAnyExecuteParams
|
|
21
|
+
from .interfaces import _DBAPIMultiExecuteParams
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_no_tuple: Tuple[Any, ...] = ()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _distill_params_20(
|
|
28
|
+
params: Optional[_CoreAnyExecuteParams],
|
|
29
|
+
) -> _CoreMultiExecuteParams:
|
|
30
|
+
if params is None:
|
|
31
|
+
return _no_tuple
|
|
32
|
+
# Assume list is more likely than tuple
|
|
33
|
+
elif isinstance(params, list) or isinstance(params, tuple):
|
|
34
|
+
# collections_abc.MutableSequence): # avoid abc.__instancecheck__
|
|
35
|
+
if params and not isinstance(params[0], Mapping):
|
|
36
|
+
raise exc.ArgumentError(
|
|
37
|
+
"List argument must consist only of dictionaries"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return params
|
|
41
|
+
elif isinstance(params, dict) or isinstance(
|
|
42
|
+
# only do immutabledict or abc.__instancecheck__ for Mapping after
|
|
43
|
+
# we've checked for plain dictionaries and would otherwise raise
|
|
44
|
+
params,
|
|
45
|
+
Mapping,
|
|
46
|
+
):
|
|
47
|
+
return [params]
|
|
48
|
+
else:
|
|
49
|
+
raise exc.ArgumentError("mapping or list expected for parameters")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _distill_raw_params(
|
|
53
|
+
params: Optional[_DBAPIAnyExecuteParams],
|
|
54
|
+
) -> _DBAPIMultiExecuteParams:
|
|
55
|
+
if params is None:
|
|
56
|
+
return _no_tuple
|
|
57
|
+
elif isinstance(params, list):
|
|
58
|
+
# collections_abc.MutableSequence): # avoid abc.__instancecheck__
|
|
59
|
+
if params and not isinstance(params[0], (tuple, Mapping)):
|
|
60
|
+
raise exc.ArgumentError(
|
|
61
|
+
"List argument must consist only of tuples or dictionaries"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return params
|
|
65
|
+
elif isinstance(params, (tuple, dict)) or isinstance(
|
|
66
|
+
# only do abc.__instancecheck__ for Mapping after we've checked
|
|
67
|
+
# for plain dictionaries and would otherwise raise
|
|
68
|
+
params,
|
|
69
|
+
Mapping,
|
|
70
|
+
):
|
|
71
|
+
# cast("Union[List[Mapping[str, Any]], Tuple[Any, ...]]", [params])
|
|
72
|
+
return [params] # type: ignore
|
|
73
|
+
else:
|
|
74
|
+
raise exc.ArgumentError("mapping or sequence expected for parameters")
|