alembic 1.14.0__py3-none-any.whl → 1.15.0__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.
- alembic/__init__.py +1 -1
- alembic/autogenerate/api.py +2 -2
- alembic/autogenerate/compare.py +11 -23
- alembic/autogenerate/render.py +29 -22
- alembic/command.py +3 -1
- alembic/context.pyi +5 -2
- alembic/ddl/base.py +2 -2
- alembic/ddl/impl.py +8 -9
- alembic/ddl/mysql.py +1 -2
- alembic/ddl/postgresql.py +7 -6
- alembic/ddl/sqlite.py +13 -1
- alembic/op.pyi +1 -2
- alembic/operations/base.py +1 -2
- alembic/operations/batch.py +5 -4
- alembic/operations/ops.py +1 -2
- alembic/operations/toimpl.py +0 -13
- alembic/runtime/environment.py +2 -2
- alembic/runtime/migration.py +4 -4
- alembic/testing/assertions.py +2 -3
- alembic/testing/env.py +62 -78
- alembic/testing/fixtures.py +3 -15
- alembic/testing/requirements.py +1 -35
- alembic/testing/suite/test_autogen_computed.py +2 -62
- alembic/testing/warnings.py +0 -9
- alembic/util/__init__.py +0 -7
- alembic/util/compat.py +1 -0
- alembic/util/exc.py +20 -1
- alembic/util/messaging.py +1 -4
- alembic/util/sqla_compat.py +72 -238
- {alembic-1.14.0.dist-info → alembic-1.15.0.dist-info}/LICENSE +1 -1
- {alembic-1.14.0.dist-info → alembic-1.15.0.dist-info}/METADATA +9 -12
- alembic-1.15.0.dist-info/RECORD +74 -0
- {alembic-1.14.0.dist-info → alembic-1.15.0.dist-info}/WHEEL +1 -1
- alembic/templates/async/README +0 -1
- alembic/templates/async/alembic.ini.mako +0 -115
- alembic/templates/async/script.py.mako +0 -26
- alembic/templates/generic/README +0 -1
- alembic/templates/generic/alembic.ini.mako +0 -117
- alembic/templates/generic/script.py.mako +0 -26
- alembic/templates/multidb/README +0 -12
- alembic/templates/multidb/alembic.ini.mako +0 -122
- alembic/templates/multidb/script.py.mako +0 -47
- alembic-1.14.0.dist-info/RECORD +0 -83
- {alembic-1.14.0.dist-info → alembic-1.15.0.dist-info}/entry_points.txt +0 -0
- {alembic-1.14.0.dist-info → alembic-1.15.0.dist-info}/top_level.txt +0 -0
alembic/__init__.py
CHANGED
alembic/autogenerate/api.py
CHANGED
@@ -277,7 +277,7 @@ class AutogenContext:
|
|
277
277
|
"""Maintains configuration and state that's specific to an
|
278
278
|
autogenerate operation."""
|
279
279
|
|
280
|
-
metadata:
|
280
|
+
metadata: Union[MetaData, Sequence[MetaData], None] = None
|
281
281
|
"""The :class:`~sqlalchemy.schema.MetaData` object
|
282
282
|
representing the destination.
|
283
283
|
|
@@ -332,7 +332,7 @@ class AutogenContext:
|
|
332
332
|
def __init__(
|
333
333
|
self,
|
334
334
|
migration_context: MigrationContext,
|
335
|
-
metadata:
|
335
|
+
metadata: Union[MetaData, Sequence[MetaData], None] = None,
|
336
336
|
opts: Optional[Dict[str, Any]] = None,
|
337
337
|
autogenerate: bool = True,
|
338
338
|
) -> None:
|
alembic/autogenerate/compare.py
CHANGED
@@ -216,7 +216,7 @@ def _compare_tables(
|
|
216
216
|
(inspector),
|
217
217
|
# fmt: on
|
218
218
|
)
|
219
|
-
|
219
|
+
inspector.reflect_table(t, include_columns=None)
|
220
220
|
if autogen_context.run_object_filters(t, tname, "table", True, None):
|
221
221
|
modify_table_ops = ops.ModifyTableOps(tname, [], schema=s)
|
222
222
|
|
@@ -246,7 +246,7 @@ def _compare_tables(
|
|
246
246
|
_compat_autogen_column_reflect(inspector),
|
247
247
|
# fmt: on
|
248
248
|
)
|
249
|
-
|
249
|
+
inspector.reflect_table(t, include_columns=None)
|
250
250
|
conn_column_info[(s, tname)] = t
|
251
251
|
|
252
252
|
for s, tname in sorted(existing_tables, key=lambda x: (x[0] or "", x[1])):
|
@@ -1067,27 +1067,15 @@ def _compare_server_default(
|
|
1067
1067
|
return False
|
1068
1068
|
|
1069
1069
|
if sqla_compat._server_default_is_computed(metadata_default):
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
else:
|
1080
|
-
return (
|
1081
|
-
_compare_computed_default( # type:ignore[func-returns-value]
|
1082
|
-
autogen_context,
|
1083
|
-
alter_column_op,
|
1084
|
-
schema,
|
1085
|
-
tname,
|
1086
|
-
cname,
|
1087
|
-
conn_col,
|
1088
|
-
metadata_col,
|
1089
|
-
)
|
1090
|
-
)
|
1070
|
+
return _compare_computed_default( # type:ignore[func-returns-value]
|
1071
|
+
autogen_context,
|
1072
|
+
alter_column_op,
|
1073
|
+
schema,
|
1074
|
+
tname,
|
1075
|
+
cname,
|
1076
|
+
conn_col,
|
1077
|
+
metadata_col,
|
1078
|
+
)
|
1091
1079
|
if sqla_compat._server_default_is_computed(conn_col_default):
|
1092
1080
|
_warn_computed_not_supported(tname, cname)
|
1093
1081
|
return False
|
alembic/autogenerate/render.py
CHANGED
@@ -19,6 +19,7 @@ from sqlalchemy import schema as sa_schema
|
|
19
19
|
from sqlalchemy import sql
|
20
20
|
from sqlalchemy import types as sqltypes
|
21
21
|
from sqlalchemy.sql.elements import conv
|
22
|
+
from sqlalchemy.sql.elements import Label
|
22
23
|
from sqlalchemy.sql.elements import quoted_name
|
23
24
|
|
24
25
|
from .. import util
|
@@ -28,6 +29,8 @@ from ..util import sqla_compat
|
|
28
29
|
if TYPE_CHECKING:
|
29
30
|
from typing import Literal
|
30
31
|
|
32
|
+
from sqlalchemy import Computed
|
33
|
+
from sqlalchemy import Identity
|
31
34
|
from sqlalchemy.sql.base import DialectKWArgs
|
32
35
|
from sqlalchemy.sql.elements import ColumnElement
|
33
36
|
from sqlalchemy.sql.elements import TextClause
|
@@ -48,8 +51,6 @@ if TYPE_CHECKING:
|
|
48
51
|
from alembic.config import Config
|
49
52
|
from alembic.operations.ops import MigrationScript
|
50
53
|
from alembic.operations.ops import ModifyTableOps
|
51
|
-
from alembic.util.sqla_compat import Computed
|
52
|
-
from alembic.util.sqla_compat import Identity
|
53
54
|
|
54
55
|
|
55
56
|
MAX_PYTHON_ARGS = 255
|
@@ -584,23 +585,28 @@ def _render_potential_expr(
|
|
584
585
|
value: Any,
|
585
586
|
autogen_context: AutogenContext,
|
586
587
|
*,
|
587
|
-
|
588
|
+
wrap_in_element: bool = True,
|
588
589
|
is_server_default: bool = False,
|
589
590
|
is_index: bool = False,
|
590
591
|
) -> str:
|
591
592
|
if isinstance(value, sql.ClauseElement):
|
592
|
-
|
593
|
-
|
593
|
+
sql_text = autogen_context.migration_context.impl.render_ddl_sql_expr(
|
594
|
+
value, is_server_default=is_server_default, is_index=is_index
|
595
|
+
)
|
596
|
+
if wrap_in_element:
|
597
|
+
prefix = _sqlalchemy_autogenerate_prefix(autogen_context)
|
598
|
+
element = "literal_column" if is_index else "text"
|
599
|
+
value_str = f"{prefix}{element}({sql_text!r})"
|
600
|
+
if (
|
601
|
+
is_index
|
602
|
+
and isinstance(value, Label)
|
603
|
+
and type(value.name) is str
|
604
|
+
):
|
605
|
+
return value_str + f".label({value.name!r})"
|
606
|
+
else:
|
607
|
+
return value_str
|
594
608
|
else:
|
595
|
-
|
596
|
-
|
597
|
-
return template % {
|
598
|
-
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
|
599
|
-
"sql": autogen_context.migration_context.impl.render_ddl_sql_expr(
|
600
|
-
value, is_server_default=is_server_default, is_index=is_index
|
601
|
-
),
|
602
|
-
}
|
603
|
-
|
609
|
+
return repr(sql_text)
|
604
610
|
else:
|
605
611
|
return repr(value)
|
606
612
|
|
@@ -628,9 +634,9 @@ def _uq_constraint(
|
|
628
634
|
has_batch = autogen_context._has_batch
|
629
635
|
|
630
636
|
if constraint.deferrable:
|
631
|
-
opts.append(("deferrable",
|
637
|
+
opts.append(("deferrable", constraint.deferrable))
|
632
638
|
if constraint.initially:
|
633
|
-
opts.append(("initially",
|
639
|
+
opts.append(("initially", constraint.initially))
|
634
640
|
if not has_batch and alter and constraint.table.schema:
|
635
641
|
opts.append(("schema", _ident(constraint.table.schema)))
|
636
642
|
if not alter and constraint.name:
|
@@ -741,7 +747,7 @@ def _render_column(
|
|
741
747
|
+ [
|
742
748
|
"%s=%s"
|
743
749
|
% (key, _render_potential_expr(val, autogen_context))
|
744
|
-
for key, val in
|
750
|
+
for key, val in column.kwargs.items()
|
745
751
|
]
|
746
752
|
)
|
747
753
|
),
|
@@ -787,7 +793,7 @@ def _render_computed(
|
|
787
793
|
computed: Computed, autogen_context: AutogenContext
|
788
794
|
) -> str:
|
789
795
|
text = _render_potential_expr(
|
790
|
-
computed.sqltext, autogen_context,
|
796
|
+
computed.sqltext, autogen_context, wrap_in_element=False
|
791
797
|
)
|
792
798
|
|
793
799
|
kwargs = {}
|
@@ -831,7 +837,10 @@ def _repr_type(
|
|
831
837
|
|
832
838
|
mod = type(type_).__module__
|
833
839
|
imports = autogen_context.imports
|
834
|
-
|
840
|
+
|
841
|
+
if not _skip_variants and sqla_compat._type_has_variants(type_):
|
842
|
+
return _render_Variant_type(type_, autogen_context)
|
843
|
+
elif mod.startswith("sqlalchemy.dialects"):
|
835
844
|
match = re.match(r"sqlalchemy\.dialects\.(\w+)", mod)
|
836
845
|
assert match is not None
|
837
846
|
dname = match.group(1)
|
@@ -843,8 +852,6 @@ def _repr_type(
|
|
843
852
|
return "%s.%r" % (dname, type_)
|
844
853
|
elif impl_rt:
|
845
854
|
return impl_rt
|
846
|
-
elif not _skip_variants and sqla_compat._type_has_variants(type_):
|
847
|
-
return _render_Variant_type(type_, autogen_context)
|
848
855
|
elif mod.startswith("sqlalchemy."):
|
849
856
|
if "_render_%s_type" % type_.__visit_name__ in globals():
|
850
857
|
fn = globals()["_render_%s_type" % type_.__visit_name__]
|
@@ -1100,7 +1107,7 @@ def _render_check_constraint(
|
|
1100
1107
|
else ""
|
1101
1108
|
),
|
1102
1109
|
"sqltext": _render_potential_expr(
|
1103
|
-
constraint.sqltext, autogen_context,
|
1110
|
+
constraint.sqltext, autogen_context, wrap_in_element=False
|
1104
1111
|
),
|
1105
1112
|
}
|
1106
1113
|
|
alembic/command.py
CHANGED
@@ -298,7 +298,9 @@ def check(config: "Config") -> None:
|
|
298
298
|
|
299
299
|
if diffs:
|
300
300
|
raise util.AutogenerateDiffsDetected(
|
301
|
-
f"New upgrade operations detected: {diffs}"
|
301
|
+
f"New upgrade operations detected: {diffs}",
|
302
|
+
revision_context=revision_context,
|
303
|
+
diffs=diffs,
|
302
304
|
)
|
303
305
|
else:
|
304
306
|
config.print_stdout("No new upgrade operations detected.")
|
alembic/context.pyi
CHANGED
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
5
5
|
from typing import Any
|
6
6
|
from typing import Callable
|
7
7
|
from typing import Collection
|
8
|
-
from typing import ContextManager
|
9
8
|
from typing import Dict
|
10
9
|
from typing import Iterable
|
11
10
|
from typing import List
|
@@ -20,6 +19,8 @@ from typing import Tuple
|
|
20
19
|
from typing import TYPE_CHECKING
|
21
20
|
from typing import Union
|
22
21
|
|
22
|
+
from typing_extensions import ContextManager
|
23
|
+
|
23
24
|
if TYPE_CHECKING:
|
24
25
|
from sqlalchemy.engine.base import Connection
|
25
26
|
from sqlalchemy.engine.url import URL
|
@@ -40,7 +41,9 @@ if TYPE_CHECKING:
|
|
40
41
|
|
41
42
|
### end imports ###
|
42
43
|
|
43
|
-
def begin_transaction() ->
|
44
|
+
def begin_transaction() -> (
|
45
|
+
Union[_ProxyTransaction, ContextManager[None, Optional[bool]]]
|
46
|
+
):
|
44
47
|
"""Return a context manager that will
|
45
48
|
enclose an operation within a "transaction",
|
46
49
|
as defined by the environment's offline
|
alembic/ddl/base.py
CHANGED
@@ -25,6 +25,8 @@ from ..util.sqla_compat import _table_for_constraint # noqa
|
|
25
25
|
if TYPE_CHECKING:
|
26
26
|
from typing import Any
|
27
27
|
|
28
|
+
from sqlalchemy import Computed
|
29
|
+
from sqlalchemy import Identity
|
28
30
|
from sqlalchemy.sql.compiler import Compiled
|
29
31
|
from sqlalchemy.sql.compiler import DDLCompiler
|
30
32
|
from sqlalchemy.sql.elements import TextClause
|
@@ -33,8 +35,6 @@ if TYPE_CHECKING:
|
|
33
35
|
from sqlalchemy.sql.type_api import TypeEngine
|
34
36
|
|
35
37
|
from .impl import DefaultImpl
|
36
|
-
from ..util.sqla_compat import Computed
|
37
|
-
from ..util.sqla_compat import Identity
|
38
38
|
|
39
39
|
_ServerDefault = Union["TextClause", "FetchedValue", "Function[Any]", str]
|
40
40
|
|
alembic/ddl/impl.py
CHANGED
@@ -459,7 +459,9 @@ class DefaultImpl(metaclass=ImplMeta):
|
|
459
459
|
if self.as_sql:
|
460
460
|
for row in rows:
|
461
461
|
self._exec(
|
462
|
-
|
462
|
+
table.insert()
|
463
|
+
.inline()
|
464
|
+
.values(
|
463
465
|
**{
|
464
466
|
k: (
|
465
467
|
sqla_compat._literal_bindparam(
|
@@ -477,14 +479,10 @@ class DefaultImpl(metaclass=ImplMeta):
|
|
477
479
|
else:
|
478
480
|
if rows:
|
479
481
|
if multiinsert:
|
480
|
-
self._exec(
|
481
|
-
sqla_compat._insert_inline(table), multiparams=rows
|
482
|
-
)
|
482
|
+
self._exec(table.insert().inline(), multiparams=rows)
|
483
483
|
else:
|
484
484
|
for row in rows:
|
485
|
-
self._exec(
|
486
|
-
sqla_compat._insert_inline(table).values(**row)
|
487
|
-
)
|
485
|
+
self._exec(table.insert().inline().values(**row))
|
488
486
|
|
489
487
|
def _tokenize_column_type(self, column: Column) -> Params:
|
490
488
|
definition: str
|
@@ -693,7 +691,7 @@ class DefaultImpl(metaclass=ImplMeta):
|
|
693
691
|
diff, ignored = _compare_identity_options(
|
694
692
|
metadata_identity,
|
695
693
|
inspector_identity,
|
696
|
-
|
694
|
+
schema.Identity(),
|
697
695
|
skip={"always"},
|
698
696
|
)
|
699
697
|
|
@@ -874,12 +872,13 @@ def _compare_identity_options(
|
|
874
872
|
set(meta_d).union(insp_d),
|
875
873
|
)
|
876
874
|
if sqla_compat.identity_has_dialect_kwargs:
|
875
|
+
assert hasattr(default_io, "dialect_kwargs")
|
877
876
|
# use only the dialect kwargs in inspector_io since metadata_io
|
878
877
|
# can have options for many backends
|
879
878
|
check_dicts(
|
880
879
|
getattr(metadata_io, "dialect_kwargs", {}),
|
881
880
|
getattr(inspector_io, "dialect_kwargs", {}),
|
882
|
-
default_io.dialect_kwargs,
|
881
|
+
default_io.dialect_kwargs,
|
883
882
|
getattr(inspector_io, "dialect_kwargs", {}),
|
884
883
|
)
|
885
884
|
|
alembic/ddl/mysql.py
CHANGED
@@ -23,7 +23,6 @@ from .base import format_server_default
|
|
23
23
|
from .impl import DefaultImpl
|
24
24
|
from .. import util
|
25
25
|
from ..util import sqla_compat
|
26
|
-
from ..util.sqla_compat import _is_mariadb
|
27
26
|
from ..util.sqla_compat import _is_type_bound
|
28
27
|
from ..util.sqla_compat import compiles
|
29
28
|
|
@@ -475,7 +474,7 @@ def _mysql_drop_constraint(
|
|
475
474
|
# note that SQLAlchemy as of 1.2 does not yet support
|
476
475
|
# DROP CONSTRAINT for MySQL/MariaDB, so we implement fully
|
477
476
|
# here.
|
478
|
-
if
|
477
|
+
if compiler.dialect.is_mariadb: # type: ignore[attr-defined]
|
479
478
|
return "ALTER TABLE %s DROP CONSTRAINT %s" % (
|
480
479
|
compiler.preparer.format_table(constraint.table),
|
481
480
|
compiler.preparer.format_constraint(constraint),
|
alembic/ddl/postgresql.py
CHANGED
@@ -16,8 +16,11 @@ from typing import TYPE_CHECKING
|
|
16
16
|
from typing import Union
|
17
17
|
|
18
18
|
from sqlalchemy import Column
|
19
|
+
from sqlalchemy import Float
|
20
|
+
from sqlalchemy import Identity
|
19
21
|
from sqlalchemy import literal_column
|
20
22
|
from sqlalchemy import Numeric
|
23
|
+
from sqlalchemy import select
|
21
24
|
from sqlalchemy import text
|
22
25
|
from sqlalchemy import types as sqltypes
|
23
26
|
from sqlalchemy.dialects.postgresql import BIGINT
|
@@ -132,7 +135,7 @@ class PostgresqlImpl(DefaultImpl):
|
|
132
135
|
metadata_default = metadata_column.server_default.arg
|
133
136
|
|
134
137
|
if isinstance(metadata_default, str):
|
135
|
-
if not isinstance(inspector_column.type, Numeric):
|
138
|
+
if not isinstance(inspector_column.type, (Numeric, Float)):
|
136
139
|
metadata_default = re.sub(r"^'|'$", "", metadata_default)
|
137
140
|
metadata_default = f"'{metadata_default}'"
|
138
141
|
|
@@ -142,9 +145,7 @@ class PostgresqlImpl(DefaultImpl):
|
|
142
145
|
conn = self.connection
|
143
146
|
assert conn is not None
|
144
147
|
return not conn.scalar(
|
145
|
-
|
146
|
-
literal_column(conn_col_default) == metadata_default
|
147
|
-
)
|
148
|
+
select(literal_column(conn_col_default) == metadata_default)
|
148
149
|
)
|
149
150
|
|
150
151
|
def alter_column( # type:ignore[override]
|
@@ -585,7 +586,7 @@ def visit_identity_column(
|
|
585
586
|
)
|
586
587
|
else:
|
587
588
|
text += "SET %s " % compiler.get_identity_options(
|
588
|
-
|
589
|
+
Identity(**{attr: getattr(identity, attr)})
|
589
590
|
)
|
590
591
|
return text
|
591
592
|
|
@@ -845,5 +846,5 @@ def _render_potential_column(
|
|
845
846
|
return render._render_potential_expr(
|
846
847
|
value,
|
847
848
|
autogen_context,
|
848
|
-
|
849
|
+
wrap_in_element=isinstance(value, (TextClause, FunctionElement)),
|
849
850
|
)
|
alembic/ddl/sqlite.py
CHANGED
@@ -11,11 +11,14 @@ from typing import TYPE_CHECKING
|
|
11
11
|
from typing import Union
|
12
12
|
|
13
13
|
from sqlalchemy import cast
|
14
|
+
from sqlalchemy import Computed
|
14
15
|
from sqlalchemy import JSON
|
15
16
|
from sqlalchemy import schema
|
16
17
|
from sqlalchemy import sql
|
17
18
|
|
18
19
|
from .base import alter_table
|
20
|
+
from .base import ColumnName
|
21
|
+
from .base import format_column_name
|
19
22
|
from .base import format_table_name
|
20
23
|
from .base import RenameTable
|
21
24
|
from .impl import DefaultImpl
|
@@ -62,7 +65,7 @@ class SQLiteImpl(DefaultImpl):
|
|
62
65
|
) and isinstance(col.server_default.arg, sql.ClauseElement):
|
63
66
|
return True
|
64
67
|
elif (
|
65
|
-
isinstance(col.server_default,
|
68
|
+
isinstance(col.server_default, Computed)
|
66
69
|
and col.server_default.persisted
|
67
70
|
):
|
68
71
|
return True
|
@@ -207,6 +210,15 @@ def visit_rename_table(
|
|
207
210
|
)
|
208
211
|
|
209
212
|
|
213
|
+
@compiles(ColumnName, "sqlite")
|
214
|
+
def visit_column_name(element: ColumnName, compiler: DDLCompiler, **kw) -> str:
|
215
|
+
return "%s RENAME COLUMN %s TO %s" % (
|
216
|
+
alter_table(compiler, element.table_name, element.schema),
|
217
|
+
format_column_name(compiler, element.column_name),
|
218
|
+
format_column_name(compiler, element.newname),
|
219
|
+
)
|
220
|
+
|
221
|
+
|
210
222
|
# @compiles(AddColumn, 'sqlite')
|
211
223
|
# def visit_add_column(element, compiler, **kw):
|
212
224
|
# return "%s %s" % (
|
alembic/op.pyi
CHANGED
@@ -27,7 +27,6 @@ if TYPE_CHECKING:
|
|
27
27
|
from sqlalchemy.sql.elements import conv
|
28
28
|
from sqlalchemy.sql.elements import TextClause
|
29
29
|
from sqlalchemy.sql.expression import TableClause
|
30
|
-
from sqlalchemy.sql.functions import Function
|
31
30
|
from sqlalchemy.sql.schema import Column
|
32
31
|
from sqlalchemy.sql.schema import Computed
|
33
32
|
from sqlalchemy.sql.schema import Identity
|
@@ -650,7 +649,7 @@ def create_foreign_key(
|
|
650
649
|
def create_index(
|
651
650
|
index_name: Optional[str],
|
652
651
|
table_name: str,
|
653
|
-
columns: Sequence[Union[str, TextClause,
|
652
|
+
columns: Sequence[Union[str, TextClause, ColumnElement[Any]]],
|
654
653
|
*,
|
655
654
|
schema: Optional[str] = None,
|
656
655
|
unique: bool = False,
|
alembic/operations/base.py
CHANGED
@@ -43,7 +43,6 @@ if TYPE_CHECKING:
|
|
43
43
|
from sqlalchemy.sql.expression import ColumnElement
|
44
44
|
from sqlalchemy.sql.expression import TableClause
|
45
45
|
from sqlalchemy.sql.expression import TextClause
|
46
|
-
from sqlalchemy.sql.functions import Function
|
47
46
|
from sqlalchemy.sql.schema import Column
|
48
47
|
from sqlalchemy.sql.schema import Computed
|
49
48
|
from sqlalchemy.sql.schema import Identity
|
@@ -1074,7 +1073,7 @@ class Operations(AbstractOperations):
|
|
1074
1073
|
self,
|
1075
1074
|
index_name: Optional[str],
|
1076
1075
|
table_name: str,
|
1077
|
-
columns: Sequence[Union[str, TextClause,
|
1076
|
+
columns: Sequence[Union[str, TextClause, ColumnElement[Any]]],
|
1078
1077
|
*,
|
1079
1078
|
schema: Optional[str] = None,
|
1080
1079
|
unique: bool = False,
|
alembic/operations/batch.py
CHANGED
@@ -18,6 +18,7 @@ from sqlalchemy import Index
|
|
18
18
|
from sqlalchemy import MetaData
|
19
19
|
from sqlalchemy import PrimaryKeyConstraint
|
20
20
|
from sqlalchemy import schema as sql_schema
|
21
|
+
from sqlalchemy import select
|
21
22
|
from sqlalchemy import Table
|
22
23
|
from sqlalchemy import types as sqltypes
|
23
24
|
from sqlalchemy.sql.schema import SchemaEventTarget
|
@@ -31,11 +32,9 @@ from ..util.sqla_compat import _copy_expression
|
|
31
32
|
from ..util.sqla_compat import _ensure_scope_for_ddl
|
32
33
|
from ..util.sqla_compat import _fk_is_self_referential
|
33
34
|
from ..util.sqla_compat import _idx_table_bound_expressions
|
34
|
-
from ..util.sqla_compat import _insert_inline
|
35
35
|
from ..util.sqla_compat import _is_type_bound
|
36
36
|
from ..util.sqla_compat import _remove_column_from_collection
|
37
37
|
from ..util.sqla_compat import _resolve_for_variant
|
38
|
-
from ..util.sqla_compat import _select
|
39
38
|
from ..util.sqla_compat import constraint_name_defined
|
40
39
|
from ..util.sqla_compat import constraint_name_string
|
41
40
|
|
@@ -449,13 +448,15 @@ class ApplyBatchImpl:
|
|
449
448
|
|
450
449
|
try:
|
451
450
|
op_impl._exec(
|
452
|
-
|
451
|
+
self.new_table.insert()
|
452
|
+
.inline()
|
453
|
+
.from_select(
|
453
454
|
list(
|
454
455
|
k
|
455
456
|
for k, transfer in self.column_transfers.items()
|
456
457
|
if "expr" in transfer
|
457
458
|
),
|
458
|
-
|
459
|
+
select(
|
459
460
|
*[
|
460
461
|
transfer["expr"]
|
461
462
|
for transfer in self.column_transfers.values()
|
alembic/operations/ops.py
CHANGED
@@ -35,7 +35,6 @@ if TYPE_CHECKING:
|
|
35
35
|
from sqlalchemy.sql.elements import conv
|
36
36
|
from sqlalchemy.sql.elements import quoted_name
|
37
37
|
from sqlalchemy.sql.elements import TextClause
|
38
|
-
from sqlalchemy.sql.functions import Function
|
39
38
|
from sqlalchemy.sql.schema import CheckConstraint
|
40
39
|
from sqlalchemy.sql.schema import Column
|
41
40
|
from sqlalchemy.sql.schema import Computed
|
@@ -933,7 +932,7 @@ class CreateIndexOp(MigrateOperation):
|
|
933
932
|
operations: Operations,
|
934
933
|
index_name: Optional[str],
|
935
934
|
table_name: str,
|
936
|
-
columns: Sequence[Union[str, TextClause,
|
935
|
+
columns: Sequence[Union[str, TextClause, ColumnElement[Any]]],
|
937
936
|
*,
|
938
937
|
schema: Optional[str] = None,
|
939
938
|
unique: bool = False,
|
alembic/operations/toimpl.py
CHANGED
@@ -8,7 +8,6 @@ from sqlalchemy import schema as sa_schema
|
|
8
8
|
from . import ops
|
9
9
|
from .base import Operations
|
10
10
|
from ..util.sqla_compat import _copy
|
11
|
-
from ..util.sqla_compat import sqla_14
|
12
11
|
|
13
12
|
if TYPE_CHECKING:
|
14
13
|
from sqlalchemy.sql.schema import Table
|
@@ -81,9 +80,6 @@ def alter_column(
|
|
81
80
|
def drop_table(operations: "Operations", operation: "ops.DropTableOp") -> None:
|
82
81
|
kw = {}
|
83
82
|
if operation.if_exists is not None:
|
84
|
-
if not sqla_14:
|
85
|
-
raise NotImplementedError("SQLAlchemy 1.4+ required")
|
86
|
-
|
87
83
|
kw["if_exists"] = operation.if_exists
|
88
84
|
operations.impl.drop_table(
|
89
85
|
operation.to_table(operations.migration_context), **kw
|
@@ -107,9 +103,6 @@ def create_index(
|
|
107
103
|
idx = operation.to_index(operations.migration_context)
|
108
104
|
kw = {}
|
109
105
|
if operation.if_not_exists is not None:
|
110
|
-
if not sqla_14:
|
111
|
-
raise NotImplementedError("SQLAlchemy 1.4+ required")
|
112
|
-
|
113
106
|
kw["if_not_exists"] = operation.if_not_exists
|
114
107
|
operations.impl.create_index(idx, **kw)
|
115
108
|
|
@@ -118,9 +111,6 @@ def create_index(
|
|
118
111
|
def drop_index(operations: "Operations", operation: "ops.DropIndexOp") -> None:
|
119
112
|
kw = {}
|
120
113
|
if operation.if_exists is not None:
|
121
|
-
if not sqla_14:
|
122
|
-
raise NotImplementedError("SQLAlchemy 1.4+ required")
|
123
|
-
|
124
114
|
kw["if_exists"] = operation.if_exists
|
125
115
|
|
126
116
|
operations.impl.drop_index(
|
@@ -135,9 +125,6 @@ def create_table(
|
|
135
125
|
) -> "Table":
|
136
126
|
kw = {}
|
137
127
|
if operation.if_not_exists is not None:
|
138
|
-
if not sqla_14:
|
139
|
-
raise NotImplementedError("SQLAlchemy 1.4+ required")
|
140
|
-
|
141
128
|
kw["if_not_exists"] = operation.if_not_exists
|
142
129
|
table = operation.to_table(operations.migration_context)
|
143
130
|
operations.impl.create_table(table, **kw)
|
alembic/runtime/environment.py
CHANGED
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
3
3
|
from typing import Any
|
4
4
|
from typing import Callable
|
5
5
|
from typing import Collection
|
6
|
-
from typing import ContextManager
|
7
6
|
from typing import Dict
|
8
7
|
from typing import List
|
9
8
|
from typing import Mapping
|
@@ -18,6 +17,7 @@ from typing import Union
|
|
18
17
|
|
19
18
|
from sqlalchemy.sql.schema import Column
|
20
19
|
from sqlalchemy.sql.schema import FetchedValue
|
20
|
+
from typing_extensions import ContextManager
|
21
21
|
from typing_extensions import Literal
|
22
22
|
|
23
23
|
from .migration import _ProxyTransaction
|
@@ -976,7 +976,7 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
976
976
|
|
977
977
|
def begin_transaction(
|
978
978
|
self,
|
979
|
-
) -> Union[_ProxyTransaction, ContextManager[None]]:
|
979
|
+
) -> Union[_ProxyTransaction, ContextManager[None, Optional[bool]]]:
|
980
980
|
"""Return a context manager that will
|
981
981
|
enclose an operation within a "transaction",
|
982
982
|
as defined by the environment's offline
|
alembic/runtime/migration.py
CHANGED
@@ -11,7 +11,6 @@ from typing import Any
|
|
11
11
|
from typing import Callable
|
12
12
|
from typing import cast
|
13
13
|
from typing import Collection
|
14
|
-
from typing import ContextManager
|
15
14
|
from typing import Dict
|
16
15
|
from typing import Iterable
|
17
16
|
from typing import Iterator
|
@@ -24,15 +23,16 @@ from typing import Union
|
|
24
23
|
|
25
24
|
from sqlalchemy import Column
|
26
25
|
from sqlalchemy import literal_column
|
26
|
+
from sqlalchemy import select
|
27
27
|
from sqlalchemy.engine import Engine
|
28
28
|
from sqlalchemy.engine import url as sqla_url
|
29
29
|
from sqlalchemy.engine.strategies import MockEngineStrategy
|
30
|
+
from typing_extensions import ContextManager
|
30
31
|
|
31
32
|
from .. import ddl
|
32
33
|
from .. import util
|
33
34
|
from ..util import sqla_compat
|
34
35
|
from ..util.compat import EncodedIO
|
35
|
-
from ..util.sqla_compat import _select
|
36
36
|
|
37
37
|
if TYPE_CHECKING:
|
38
38
|
from sqlalchemy.engine import Dialect
|
@@ -368,7 +368,7 @@ class MigrationContext:
|
|
368
368
|
|
369
369
|
def begin_transaction(
|
370
370
|
self, _per_migration: bool = False
|
371
|
-
) -> Union[_ProxyTransaction, ContextManager[None]]:
|
371
|
+
) -> Union[_ProxyTransaction, ContextManager[None, Optional[bool]]]:
|
372
372
|
"""Begin a logical transaction for migration operations.
|
373
373
|
|
374
374
|
This method is used within an ``env.py`` script to demarcate where
|
@@ -534,7 +534,7 @@ class MigrationContext:
|
|
534
534
|
return tuple(
|
535
535
|
row[0]
|
536
536
|
for row in self.connection.execute(
|
537
|
-
|
537
|
+
select(self._version.c.version_num)
|
538
538
|
)
|
539
539
|
)
|
540
540
|
|
alembic/testing/assertions.py
CHANGED
@@ -8,6 +8,7 @@ from typing import Dict
|
|
8
8
|
|
9
9
|
from sqlalchemy import exc as sa_exc
|
10
10
|
from sqlalchemy.engine import default
|
11
|
+
from sqlalchemy.engine import URL
|
11
12
|
from sqlalchemy.testing.assertions import _expect_warnings
|
12
13
|
from sqlalchemy.testing.assertions import eq_ # noqa
|
13
14
|
from sqlalchemy.testing.assertions import is_ # noqa
|
@@ -17,8 +18,6 @@ from sqlalchemy.testing.assertions import is_true # noqa
|
|
17
18
|
from sqlalchemy.testing.assertions import ne_ # noqa
|
18
19
|
from sqlalchemy.util import decorator
|
19
20
|
|
20
|
-
from ..util import sqla_compat
|
21
|
-
|
22
21
|
|
23
22
|
def _assert_proper_exception_context(exception):
|
24
23
|
"""assert that any exception we're catching does not have a __context__
|
@@ -127,7 +126,7 @@ def _get_dialect(name):
|
|
127
126
|
if name is None or name == "default":
|
128
127
|
return default.DefaultDialect()
|
129
128
|
else:
|
130
|
-
d =
|
129
|
+
d = URL.create(name).get_dialect()()
|
131
130
|
|
132
131
|
if name == "postgresql":
|
133
132
|
d.implicit_returning = True
|