alembic 1.12.1__py3-none-any.whl → 1.13.1__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 -3
- alembic/autogenerate/__init__.py +10 -10
- alembic/autogenerate/api.py +8 -5
- alembic/autogenerate/compare.py +134 -199
- alembic/autogenerate/render.py +39 -24
- alembic/autogenerate/rewriter.py +26 -13
- alembic/command.py +7 -2
- alembic/config.py +20 -9
- alembic/context.pyi +12 -6
- alembic/ddl/__init__.py +1 -1
- alembic/ddl/_autogen.py +325 -0
- alembic/ddl/base.py +12 -9
- alembic/ddl/impl.py +110 -13
- alembic/ddl/mssql.py +4 -1
- alembic/ddl/mysql.py +9 -6
- alembic/ddl/oracle.py +4 -1
- alembic/ddl/postgresql.py +147 -73
- alembic/ddl/sqlite.py +8 -6
- alembic/op.pyi +46 -8
- alembic/operations/base.py +70 -14
- alembic/operations/batch.py +7 -8
- alembic/operations/ops.py +53 -31
- alembic/operations/schemaobj.py +5 -4
- alembic/operations/toimpl.py +8 -5
- alembic/runtime/environment.py +17 -7
- alembic/runtime/migration.py +27 -11
- alembic/script/base.py +34 -27
- alembic/script/revision.py +30 -17
- alembic/script/write_hooks.py +3 -0
- alembic/templates/async/alembic.ini.mako +3 -3
- alembic/templates/generic/alembic.ini.mako +3 -3
- alembic/templates/multidb/alembic.ini.mako +3 -3
- alembic/testing/requirements.py +12 -0
- alembic/testing/schemacompare.py +9 -0
- alembic/util/__init__.py +31 -31
- alembic/util/compat.py +25 -9
- alembic/util/langhelpers.py +78 -33
- alembic/util/messaging.py +6 -3
- alembic/util/pyfiles.py +7 -3
- alembic/util/sqla_compat.py +52 -26
- {alembic-1.12.1.dist-info → alembic-1.13.1.dist-info}/METADATA +5 -4
- alembic-1.13.1.dist-info/RECORD +83 -0
- {alembic-1.12.1.dist-info → alembic-1.13.1.dist-info}/WHEEL +1 -1
- alembic-1.12.1.dist-info/RECORD +0 -82
- {alembic-1.12.1.dist-info → alembic-1.13.1.dist-info}/LICENSE +0 -0
- {alembic-1.12.1.dist-info → alembic-1.13.1.dist-info}/entry_points.txt +0 -0
- {alembic-1.12.1.dist-info → alembic-1.13.1.dist-info}/top_level.txt +0 -0
alembic/operations/batch.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
|
2
|
+
# mypy: no-warn-return-any, allow-any-generics
|
3
|
+
|
1
4
|
from __future__ import annotations
|
2
5
|
|
3
6
|
from typing import Any
|
@@ -17,7 +20,7 @@ from sqlalchemy import PrimaryKeyConstraint
|
|
17
20
|
from sqlalchemy import schema as sql_schema
|
18
21
|
from sqlalchemy import Table
|
19
22
|
from sqlalchemy import types as sqltypes
|
20
|
-
from sqlalchemy.
|
23
|
+
from sqlalchemy.sql.schema import SchemaEventTarget
|
21
24
|
from sqlalchemy.util import OrderedDict
|
22
25
|
from sqlalchemy.util import topological
|
23
26
|
|
@@ -374,7 +377,7 @@ class ApplyBatchImpl:
|
|
374
377
|
for idx_existing in self.indexes.values():
|
375
378
|
# this is a lift-and-move from Table.to_metadata
|
376
379
|
|
377
|
-
if idx_existing._column_flag:
|
380
|
+
if idx_existing._column_flag:
|
378
381
|
continue
|
379
382
|
|
380
383
|
idx_copy = Index(
|
@@ -403,9 +406,7 @@ class ApplyBatchImpl:
|
|
403
406
|
def _setup_referent(
|
404
407
|
self, metadata: MetaData, constraint: ForeignKeyConstraint
|
405
408
|
) -> None:
|
406
|
-
spec = constraint.elements[
|
407
|
-
0
|
408
|
-
]._get_colspec() # type:ignore[attr-defined]
|
409
|
+
spec = constraint.elements[0]._get_colspec()
|
409
410
|
parts = spec.split(".")
|
410
411
|
tname = parts[-2]
|
411
412
|
if len(parts) == 3:
|
@@ -546,9 +547,7 @@ class ApplyBatchImpl:
|
|
546
547
|
else:
|
547
548
|
sql_schema.DefaultClause(
|
548
549
|
server_default # type: ignore[arg-type]
|
549
|
-
)._set_parent(
|
550
|
-
existing
|
551
|
-
)
|
550
|
+
)._set_parent(existing)
|
552
551
|
if autoincrement is not None:
|
553
552
|
existing.autoincrement = bool(autoincrement)
|
554
553
|
|
alembic/operations/ops.py
CHANGED
@@ -5,6 +5,7 @@ import re
|
|
5
5
|
from typing import Any
|
6
6
|
from typing import Callable
|
7
7
|
from typing import cast
|
8
|
+
from typing import Dict
|
8
9
|
from typing import FrozenSet
|
9
10
|
from typing import Iterator
|
10
11
|
from typing import List
|
@@ -15,6 +16,7 @@ from typing import Set
|
|
15
16
|
from typing import Tuple
|
16
17
|
from typing import Type
|
17
18
|
from typing import TYPE_CHECKING
|
19
|
+
from typing import TypeVar
|
18
20
|
from typing import Union
|
19
21
|
|
20
22
|
from sqlalchemy.types import NULLTYPE
|
@@ -53,6 +55,9 @@ if TYPE_CHECKING:
|
|
53
55
|
from ..runtime.migration import MigrationContext
|
54
56
|
from ..script.revision import _RevIdType
|
55
57
|
|
58
|
+
_T = TypeVar("_T", bound=Any)
|
59
|
+
_AC = TypeVar("_AC", bound="AddConstraintOp")
|
60
|
+
|
56
61
|
|
57
62
|
class MigrateOperation:
|
58
63
|
"""base class for migration command and organization objects.
|
@@ -70,7 +75,7 @@ class MigrateOperation:
|
|
70
75
|
"""
|
71
76
|
|
72
77
|
@util.memoized_property
|
73
|
-
def info(self):
|
78
|
+
def info(self) -> Dict[Any, Any]:
|
74
79
|
"""A dictionary that may be used to store arbitrary information
|
75
80
|
along with this :class:`.MigrateOperation` object.
|
76
81
|
|
@@ -92,12 +97,14 @@ class AddConstraintOp(MigrateOperation):
|
|
92
97
|
add_constraint_ops = util.Dispatcher()
|
93
98
|
|
94
99
|
@property
|
95
|
-
def constraint_type(self):
|
100
|
+
def constraint_type(self) -> str:
|
96
101
|
raise NotImplementedError()
|
97
102
|
|
98
103
|
@classmethod
|
99
|
-
def register_add_constraint(
|
100
|
-
|
104
|
+
def register_add_constraint(
|
105
|
+
cls, type_: str
|
106
|
+
) -> Callable[[Type[_AC]], Type[_AC]]:
|
107
|
+
def go(klass: Type[_AC]) -> Type[_AC]:
|
101
108
|
cls.add_constraint_ops.dispatch_for(type_)(klass.from_constraint)
|
102
109
|
return klass
|
103
110
|
|
@@ -105,7 +112,7 @@ class AddConstraintOp(MigrateOperation):
|
|
105
112
|
|
106
113
|
@classmethod
|
107
114
|
def from_constraint(cls, constraint: Constraint) -> AddConstraintOp:
|
108
|
-
return cls.add_constraint_ops.dispatch(constraint.__visit_name__)(
|
115
|
+
return cls.add_constraint_ops.dispatch(constraint.__visit_name__)( # type: ignore[no-any-return] # noqa: E501
|
109
116
|
constraint
|
110
117
|
)
|
111
118
|
|
@@ -398,7 +405,7 @@ class CreateUniqueConstraintOp(AddConstraintOp):
|
|
398
405
|
|
399
406
|
uq_constraint = cast("UniqueConstraint", constraint)
|
400
407
|
|
401
|
-
kw:
|
408
|
+
kw: Dict[str, Any] = {}
|
402
409
|
if uq_constraint.deferrable:
|
403
410
|
kw["deferrable"] = uq_constraint.deferrable
|
404
411
|
if uq_constraint.initially:
|
@@ -532,7 +539,7 @@ class CreateForeignKeyOp(AddConstraintOp):
|
|
532
539
|
@classmethod
|
533
540
|
def from_constraint(cls, constraint: Constraint) -> CreateForeignKeyOp:
|
534
541
|
fk_constraint = cast("ForeignKeyConstraint", constraint)
|
535
|
-
kw:
|
542
|
+
kw: Dict[str, Any] = {}
|
536
543
|
if fk_constraint.onupdate:
|
537
544
|
kw["onupdate"] = fk_constraint.onupdate
|
538
545
|
if fk_constraint.ondelete:
|
@@ -897,9 +904,9 @@ class CreateIndexOp(MigrateOperation):
|
|
897
904
|
def from_index(cls, index: Index) -> CreateIndexOp:
|
898
905
|
assert index.table is not None
|
899
906
|
return cls(
|
900
|
-
index.name,
|
907
|
+
index.name,
|
901
908
|
index.table.name,
|
902
|
-
|
909
|
+
index.expressions,
|
903
910
|
schema=index.table.schema,
|
904
911
|
unique=index.unique,
|
905
912
|
**index.kwargs,
|
@@ -1054,6 +1061,7 @@ class DropIndexOp(MigrateOperation):
|
|
1054
1061
|
table_name=index.table.name,
|
1055
1062
|
schema=index.table.schema,
|
1056
1063
|
_reverse=CreateIndexOp.from_index(index),
|
1064
|
+
unique=index.unique,
|
1057
1065
|
**index.kwargs,
|
1058
1066
|
)
|
1059
1067
|
|
@@ -1182,7 +1190,7 @@ class CreateTableOp(MigrateOperation):
|
|
1182
1190
|
|
1183
1191
|
return cls(
|
1184
1192
|
table.name,
|
1185
|
-
list(table.c) + list(table.constraints),
|
1193
|
+
list(table.c) + list(table.constraints),
|
1186
1194
|
schema=table.schema,
|
1187
1195
|
_namespace_metadata=_namespace_metadata,
|
1188
1196
|
# given a Table() object, this Table will contain full Index()
|
@@ -1534,7 +1542,7 @@ class CreateTableCommentOp(AlterTableOp):
|
|
1534
1542
|
)
|
1535
1543
|
return operations.invoke(op)
|
1536
1544
|
|
1537
|
-
def reverse(self):
|
1545
|
+
def reverse(self) -> Union[CreateTableCommentOp, DropTableCommentOp]:
|
1538
1546
|
"""Reverses the COMMENT ON operation against a table."""
|
1539
1547
|
if self.existing_comment is None:
|
1540
1548
|
return DropTableCommentOp(
|
@@ -1550,14 +1558,16 @@ class CreateTableCommentOp(AlterTableOp):
|
|
1550
1558
|
schema=self.schema,
|
1551
1559
|
)
|
1552
1560
|
|
1553
|
-
def to_table(
|
1561
|
+
def to_table(
|
1562
|
+
self, migration_context: Optional[MigrationContext] = None
|
1563
|
+
) -> Table:
|
1554
1564
|
schema_obj = schemaobj.SchemaObjects(migration_context)
|
1555
1565
|
|
1556
1566
|
return schema_obj.table(
|
1557
1567
|
self.table_name, schema=self.schema, comment=self.comment
|
1558
1568
|
)
|
1559
1569
|
|
1560
|
-
def to_diff_tuple(self):
|
1570
|
+
def to_diff_tuple(self) -> Tuple[Any, ...]:
|
1561
1571
|
return ("add_table_comment", self.to_table(), self.existing_comment)
|
1562
1572
|
|
1563
1573
|
|
@@ -1629,18 +1639,20 @@ class DropTableCommentOp(AlterTableOp):
|
|
1629
1639
|
)
|
1630
1640
|
return operations.invoke(op)
|
1631
1641
|
|
1632
|
-
def reverse(self):
|
1642
|
+
def reverse(self) -> CreateTableCommentOp:
|
1633
1643
|
"""Reverses the COMMENT ON operation against a table."""
|
1634
1644
|
return CreateTableCommentOp(
|
1635
1645
|
self.table_name, self.existing_comment, schema=self.schema
|
1636
1646
|
)
|
1637
1647
|
|
1638
|
-
def to_table(
|
1648
|
+
def to_table(
|
1649
|
+
self, migration_context: Optional[MigrationContext] = None
|
1650
|
+
) -> Table:
|
1639
1651
|
schema_obj = schemaobj.SchemaObjects(migration_context)
|
1640
1652
|
|
1641
1653
|
return schema_obj.table(self.table_name, schema=self.schema)
|
1642
1654
|
|
1643
|
-
def to_diff_tuple(self):
|
1655
|
+
def to_diff_tuple(self) -> Tuple[Any, ...]:
|
1644
1656
|
return ("remove_table_comment", self.to_table())
|
1645
1657
|
|
1646
1658
|
|
@@ -1817,8 +1829,10 @@ class AlterColumnOp(AlterTableOp):
|
|
1817
1829
|
comment: Optional[Union[str, Literal[False]]] = False,
|
1818
1830
|
server_default: Any = False,
|
1819
1831
|
new_column_name: Optional[str] = None,
|
1820
|
-
type_: Optional[Union[TypeEngine, Type[TypeEngine]]] = None,
|
1821
|
-
existing_type: Optional[
|
1832
|
+
type_: Optional[Union[TypeEngine[Any], Type[TypeEngine[Any]]]] = None,
|
1833
|
+
existing_type: Optional[
|
1834
|
+
Union[TypeEngine[Any], Type[TypeEngine[Any]]]
|
1835
|
+
] = None,
|
1822
1836
|
existing_server_default: Optional[
|
1823
1837
|
Union[str, bool, Identity, Computed]
|
1824
1838
|
] = False,
|
@@ -1938,8 +1952,10 @@ class AlterColumnOp(AlterTableOp):
|
|
1938
1952
|
comment: Optional[Union[str, Literal[False]]] = False,
|
1939
1953
|
server_default: Any = False,
|
1940
1954
|
new_column_name: Optional[str] = None,
|
1941
|
-
type_: Optional[Union[TypeEngine, Type[TypeEngine]]] = None,
|
1942
|
-
existing_type: Optional[
|
1955
|
+
type_: Optional[Union[TypeEngine[Any], Type[TypeEngine[Any]]]] = None,
|
1956
|
+
existing_type: Optional[
|
1957
|
+
Union[TypeEngine[Any], Type[TypeEngine[Any]]]
|
1958
|
+
] = None,
|
1943
1959
|
existing_server_default: Optional[
|
1944
1960
|
Union[str, bool, Identity, Computed]
|
1945
1961
|
] = False,
|
@@ -2019,11 +2035,11 @@ class AddColumnOp(AlterTableOp):
|
|
2019
2035
|
) -> Tuple[str, Optional[str], str, Column[Any]]:
|
2020
2036
|
return ("add_column", self.schema, self.table_name, self.column)
|
2021
2037
|
|
2022
|
-
def to_column(self) -> Column:
|
2038
|
+
def to_column(self) -> Column[Any]:
|
2023
2039
|
return self.column
|
2024
2040
|
|
2025
2041
|
@classmethod
|
2026
|
-
def from_column(cls, col: Column) -> AddColumnOp:
|
2042
|
+
def from_column(cls, col: Column[Any]) -> AddColumnOp:
|
2027
2043
|
return cls(col.table.name, col, schema=col.table.schema)
|
2028
2044
|
|
2029
2045
|
@classmethod
|
@@ -2214,7 +2230,7 @@ class DropColumnOp(AlterTableOp):
|
|
2214
2230
|
|
2215
2231
|
def to_column(
|
2216
2232
|
self, migration_context: Optional[MigrationContext] = None
|
2217
|
-
) -> Column:
|
2233
|
+
) -> Column[Any]:
|
2218
2234
|
if self._reverse is not None:
|
2219
2235
|
return self._reverse.column
|
2220
2236
|
schema_obj = schemaobj.SchemaObjects(migration_context)
|
@@ -2298,7 +2314,7 @@ class BulkInsertOp(MigrateOperation):
|
|
2298
2314
|
def __init__(
|
2299
2315
|
self,
|
2300
2316
|
table: Union[Table, TableClause],
|
2301
|
-
rows: List[
|
2317
|
+
rows: List[Dict[str, Any]],
|
2302
2318
|
*,
|
2303
2319
|
multiinsert: bool = True,
|
2304
2320
|
) -> None:
|
@@ -2311,7 +2327,7 @@ class BulkInsertOp(MigrateOperation):
|
|
2311
2327
|
cls,
|
2312
2328
|
operations: Operations,
|
2313
2329
|
table: Union[Table, TableClause],
|
2314
|
-
rows: List[
|
2330
|
+
rows: List[Dict[str, Any]],
|
2315
2331
|
*,
|
2316
2332
|
multiinsert: bool = True,
|
2317
2333
|
) -> None:
|
@@ -2607,7 +2623,7 @@ class UpgradeOps(OpContainer):
|
|
2607
2623
|
self.upgrade_token = upgrade_token
|
2608
2624
|
|
2609
2625
|
def reverse_into(self, downgrade_ops: DowngradeOps) -> DowngradeOps:
|
2610
|
-
downgrade_ops.ops[:] = list(
|
2626
|
+
downgrade_ops.ops[:] = list(
|
2611
2627
|
reversed([op.reverse() for op in self.ops])
|
2612
2628
|
)
|
2613
2629
|
return downgrade_ops
|
@@ -2634,7 +2650,7 @@ class DowngradeOps(OpContainer):
|
|
2634
2650
|
super().__init__(ops=ops)
|
2635
2651
|
self.downgrade_token = downgrade_token
|
2636
2652
|
|
2637
|
-
def reverse(self):
|
2653
|
+
def reverse(self) -> UpgradeOps:
|
2638
2654
|
return UpgradeOps(
|
2639
2655
|
ops=list(reversed([op.reverse() for op in self.ops]))
|
2640
2656
|
)
|
@@ -2665,6 +2681,8 @@ class MigrationScript(MigrateOperation):
|
|
2665
2681
|
"""
|
2666
2682
|
|
2667
2683
|
_needs_render: Optional[bool]
|
2684
|
+
_upgrade_ops: List[UpgradeOps]
|
2685
|
+
_downgrade_ops: List[DowngradeOps]
|
2668
2686
|
|
2669
2687
|
def __init__(
|
2670
2688
|
self,
|
@@ -2692,7 +2710,7 @@ class MigrationScript(MigrateOperation):
|
|
2692
2710
|
self.downgrade_ops = downgrade_ops
|
2693
2711
|
|
2694
2712
|
@property
|
2695
|
-
def upgrade_ops(self):
|
2713
|
+
def upgrade_ops(self) -> Optional[UpgradeOps]:
|
2696
2714
|
"""An instance of :class:`.UpgradeOps`.
|
2697
2715
|
|
2698
2716
|
.. seealso::
|
@@ -2711,13 +2729,15 @@ class MigrationScript(MigrateOperation):
|
|
2711
2729
|
return self._upgrade_ops[0]
|
2712
2730
|
|
2713
2731
|
@upgrade_ops.setter
|
2714
|
-
def upgrade_ops(
|
2732
|
+
def upgrade_ops(
|
2733
|
+
self, upgrade_ops: Union[UpgradeOps, List[UpgradeOps]]
|
2734
|
+
) -> None:
|
2715
2735
|
self._upgrade_ops = util.to_list(upgrade_ops)
|
2716
2736
|
for elem in self._upgrade_ops:
|
2717
2737
|
assert isinstance(elem, UpgradeOps)
|
2718
2738
|
|
2719
2739
|
@property
|
2720
|
-
def downgrade_ops(self):
|
2740
|
+
def downgrade_ops(self) -> Optional[DowngradeOps]:
|
2721
2741
|
"""An instance of :class:`.DowngradeOps`.
|
2722
2742
|
|
2723
2743
|
.. seealso::
|
@@ -2736,7 +2756,9 @@ class MigrationScript(MigrateOperation):
|
|
2736
2756
|
return self._downgrade_ops[0]
|
2737
2757
|
|
2738
2758
|
@downgrade_ops.setter
|
2739
|
-
def downgrade_ops(
|
2759
|
+
def downgrade_ops(
|
2760
|
+
self, downgrade_ops: Union[DowngradeOps, List[DowngradeOps]]
|
2761
|
+
) -> None:
|
2740
2762
|
self._downgrade_ops = util.to_list(downgrade_ops)
|
2741
2763
|
for elem in self._downgrade_ops:
|
2742
2764
|
assert isinstance(elem, DowngradeOps)
|
alembic/operations/schemaobj.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
|
2
|
+
# mypy: no-warn-return-any, allow-any-generics
|
3
|
+
|
1
4
|
from __future__ import annotations
|
2
5
|
|
3
6
|
from typing import Any
|
@@ -274,10 +277,8 @@ class SchemaObjects:
|
|
274
277
|
ForeignKey.
|
275
278
|
|
276
279
|
"""
|
277
|
-
if isinstance(fk._colspec, str):
|
278
|
-
table_key, cname = fk._colspec.rsplit(
|
279
|
-
".", 1
|
280
|
-
)
|
280
|
+
if isinstance(fk._colspec, str):
|
281
|
+
table_key, cname = fk._colspec.rsplit(".", 1)
|
281
282
|
sname, tname = self._parse_table_key(table_key)
|
282
283
|
if table_key not in metadata.tables:
|
283
284
|
rel_t = sa_schema.Table(tname, metadata, schema=sname)
|
alembic/operations/toimpl.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
|
2
|
+
# mypy: no-warn-return-any, allow-any-generics
|
3
|
+
|
1
4
|
from typing import TYPE_CHECKING
|
2
5
|
|
3
6
|
from sqlalchemy import schema as sa_schema
|
@@ -5,7 +8,7 @@ from sqlalchemy import schema as sa_schema
|
|
5
8
|
from . import ops
|
6
9
|
from .base import Operations
|
7
10
|
from ..util.sqla_compat import _copy
|
8
|
-
from ..util.sqla_compat import
|
11
|
+
from ..util.sqla_compat import sqla_14
|
9
12
|
|
10
13
|
if TYPE_CHECKING:
|
11
14
|
from sqlalchemy.sql.schema import Table
|
@@ -98,8 +101,8 @@ def create_index(
|
|
98
101
|
idx = operation.to_index(operations.migration_context)
|
99
102
|
kw = {}
|
100
103
|
if operation.if_not_exists is not None:
|
101
|
-
if not
|
102
|
-
raise NotImplementedError("SQLAlchemy
|
104
|
+
if not sqla_14:
|
105
|
+
raise NotImplementedError("SQLAlchemy 1.4+ required")
|
103
106
|
|
104
107
|
kw["if_not_exists"] = operation.if_not_exists
|
105
108
|
operations.impl.create_index(idx, **kw)
|
@@ -109,8 +112,8 @@ def create_index(
|
|
109
112
|
def drop_index(operations: "Operations", operation: "ops.DropIndexOp") -> None:
|
110
113
|
kw = {}
|
111
114
|
if operation.if_exists is not None:
|
112
|
-
if not
|
113
|
-
raise NotImplementedError("SQLAlchemy
|
115
|
+
if not sqla_14:
|
116
|
+
raise NotImplementedError("SQLAlchemy 1.4+ required")
|
114
117
|
|
115
118
|
kw["if_exists"] = operation.if_exists
|
116
119
|
|
alembic/runtime/environment.py
CHANGED
@@ -10,6 +10,7 @@ from typing import Mapping
|
|
10
10
|
from typing import MutableMapping
|
11
11
|
from typing import Optional
|
12
12
|
from typing import overload
|
13
|
+
from typing import Sequence
|
13
14
|
from typing import TextIO
|
14
15
|
from typing import Tuple
|
15
16
|
from typing import TYPE_CHECKING
|
@@ -227,9 +228,9 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
227
228
|
has been configured.
|
228
229
|
|
229
230
|
"""
|
230
|
-
return self.context_opts.get("as_sql", False)
|
231
|
+
return self.context_opts.get("as_sql", False) # type: ignore[no-any-return] # noqa: E501
|
231
232
|
|
232
|
-
def is_transactional_ddl(self):
|
233
|
+
def is_transactional_ddl(self) -> bool:
|
233
234
|
"""Return True if the context is configured to expect a
|
234
235
|
transactional DDL capable backend.
|
235
236
|
|
@@ -338,7 +339,7 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
338
339
|
line.
|
339
340
|
|
340
341
|
"""
|
341
|
-
return self.context_opts.get("tag", None)
|
342
|
+
return self.context_opts.get("tag", None) # type: ignore[no-any-return] # noqa: E501
|
342
343
|
|
343
344
|
@overload
|
344
345
|
def get_x_argument(self, as_dictionary: Literal[False]) -> List[str]:
|
@@ -366,7 +367,11 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
366
367
|
The return value is a list, returned directly from the ``argparse``
|
367
368
|
structure. If ``as_dictionary=True`` is passed, the ``x`` arguments
|
368
369
|
are parsed using ``key=value`` format into a dictionary that is
|
369
|
-
then returned.
|
370
|
+
then returned. If there is no ``=`` in the argument, value is an empty
|
371
|
+
string.
|
372
|
+
|
373
|
+
.. versionchanged:: 1.13.1 Support ``as_dictionary=True`` when
|
374
|
+
arguments are passed without the ``=`` symbol.
|
370
375
|
|
371
376
|
For example, to support passing a database URL on the command line,
|
372
377
|
the standard ``env.py`` script can be modified like this::
|
@@ -400,7 +405,12 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
400
405
|
else:
|
401
406
|
value = []
|
402
407
|
if as_dictionary:
|
403
|
-
|
408
|
+
dict_value = {}
|
409
|
+
for arg in value:
|
410
|
+
x_key, _, x_value = arg.partition("=")
|
411
|
+
dict_value[x_key] = x_value
|
412
|
+
value = dict_value
|
413
|
+
|
404
414
|
return value
|
405
415
|
|
406
416
|
def configure(
|
@@ -416,7 +426,7 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
416
426
|
tag: Optional[str] = None,
|
417
427
|
template_args: Optional[Dict[str, Any]] = None,
|
418
428
|
render_as_batch: bool = False,
|
419
|
-
target_metadata:
|
429
|
+
target_metadata: Union[MetaData, Sequence[MetaData], None] = None,
|
420
430
|
include_name: Optional[IncludeNameFn] = None,
|
421
431
|
include_object: Optional[IncludeObjectFn] = None,
|
422
432
|
include_schemas: bool = False,
|
@@ -940,7 +950,7 @@ class EnvironmentContext(util.ModuleClsProxy):
|
|
940
950
|
def execute(
|
941
951
|
self,
|
942
952
|
sql: Union[Executable, str],
|
943
|
-
execution_options: Optional[
|
953
|
+
execution_options: Optional[Dict[str, Any]] = None,
|
944
954
|
) -> None:
|
945
955
|
"""Execute the given SQL using the current change context.
|
946
956
|
|
alembic/runtime/migration.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
|
2
|
+
# mypy: no-warn-return-any, allow-any-generics
|
3
|
+
|
1
4
|
from __future__ import annotations
|
2
5
|
|
3
6
|
from contextlib import contextmanager
|
@@ -521,7 +524,7 @@ class MigrationContext:
|
|
521
524
|
start_from_rev = None
|
522
525
|
elif start_from_rev is not None and self.script:
|
523
526
|
start_from_rev = [
|
524
|
-
|
527
|
+
self.script.get_revision(sfr).revision
|
525
528
|
for sfr in util.to_list(start_from_rev)
|
526
529
|
if sfr not in (None, "base")
|
527
530
|
]
|
@@ -652,7 +655,7 @@ class MigrationContext:
|
|
652
655
|
def execute(
|
653
656
|
self,
|
654
657
|
sql: Union[Executable, str],
|
655
|
-
execution_options: Optional[
|
658
|
+
execution_options: Optional[Dict[str, Any]] = None,
|
656
659
|
) -> None:
|
657
660
|
"""Execute a SQL construct or string statement.
|
658
661
|
|
@@ -1000,6 +1003,12 @@ class MigrationStep:
|
|
1000
1003
|
is_upgrade: bool
|
1001
1004
|
migration_fn: Any
|
1002
1005
|
|
1006
|
+
if TYPE_CHECKING:
|
1007
|
+
|
1008
|
+
@property
|
1009
|
+
def doc(self) -> Optional[str]:
|
1010
|
+
...
|
1011
|
+
|
1003
1012
|
@property
|
1004
1013
|
def name(self) -> str:
|
1005
1014
|
return self.migration_fn.__name__
|
@@ -1048,13 +1057,9 @@ class RevisionStep(MigrationStep):
|
|
1048
1057
|
self.revision = revision
|
1049
1058
|
self.is_upgrade = is_upgrade
|
1050
1059
|
if is_upgrade:
|
1051
|
-
self.migration_fn =
|
1052
|
-
revision.module.upgrade # type:ignore[attr-defined]
|
1053
|
-
)
|
1060
|
+
self.migration_fn = revision.module.upgrade
|
1054
1061
|
else:
|
1055
|
-
self.migration_fn =
|
1056
|
-
revision.module.downgrade # type:ignore[attr-defined]
|
1057
|
-
)
|
1062
|
+
self.migration_fn = revision.module.downgrade
|
1058
1063
|
|
1059
1064
|
def __repr__(self):
|
1060
1065
|
return "RevisionStep(%r, is_upgrade=%r)" % (
|
@@ -1070,7 +1075,7 @@ class RevisionStep(MigrationStep):
|
|
1070
1075
|
)
|
1071
1076
|
|
1072
1077
|
@property
|
1073
|
-
def doc(self) -> str:
|
1078
|
+
def doc(self) -> Optional[str]:
|
1074
1079
|
return self.revision.doc
|
1075
1080
|
|
1076
1081
|
@property
|
@@ -1168,7 +1173,18 @@ class RevisionStep(MigrationStep):
|
|
1168
1173
|
}
|
1169
1174
|
return tuple(set(self.to_revisions).difference(ancestors))
|
1170
1175
|
else:
|
1171
|
-
return
|
1176
|
+
# for each revision we plan to return, compute its ancestors
|
1177
|
+
# (excluding self), and remove those from the final output since
|
1178
|
+
# they are already accounted for.
|
1179
|
+
ancestors = {
|
1180
|
+
r.revision
|
1181
|
+
for to_revision in self.to_revisions
|
1182
|
+
for r in self.revision_map._get_ancestor_nodes(
|
1183
|
+
self.revision_map.get_revisions(to_revision), check=False
|
1184
|
+
)
|
1185
|
+
if r.revision != to_revision
|
1186
|
+
}
|
1187
|
+
return tuple(set(self.to_revisions).difference(ancestors))
|
1172
1188
|
|
1173
1189
|
def unmerge_branch_idents(
|
1174
1190
|
self, heads: Set[str]
|
@@ -1283,7 +1299,7 @@ class StampStep(MigrationStep):
|
|
1283
1299
|
def __eq__(self, other):
|
1284
1300
|
return (
|
1285
1301
|
isinstance(other, StampStep)
|
1286
|
-
and other.from_revisions == self.
|
1302
|
+
and other.from_revisions == self.from_revisions
|
1287
1303
|
and other.to_revisions == self.to_revisions
|
1288
1304
|
and other.branch_move == self.branch_move
|
1289
1305
|
and self.is_upgrade == other.is_upgrade
|