alembic 1.15.2__py3-none-any.whl → 1.16.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/compare.py +60 -7
- alembic/autogenerate/render.py +25 -4
- alembic/command.py +112 -37
- alembic/config.py +574 -222
- alembic/ddl/base.py +31 -7
- alembic/ddl/impl.py +23 -5
- alembic/ddl/mssql.py +3 -1
- alembic/ddl/mysql.py +8 -4
- alembic/ddl/postgresql.py +6 -2
- alembic/ddl/sqlite.py +1 -1
- alembic/op.pyi +24 -5
- alembic/operations/base.py +18 -3
- alembic/operations/ops.py +49 -8
- alembic/operations/toimpl.py +20 -3
- alembic/script/base.py +123 -136
- alembic/script/revision.py +1 -1
- alembic/script/write_hooks.py +20 -21
- alembic/templates/async/alembic.ini.mako +40 -16
- alembic/templates/generic/alembic.ini.mako +39 -17
- alembic/templates/multidb/alembic.ini.mako +42 -17
- alembic/templates/pyproject/README +1 -0
- alembic/templates/pyproject/alembic.ini.mako +44 -0
- alembic/templates/pyproject/env.py +78 -0
- alembic/templates/pyproject/pyproject.toml.mako +76 -0
- alembic/templates/pyproject/script.py.mako +28 -0
- alembic/testing/__init__.py +2 -0
- alembic/testing/assertions.py +4 -0
- alembic/testing/env.py +56 -1
- alembic/testing/fixtures.py +28 -1
- alembic/testing/suite/_autogen_fixtures.py +113 -0
- alembic/util/__init__.py +1 -0
- alembic/util/compat.py +56 -0
- alembic/util/messaging.py +4 -0
- alembic/util/pyfiles.py +56 -19
- {alembic-1.15.2.dist-info → alembic-1.16.0.dist-info}/METADATA +3 -3
- {alembic-1.15.2.dist-info → alembic-1.16.0.dist-info}/RECORD +41 -36
- {alembic-1.15.2.dist-info → alembic-1.16.0.dist-info}/WHEEL +1 -1
- {alembic-1.15.2.dist-info → alembic-1.16.0.dist-info}/entry_points.txt +0 -0
- {alembic-1.15.2.dist-info → alembic-1.16.0.dist-info}/licenses/LICENSE +0 -0
- {alembic-1.15.2.dist-info → alembic-1.16.0.dist-info}/top_level.txt +0 -0
alembic/ddl/base.py
CHANGED
@@ -154,17 +154,24 @@ class AddColumn(AlterTable):
|
|
154
154
|
name: str,
|
155
155
|
column: Column[Any],
|
156
156
|
schema: Optional[Union[quoted_name, str]] = None,
|
157
|
+
if_not_exists: Optional[bool] = None,
|
157
158
|
) -> None:
|
158
159
|
super().__init__(name, schema=schema)
|
159
160
|
self.column = column
|
161
|
+
self.if_not_exists = if_not_exists
|
160
162
|
|
161
163
|
|
162
164
|
class DropColumn(AlterTable):
|
163
165
|
def __init__(
|
164
|
-
self,
|
166
|
+
self,
|
167
|
+
name: str,
|
168
|
+
column: Column[Any],
|
169
|
+
schema: Optional[str] = None,
|
170
|
+
if_exists: Optional[bool] = None,
|
165
171
|
) -> None:
|
166
172
|
super().__init__(name, schema=schema)
|
167
173
|
self.column = column
|
174
|
+
self.if_exists = if_exists
|
168
175
|
|
169
176
|
|
170
177
|
class ColumnComment(AlterColumn):
|
@@ -189,7 +196,9 @@ def visit_rename_table(
|
|
189
196
|
def visit_add_column(element: AddColumn, compiler: DDLCompiler, **kw) -> str:
|
190
197
|
return "%s %s" % (
|
191
198
|
alter_table(compiler, element.table_name, element.schema),
|
192
|
-
add_column(
|
199
|
+
add_column(
|
200
|
+
compiler, element.column, if_not_exists=element.if_not_exists, **kw
|
201
|
+
),
|
193
202
|
)
|
194
203
|
|
195
204
|
|
@@ -197,7 +206,9 @@ def visit_add_column(element: AddColumn, compiler: DDLCompiler, **kw) -> str:
|
|
197
206
|
def visit_drop_column(element: DropColumn, compiler: DDLCompiler, **kw) -> str:
|
198
207
|
return "%s %s" % (
|
199
208
|
alter_table(compiler, element.table_name, element.schema),
|
200
|
-
drop_column(
|
209
|
+
drop_column(
|
210
|
+
compiler, element.column.name, if_exists=element.if_exists, **kw
|
211
|
+
),
|
201
212
|
)
|
202
213
|
|
203
214
|
|
@@ -320,16 +331,29 @@ def alter_table(
|
|
320
331
|
return "ALTER TABLE %s" % format_table_name(compiler, name, schema)
|
321
332
|
|
322
333
|
|
323
|
-
def drop_column(
|
324
|
-
|
334
|
+
def drop_column(
|
335
|
+
compiler: DDLCompiler, name: str, if_exists: Optional[bool] = None, **kw
|
336
|
+
) -> str:
|
337
|
+
return "DROP COLUMN %s%s" % (
|
338
|
+
"IF EXISTS " if if_exists else "",
|
339
|
+
format_column_name(compiler, name),
|
340
|
+
)
|
325
341
|
|
326
342
|
|
327
343
|
def alter_column(compiler: DDLCompiler, name: str) -> str:
|
328
344
|
return "ALTER COLUMN %s" % format_column_name(compiler, name)
|
329
345
|
|
330
346
|
|
331
|
-
def add_column(
|
332
|
-
|
347
|
+
def add_column(
|
348
|
+
compiler: DDLCompiler,
|
349
|
+
column: Column[Any],
|
350
|
+
if_not_exists: Optional[bool] = None,
|
351
|
+
**kw,
|
352
|
+
) -> str:
|
353
|
+
text = "ADD COLUMN %s%s" % (
|
354
|
+
"IF NOT EXISTS " if if_not_exists else "",
|
355
|
+
compiler.get_column_specification(column, **kw),
|
356
|
+
)
|
333
357
|
|
334
358
|
const = " ".join(
|
335
359
|
compiler.process(constraint) for constraint in column.constraints
|
alembic/ddl/impl.py
CHANGED
@@ -256,8 +256,11 @@ class DefaultImpl(metaclass=ImplMeta):
|
|
256
256
|
self,
|
257
257
|
table_name: str,
|
258
258
|
column_name: str,
|
259
|
+
*,
|
259
260
|
nullable: Optional[bool] = None,
|
260
|
-
server_default:
|
261
|
+
server_default: Optional[
|
262
|
+
Union[_ServerDefault, Literal[False]]
|
263
|
+
] = False,
|
261
264
|
name: Optional[str] = None,
|
262
265
|
type_: Optional[TypeEngine] = None,
|
263
266
|
schema: Optional[str] = None,
|
@@ -368,25 +371,40 @@ class DefaultImpl(metaclass=ImplMeta):
|
|
368
371
|
self,
|
369
372
|
table_name: str,
|
370
373
|
column: Column[Any],
|
374
|
+
*,
|
371
375
|
schema: Optional[Union[str, quoted_name]] = None,
|
376
|
+
if_not_exists: Optional[bool] = None,
|
372
377
|
) -> None:
|
373
|
-
self._exec(
|
378
|
+
self._exec(
|
379
|
+
base.AddColumn(
|
380
|
+
table_name,
|
381
|
+
column,
|
382
|
+
schema=schema,
|
383
|
+
if_not_exists=if_not_exists,
|
384
|
+
)
|
385
|
+
)
|
374
386
|
|
375
387
|
def drop_column(
|
376
388
|
self,
|
377
389
|
table_name: str,
|
378
390
|
column: Column[Any],
|
391
|
+
*,
|
379
392
|
schema: Optional[str] = None,
|
393
|
+
if_exists: Optional[bool] = None,
|
380
394
|
**kw,
|
381
395
|
) -> None:
|
382
|
-
self._exec(
|
396
|
+
self._exec(
|
397
|
+
base.DropColumn(
|
398
|
+
table_name, column, schema=schema, if_exists=if_exists
|
399
|
+
)
|
400
|
+
)
|
383
401
|
|
384
402
|
def add_constraint(self, const: Any) -> None:
|
385
403
|
if const._create_rule is None or const._create_rule(self):
|
386
404
|
self._exec(schema.AddConstraint(const))
|
387
405
|
|
388
|
-
def drop_constraint(self, const: Constraint) -> None:
|
389
|
-
self._exec(schema.DropConstraint(const))
|
406
|
+
def drop_constraint(self, const: Constraint, **kw: Any) -> None:
|
407
|
+
self._exec(schema.DropConstraint(const, **kw))
|
390
408
|
|
391
409
|
def rename_table(
|
392
410
|
self,
|
alembic/ddl/mssql.py
CHANGED
@@ -83,10 +83,11 @@ class MSSQLImpl(DefaultImpl):
|
|
83
83
|
if self.as_sql and self.batch_separator:
|
84
84
|
self.static_output(self.batch_separator)
|
85
85
|
|
86
|
-
def alter_column(
|
86
|
+
def alter_column(
|
87
87
|
self,
|
88
88
|
table_name: str,
|
89
89
|
column_name: str,
|
90
|
+
*,
|
90
91
|
nullable: Optional[bool] = None,
|
91
92
|
server_default: Optional[
|
92
93
|
Union[_ServerDefault, Literal[False]]
|
@@ -202,6 +203,7 @@ class MSSQLImpl(DefaultImpl):
|
|
202
203
|
self,
|
203
204
|
table_name: str,
|
204
205
|
column: Column[Any],
|
206
|
+
*,
|
205
207
|
schema: Optional[str] = None,
|
206
208
|
**kw,
|
207
209
|
) -> None:
|
alembic/ddl/mysql.py
CHANGED
@@ -47,12 +47,15 @@ class MySQLImpl(DefaultImpl):
|
|
47
47
|
)
|
48
48
|
type_arg_extract = [r"character set ([\w\-_]+)", r"collate ([\w\-_]+)"]
|
49
49
|
|
50
|
-
def alter_column(
|
50
|
+
def alter_column(
|
51
51
|
self,
|
52
52
|
table_name: str,
|
53
53
|
column_name: str,
|
54
|
+
*,
|
54
55
|
nullable: Optional[bool] = None,
|
55
|
-
server_default:
|
56
|
+
server_default: Optional[
|
57
|
+
Union[_ServerDefault, Literal[False]]
|
58
|
+
] = False,
|
56
59
|
name: Optional[str] = None,
|
57
60
|
type_: Optional[TypeEngine] = None,
|
58
61
|
schema: Optional[str] = None,
|
@@ -165,6 +168,7 @@ class MySQLImpl(DefaultImpl):
|
|
165
168
|
def drop_constraint(
|
166
169
|
self,
|
167
170
|
const: Constraint,
|
171
|
+
**kw: Any,
|
168
172
|
) -> None:
|
169
173
|
if isinstance(const, schema.CheckConstraint) and _is_type_bound(const):
|
170
174
|
return
|
@@ -174,7 +178,7 @@ class MySQLImpl(DefaultImpl):
|
|
174
178
|
def _is_mysql_allowed_functional_default(
|
175
179
|
self,
|
176
180
|
type_: Optional[TypeEngine],
|
177
|
-
server_default: Union[_ServerDefault, Literal[False]],
|
181
|
+
server_default: Optional[Union[_ServerDefault, Literal[False]]],
|
178
182
|
) -> bool:
|
179
183
|
return (
|
180
184
|
type_ is not None
|
@@ -325,7 +329,7 @@ class MySQLAlterDefault(AlterColumn):
|
|
325
329
|
self,
|
326
330
|
name: str,
|
327
331
|
column_name: str,
|
328
|
-
default: _ServerDefault,
|
332
|
+
default: Optional[_ServerDefault],
|
329
333
|
schema: Optional[str] = None,
|
330
334
|
) -> None:
|
331
335
|
super(AlterColumn, self).__init__(name, schema=schema)
|
alembic/ddl/postgresql.py
CHANGED
@@ -52,6 +52,7 @@ from ..operations.base import Operations
|
|
52
52
|
from ..util import sqla_compat
|
53
53
|
from ..util.sqla_compat import compiles
|
54
54
|
|
55
|
+
|
55
56
|
if TYPE_CHECKING:
|
56
57
|
from typing import Literal
|
57
58
|
|
@@ -148,12 +149,15 @@ class PostgresqlImpl(DefaultImpl):
|
|
148
149
|
select(literal_column(conn_col_default) == metadata_default)
|
149
150
|
)
|
150
151
|
|
151
|
-
def alter_column(
|
152
|
+
def alter_column(
|
152
153
|
self,
|
153
154
|
table_name: str,
|
154
155
|
column_name: str,
|
156
|
+
*,
|
155
157
|
nullable: Optional[bool] = None,
|
156
|
-
server_default:
|
158
|
+
server_default: Optional[
|
159
|
+
Union[_ServerDefault, Literal[False]]
|
160
|
+
] = False,
|
157
161
|
name: Optional[str] = None,
|
158
162
|
type_: Optional[TypeEngine] = None,
|
159
163
|
schema: Optional[str] = None,
|
alembic/ddl/sqlite.py
CHANGED
@@ -91,7 +91,7 @@ class SQLiteImpl(DefaultImpl):
|
|
91
91
|
"SQLite migrations using a copy-and-move strategy."
|
92
92
|
)
|
93
93
|
|
94
|
-
def drop_constraint(self, const: Constraint):
|
94
|
+
def drop_constraint(self, const: Constraint, **kw: Any):
|
95
95
|
if const._create_rule is None:
|
96
96
|
raise NotImplementedError(
|
97
97
|
"No support for ALTER of constraints in SQLite dialect. "
|
alembic/op.pyi
CHANGED
@@ -60,7 +60,11 @@ _C = TypeVar("_C", bound=Callable[..., Any])
|
|
60
60
|
### end imports ###
|
61
61
|
|
62
62
|
def add_column(
|
63
|
-
table_name: str,
|
63
|
+
table_name: str,
|
64
|
+
column: Column[Any],
|
65
|
+
*,
|
66
|
+
schema: Optional[str] = None,
|
67
|
+
if_not_exists: Optional[bool] = None,
|
64
68
|
) -> None:
|
65
69
|
"""Issue an "add column" instruction using the current
|
66
70
|
migration context.
|
@@ -137,6 +141,10 @@ def add_column(
|
|
137
141
|
quoting of the schema outside of the default behavior, use
|
138
142
|
the SQLAlchemy construct
|
139
143
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
144
|
+
:param if_not_exists: If True, adds IF NOT EXISTS operator
|
145
|
+
when creating the new column for compatible dialects
|
146
|
+
|
147
|
+
.. versionadded:: 1.16.0
|
140
148
|
|
141
149
|
"""
|
142
150
|
|
@@ -146,7 +154,9 @@ def alter_column(
|
|
146
154
|
*,
|
147
155
|
nullable: Optional[bool] = None,
|
148
156
|
comment: Union[str, Literal[False], None] = False,
|
149
|
-
server_default: Union[
|
157
|
+
server_default: Union[
|
158
|
+
str, bool, Identity, Computed, TextClause, None
|
159
|
+
] = False,
|
150
160
|
new_column_name: Optional[str] = None,
|
151
161
|
type_: Union[TypeEngine[Any], Type[TypeEngine[Any]], None] = None,
|
152
162
|
existing_type: Union[TypeEngine[Any], Type[TypeEngine[Any]], None] = None,
|
@@ -925,6 +935,11 @@ def drop_column(
|
|
925
935
|
quoting of the schema outside of the default behavior, use
|
926
936
|
the SQLAlchemy construct
|
927
937
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
938
|
+
:param if_exists: If True, adds IF EXISTS operator when
|
939
|
+
dropping the new column for compatible dialects
|
940
|
+
|
941
|
+
.. versionadded:: 1.16.0
|
942
|
+
|
928
943
|
:param mssql_drop_check: Optional boolean. When ``True``, on
|
929
944
|
Microsoft SQL Server only, first
|
930
945
|
drop the CHECK constraint on the column using a
|
@@ -946,7 +961,6 @@ def drop_column(
|
|
946
961
|
then exec's a separate DROP CONSTRAINT for that default. Only
|
947
962
|
works if the column has exactly one FK constraint which refers to
|
948
963
|
it, at the moment.
|
949
|
-
|
950
964
|
"""
|
951
965
|
|
952
966
|
def drop_constraint(
|
@@ -955,6 +969,7 @@ def drop_constraint(
|
|
955
969
|
type_: Optional[str] = None,
|
956
970
|
*,
|
957
971
|
schema: Optional[str] = None,
|
972
|
+
if_exists: Optional[bool] = None,
|
958
973
|
) -> None:
|
959
974
|
r"""Drop a constraint of the given name, typically via DROP CONSTRAINT.
|
960
975
|
|
@@ -966,6 +981,10 @@ def drop_constraint(
|
|
966
981
|
quoting of the schema outside of the default behavior, use
|
967
982
|
the SQLAlchemy construct
|
968
983
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
984
|
+
:param if_exists: If True, adds IF EXISTS operator when
|
985
|
+
dropping the constraint
|
986
|
+
|
987
|
+
.. versionadded:: 1.16.0
|
969
988
|
|
970
989
|
"""
|
971
990
|
|
@@ -1165,7 +1184,7 @@ def f(name: str) -> conv:
|
|
1165
1184
|
names will be converted along conventions. If the ``target_metadata``
|
1166
1185
|
contains the naming convention
|
1167
1186
|
``{"ck": "ck_bool_%(table_name)s_%(constraint_name)s"}``, then the
|
1168
|
-
output of the following
|
1187
|
+
output of the following::
|
1169
1188
|
|
1170
1189
|
op.add_column("t", "x", Boolean(name="x"))
|
1171
1190
|
|
@@ -1269,7 +1288,7 @@ def invoke(
|
|
1269
1288
|
BulkInsertOp,
|
1270
1289
|
DropTableOp,
|
1271
1290
|
ExecuteSQLOp,
|
1272
|
-
]
|
1291
|
+
],
|
1273
1292
|
) -> None: ...
|
1274
1293
|
@overload
|
1275
1294
|
def invoke(operation: MigrateOperation) -> Any:
|
alembic/operations/base.py
CHANGED
@@ -464,7 +464,7 @@ class AbstractOperations(util.ModuleClsProxy):
|
|
464
464
|
names will be converted along conventions. If the ``target_metadata``
|
465
465
|
contains the naming convention
|
466
466
|
``{"ck": "ck_bool_%(table_name)s_%(constraint_name)s"}``, then the
|
467
|
-
output of the following
|
467
|
+
output of the following::
|
468
468
|
|
469
469
|
op.add_column("t", "x", Boolean(name="x"))
|
470
470
|
|
@@ -618,6 +618,7 @@ class Operations(AbstractOperations):
|
|
618
618
|
column: Column[Any],
|
619
619
|
*,
|
620
620
|
schema: Optional[str] = None,
|
621
|
+
if_not_exists: Optional[bool] = None,
|
621
622
|
) -> None:
|
622
623
|
"""Issue an "add column" instruction using the current
|
623
624
|
migration context.
|
@@ -694,6 +695,10 @@ class Operations(AbstractOperations):
|
|
694
695
|
quoting of the schema outside of the default behavior, use
|
695
696
|
the SQLAlchemy construct
|
696
697
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
698
|
+
:param if_not_exists: If True, adds IF NOT EXISTS operator
|
699
|
+
when creating the new column for compatible dialects
|
700
|
+
|
701
|
+
.. versionadded:: 1.16.0
|
697
702
|
|
698
703
|
""" # noqa: E501
|
699
704
|
...
|
@@ -706,7 +711,7 @@ class Operations(AbstractOperations):
|
|
706
711
|
nullable: Optional[bool] = None,
|
707
712
|
comment: Union[str, Literal[False], None] = False,
|
708
713
|
server_default: Union[
|
709
|
-
str, bool, Identity, Computed, TextClause
|
714
|
+
str, bool, Identity, Computed, TextClause, None
|
710
715
|
] = False,
|
711
716
|
new_column_name: Optional[str] = None,
|
712
717
|
type_: Union[TypeEngine[Any], Type[TypeEngine[Any]], None] = None,
|
@@ -1361,6 +1366,11 @@ class Operations(AbstractOperations):
|
|
1361
1366
|
quoting of the schema outside of the default behavior, use
|
1362
1367
|
the SQLAlchemy construct
|
1363
1368
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
1369
|
+
:param if_exists: If True, adds IF EXISTS operator when
|
1370
|
+
dropping the new column for compatible dialects
|
1371
|
+
|
1372
|
+
.. versionadded:: 1.16.0
|
1373
|
+
|
1364
1374
|
:param mssql_drop_check: Optional boolean. When ``True``, on
|
1365
1375
|
Microsoft SQL Server only, first
|
1366
1376
|
drop the CHECK constraint on the column using a
|
@@ -1382,7 +1392,6 @@ class Operations(AbstractOperations):
|
|
1382
1392
|
then exec's a separate DROP CONSTRAINT for that default. Only
|
1383
1393
|
works if the column has exactly one FK constraint which refers to
|
1384
1394
|
it, at the moment.
|
1385
|
-
|
1386
1395
|
""" # noqa: E501
|
1387
1396
|
...
|
1388
1397
|
|
@@ -1393,6 +1402,7 @@ class Operations(AbstractOperations):
|
|
1393
1402
|
type_: Optional[str] = None,
|
1394
1403
|
*,
|
1395
1404
|
schema: Optional[str] = None,
|
1405
|
+
if_exists: Optional[bool] = None,
|
1396
1406
|
) -> None:
|
1397
1407
|
r"""Drop a constraint of the given name, typically via DROP CONSTRAINT.
|
1398
1408
|
|
@@ -1404,6 +1414,10 @@ class Operations(AbstractOperations):
|
|
1404
1414
|
quoting of the schema outside of the default behavior, use
|
1405
1415
|
the SQLAlchemy construct
|
1406
1416
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
1417
|
+
:param if_exists: If True, adds IF EXISTS operator when
|
1418
|
+
dropping the constraint
|
1419
|
+
|
1420
|
+
.. versionadded:: 1.16.0
|
1407
1421
|
|
1408
1422
|
""" # noqa: E501
|
1409
1423
|
...
|
@@ -1646,6 +1660,7 @@ class BatchOperations(AbstractOperations):
|
|
1646
1660
|
*,
|
1647
1661
|
insert_before: Optional[str] = None,
|
1648
1662
|
insert_after: Optional[str] = None,
|
1663
|
+
if_not_exists: Optional[bool] = None,
|
1649
1664
|
) -> None:
|
1650
1665
|
"""Issue an "add column" instruction using the current
|
1651
1666
|
batch migration context.
|
alembic/operations/ops.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from abc import abstractmethod
|
4
|
+
import os
|
5
|
+
import pathlib
|
4
6
|
import re
|
5
7
|
from typing import Any
|
6
8
|
from typing import Callable
|
@@ -140,12 +142,14 @@ class DropConstraintOp(MigrateOperation):
|
|
140
142
|
type_: Optional[str] = None,
|
141
143
|
*,
|
142
144
|
schema: Optional[str] = None,
|
145
|
+
if_exists: Optional[bool] = None,
|
143
146
|
_reverse: Optional[AddConstraintOp] = None,
|
144
147
|
) -> None:
|
145
148
|
self.constraint_name = constraint_name
|
146
149
|
self.table_name = table_name
|
147
150
|
self.constraint_type = type_
|
148
151
|
self.schema = schema
|
152
|
+
self.if_exists = if_exists
|
149
153
|
self._reverse = _reverse
|
150
154
|
|
151
155
|
def reverse(self) -> AddConstraintOp:
|
@@ -203,6 +207,7 @@ class DropConstraintOp(MigrateOperation):
|
|
203
207
|
type_: Optional[str] = None,
|
204
208
|
*,
|
205
209
|
schema: Optional[str] = None,
|
210
|
+
if_exists: Optional[bool] = None,
|
206
211
|
) -> None:
|
207
212
|
r"""Drop a constraint of the given name, typically via DROP CONSTRAINT.
|
208
213
|
|
@@ -214,10 +219,20 @@ class DropConstraintOp(MigrateOperation):
|
|
214
219
|
quoting of the schema outside of the default behavior, use
|
215
220
|
the SQLAlchemy construct
|
216
221
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
222
|
+
:param if_exists: If True, adds IF EXISTS operator when
|
223
|
+
dropping the constraint
|
224
|
+
|
225
|
+
.. versionadded:: 1.16.0
|
217
226
|
|
218
227
|
"""
|
219
228
|
|
220
|
-
op = cls(
|
229
|
+
op = cls(
|
230
|
+
constraint_name,
|
231
|
+
table_name,
|
232
|
+
type_=type_,
|
233
|
+
schema=schema,
|
234
|
+
if_exists=if_exists,
|
235
|
+
)
|
221
236
|
return operations.invoke(op)
|
222
237
|
|
223
238
|
@classmethod
|
@@ -1841,7 +1856,7 @@ class AlterColumnOp(AlterTableOp):
|
|
1841
1856
|
nullable: Optional[bool] = None,
|
1842
1857
|
comment: Optional[Union[str, Literal[False]]] = False,
|
1843
1858
|
server_default: Union[
|
1844
|
-
str, bool, Identity, Computed, TextClause
|
1859
|
+
str, bool, Identity, Computed, TextClause, None
|
1845
1860
|
] = False,
|
1846
1861
|
new_column_name: Optional[str] = None,
|
1847
1862
|
type_: Optional[Union[TypeEngine[Any], Type[TypeEngine[Any]]]] = None,
|
@@ -2034,16 +2049,20 @@ class AddColumnOp(AlterTableOp):
|
|
2034
2049
|
column: Column[Any],
|
2035
2050
|
*,
|
2036
2051
|
schema: Optional[str] = None,
|
2052
|
+
if_not_exists: Optional[bool] = None,
|
2037
2053
|
**kw: Any,
|
2038
2054
|
) -> None:
|
2039
2055
|
super().__init__(table_name, schema=schema)
|
2040
2056
|
self.column = column
|
2057
|
+
self.if_not_exists = if_not_exists
|
2041
2058
|
self.kw = kw
|
2042
2059
|
|
2043
2060
|
def reverse(self) -> DropColumnOp:
|
2044
|
-
|
2061
|
+
op = DropColumnOp.from_column_and_tablename(
|
2045
2062
|
self.schema, self.table_name, self.column
|
2046
2063
|
)
|
2064
|
+
op.if_exists = self.if_not_exists
|
2065
|
+
return op
|
2047
2066
|
|
2048
2067
|
def to_diff_tuple(
|
2049
2068
|
self,
|
@@ -2074,6 +2093,7 @@ class AddColumnOp(AlterTableOp):
|
|
2074
2093
|
column: Column[Any],
|
2075
2094
|
*,
|
2076
2095
|
schema: Optional[str] = None,
|
2096
|
+
if_not_exists: Optional[bool] = None,
|
2077
2097
|
) -> None:
|
2078
2098
|
"""Issue an "add column" instruction using the current
|
2079
2099
|
migration context.
|
@@ -2150,10 +2170,19 @@ class AddColumnOp(AlterTableOp):
|
|
2150
2170
|
quoting of the schema outside of the default behavior, use
|
2151
2171
|
the SQLAlchemy construct
|
2152
2172
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
2173
|
+
:param if_not_exists: If True, adds IF NOT EXISTS operator
|
2174
|
+
when creating the new column for compatible dialects
|
2175
|
+
|
2176
|
+
.. versionadded:: 1.16.0
|
2153
2177
|
|
2154
2178
|
"""
|
2155
2179
|
|
2156
|
-
op = cls(
|
2180
|
+
op = cls(
|
2181
|
+
table_name,
|
2182
|
+
column,
|
2183
|
+
schema=schema,
|
2184
|
+
if_not_exists=if_not_exists,
|
2185
|
+
)
|
2157
2186
|
return operations.invoke(op)
|
2158
2187
|
|
2159
2188
|
@classmethod
|
@@ -2164,6 +2193,7 @@ class AddColumnOp(AlterTableOp):
|
|
2164
2193
|
*,
|
2165
2194
|
insert_before: Optional[str] = None,
|
2166
2195
|
insert_after: Optional[str] = None,
|
2196
|
+
if_not_exists: Optional[bool] = None,
|
2167
2197
|
) -> None:
|
2168
2198
|
"""Issue an "add column" instruction using the current
|
2169
2199
|
batch migration context.
|
@@ -2184,6 +2214,7 @@ class AddColumnOp(AlterTableOp):
|
|
2184
2214
|
operations.impl.table_name,
|
2185
2215
|
column,
|
2186
2216
|
schema=operations.impl.schema,
|
2217
|
+
if_not_exists=if_not_exists,
|
2187
2218
|
**kw,
|
2188
2219
|
)
|
2189
2220
|
return operations.invoke(op)
|
@@ -2200,12 +2231,14 @@ class DropColumnOp(AlterTableOp):
|
|
2200
2231
|
column_name: str,
|
2201
2232
|
*,
|
2202
2233
|
schema: Optional[str] = None,
|
2234
|
+
if_exists: Optional[bool] = None,
|
2203
2235
|
_reverse: Optional[AddColumnOp] = None,
|
2204
2236
|
**kw: Any,
|
2205
2237
|
) -> None:
|
2206
2238
|
super().__init__(table_name, schema=schema)
|
2207
2239
|
self.column_name = column_name
|
2208
2240
|
self.kw = kw
|
2241
|
+
self.if_exists = if_exists
|
2209
2242
|
self._reverse = _reverse
|
2210
2243
|
|
2211
2244
|
def to_diff_tuple(
|
@@ -2225,9 +2258,11 @@ class DropColumnOp(AlterTableOp):
|
|
2225
2258
|
"original column is not present"
|
2226
2259
|
)
|
2227
2260
|
|
2228
|
-
|
2261
|
+
op = AddColumnOp.from_column_and_tablename(
|
2229
2262
|
self.schema, self.table_name, self._reverse.column
|
2230
2263
|
)
|
2264
|
+
op.if_not_exists = self.if_exists
|
2265
|
+
return op
|
2231
2266
|
|
2232
2267
|
@classmethod
|
2233
2268
|
def from_column_and_tablename(
|
@@ -2274,6 +2309,11 @@ class DropColumnOp(AlterTableOp):
|
|
2274
2309
|
quoting of the schema outside of the default behavior, use
|
2275
2310
|
the SQLAlchemy construct
|
2276
2311
|
:class:`~sqlalchemy.sql.elements.quoted_name`.
|
2312
|
+
:param if_exists: If True, adds IF EXISTS operator when
|
2313
|
+
dropping the new column for compatible dialects
|
2314
|
+
|
2315
|
+
.. versionadded:: 1.16.0
|
2316
|
+
|
2277
2317
|
:param mssql_drop_check: Optional boolean. When ``True``, on
|
2278
2318
|
Microsoft SQL Server only, first
|
2279
2319
|
drop the CHECK constraint on the column using a
|
@@ -2295,7 +2335,6 @@ class DropColumnOp(AlterTableOp):
|
|
2295
2335
|
then exec's a separate DROP CONSTRAINT for that default. Only
|
2296
2336
|
works if the column has exactly one FK constraint which refers to
|
2297
2337
|
it, at the moment.
|
2298
|
-
|
2299
2338
|
"""
|
2300
2339
|
|
2301
2340
|
op = cls(table_name, column_name, schema=schema, **kw)
|
@@ -2710,7 +2749,7 @@ class MigrationScript(MigrateOperation):
|
|
2710
2749
|
head: Optional[str] = None,
|
2711
2750
|
splice: Optional[bool] = None,
|
2712
2751
|
branch_label: Optional[_RevIdType] = None,
|
2713
|
-
version_path:
|
2752
|
+
version_path: Union[str, os.PathLike[str], None] = None,
|
2714
2753
|
depends_on: Optional[_RevIdType] = None,
|
2715
2754
|
) -> None:
|
2716
2755
|
self.rev_id = rev_id
|
@@ -2719,7 +2758,9 @@ class MigrationScript(MigrateOperation):
|
|
2719
2758
|
self.head = head
|
2720
2759
|
self.splice = splice
|
2721
2760
|
self.branch_label = branch_label
|
2722
|
-
self.version_path =
|
2761
|
+
self.version_path = (
|
2762
|
+
pathlib.Path(version_path).as_posix() if version_path else None
|
2763
|
+
)
|
2723
2764
|
self.depends_on = depends_on
|
2724
2765
|
self.upgrade_ops = upgrade_ops
|
2725
2766
|
self.downgrade_ops = downgrade_ops
|
alembic/operations/toimpl.py
CHANGED
@@ -8,6 +8,7 @@ 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_2
|
11
12
|
|
12
13
|
if TYPE_CHECKING:
|
13
14
|
from sqlalchemy.sql.schema import Table
|
@@ -92,7 +93,11 @@ def drop_column(
|
|
92
93
|
) -> None:
|
93
94
|
column = operation.to_column(operations.migration_context)
|
94
95
|
operations.impl.drop_column(
|
95
|
-
operation.table_name,
|
96
|
+
operation.table_name,
|
97
|
+
column,
|
98
|
+
schema=operation.schema,
|
99
|
+
if_exists=operation.if_exists,
|
100
|
+
**operation.kw,
|
96
101
|
)
|
97
102
|
|
98
103
|
|
@@ -167,7 +172,13 @@ def add_column(operations: "Operations", operation: "ops.AddColumnOp") -> None:
|
|
167
172
|
column = _copy(column)
|
168
173
|
|
169
174
|
t = operations.schema_obj.table(table_name, column, schema=schema)
|
170
|
-
operations.impl.add_column(
|
175
|
+
operations.impl.add_column(
|
176
|
+
table_name,
|
177
|
+
column,
|
178
|
+
schema=schema,
|
179
|
+
if_not_exists=operation.if_not_exists,
|
180
|
+
**kw,
|
181
|
+
)
|
171
182
|
|
172
183
|
for constraint in t.constraints:
|
173
184
|
if not isinstance(constraint, sa_schema.PrimaryKeyConstraint):
|
@@ -197,13 +208,19 @@ def create_constraint(
|
|
197
208
|
def drop_constraint(
|
198
209
|
operations: "Operations", operation: "ops.DropConstraintOp"
|
199
210
|
) -> None:
|
211
|
+
kw = {}
|
212
|
+
if operation.if_exists is not None:
|
213
|
+
if not sqla_2:
|
214
|
+
raise NotImplementedError("SQLAlchemy 2.0 required")
|
215
|
+
kw["if_exists"] = operation.if_exists
|
200
216
|
operations.impl.drop_constraint(
|
201
217
|
operations.schema_obj.generic_constraint(
|
202
218
|
operation.constraint_name,
|
203
219
|
operation.table_name,
|
204
220
|
operation.constraint_type,
|
205
221
|
schema=operation.schema,
|
206
|
-
)
|
222
|
+
),
|
223
|
+
**kw,
|
207
224
|
)
|
208
225
|
|
209
226
|
|