alembic 1.15.1__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.
Files changed (41) hide show
  1. alembic/__init__.py +1 -1
  2. alembic/autogenerate/compare.py +60 -7
  3. alembic/autogenerate/render.py +28 -4
  4. alembic/command.py +112 -37
  5. alembic/config.py +574 -222
  6. alembic/ddl/base.py +36 -8
  7. alembic/ddl/impl.py +24 -7
  8. alembic/ddl/mssql.py +3 -1
  9. alembic/ddl/mysql.py +8 -4
  10. alembic/ddl/postgresql.py +6 -2
  11. alembic/ddl/sqlite.py +1 -1
  12. alembic/op.pyi +25 -6
  13. alembic/operations/base.py +21 -4
  14. alembic/operations/ops.py +53 -10
  15. alembic/operations/toimpl.py +20 -3
  16. alembic/script/base.py +123 -136
  17. alembic/script/revision.py +1 -1
  18. alembic/script/write_hooks.py +20 -21
  19. alembic/templates/async/alembic.ini.mako +40 -16
  20. alembic/templates/generic/alembic.ini.mako +39 -17
  21. alembic/templates/multidb/alembic.ini.mako +42 -17
  22. alembic/templates/pyproject/README +1 -0
  23. alembic/templates/pyproject/alembic.ini.mako +44 -0
  24. alembic/templates/pyproject/env.py +78 -0
  25. alembic/templates/pyproject/pyproject.toml.mako +76 -0
  26. alembic/templates/pyproject/script.py.mako +28 -0
  27. alembic/testing/__init__.py +2 -0
  28. alembic/testing/assertions.py +4 -0
  29. alembic/testing/env.py +56 -1
  30. alembic/testing/fixtures.py +28 -1
  31. alembic/testing/suite/_autogen_fixtures.py +113 -0
  32. alembic/util/__init__.py +1 -0
  33. alembic/util/compat.py +56 -0
  34. alembic/util/messaging.py +4 -0
  35. alembic/util/pyfiles.py +56 -19
  36. {alembic-1.15.1.dist-info → alembic-1.16.0.dist-info}/METADATA +5 -4
  37. {alembic-1.15.1.dist-info → alembic-1.16.0.dist-info}/RECORD +41 -36
  38. {alembic-1.15.1.dist-info → alembic-1.16.0.dist-info}/WHEEL +1 -1
  39. {alembic-1.15.1.dist-info → alembic-1.16.0.dist-info}/entry_points.txt +0 -0
  40. {alembic-1.15.1.dist-info → alembic-1.16.0.dist-info/licenses}/LICENSE +0 -0
  41. {alembic-1.15.1.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, name: str, column: Column[Any], schema: Optional[str] = None
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(compiler, element.column, **kw),
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(compiler, element.column.name, **kw),
209
+ drop_column(
210
+ compiler, element.column.name, if_exists=element.if_exists, **kw
211
+ ),
201
212
  )
202
213
 
203
214
 
@@ -299,9 +310,13 @@ def format_server_default(
299
310
  compiler: DDLCompiler,
300
311
  default: Optional[_ServerDefault],
301
312
  ) -> str:
302
- return compiler.get_column_default_string(
313
+ # this can be updated to use compiler.render_default_string
314
+ # for SQLAlchemy 2.0 and above; not in 1.4
315
+ default_str = compiler.get_column_default_string(
303
316
  Column("x", Integer, server_default=default)
304
317
  )
318
+ assert default_str is not None
319
+ return default_str
305
320
 
306
321
 
307
322
  def format_type(compiler: DDLCompiler, type_: TypeEngine) -> str:
@@ -316,16 +331,29 @@ def alter_table(
316
331
  return "ALTER TABLE %s" % format_table_name(compiler, name, schema)
317
332
 
318
333
 
319
- def drop_column(compiler: DDLCompiler, name: str, **kw) -> str:
320
- return "DROP COLUMN %s" % format_column_name(compiler, name)
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
+ )
321
341
 
322
342
 
323
343
  def alter_column(compiler: DDLCompiler, name: str) -> str:
324
344
  return "ALTER COLUMN %s" % format_column_name(compiler, name)
325
345
 
326
346
 
327
- def add_column(compiler: DDLCompiler, column: Column[Any], **kw) -> str:
328
- text = "ADD COLUMN %s" % compiler.get_column_specification(column, **kw)
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
+ )
329
357
 
330
358
  const = " ".join(
331
359
  compiler.process(constraint) for constraint in column.constraints
alembic/ddl/impl.py CHANGED
@@ -46,7 +46,6 @@ if TYPE_CHECKING:
46
46
  from sqlalchemy.engine.reflection import Inspector
47
47
  from sqlalchemy.sql import ClauseElement
48
48
  from sqlalchemy.sql import Executable
49
- from sqlalchemy.sql.elements import ColumnElement
50
49
  from sqlalchemy.sql.elements import quoted_name
51
50
  from sqlalchemy.sql.schema import Constraint
52
51
  from sqlalchemy.sql.schema import ForeignKeyConstraint
@@ -257,8 +256,11 @@ class DefaultImpl(metaclass=ImplMeta):
257
256
  self,
258
257
  table_name: str,
259
258
  column_name: str,
259
+ *,
260
260
  nullable: Optional[bool] = None,
261
- server_default: Union[_ServerDefault, Literal[False]] = False,
261
+ server_default: Optional[
262
+ Union[_ServerDefault, Literal[False]]
263
+ ] = False,
262
264
  name: Optional[str] = None,
263
265
  type_: Optional[TypeEngine] = None,
264
266
  schema: Optional[str] = None,
@@ -369,25 +371,40 @@ class DefaultImpl(metaclass=ImplMeta):
369
371
  self,
370
372
  table_name: str,
371
373
  column: Column[Any],
374
+ *,
372
375
  schema: Optional[Union[str, quoted_name]] = None,
376
+ if_not_exists: Optional[bool] = None,
373
377
  ) -> None:
374
- self._exec(base.AddColumn(table_name, column, schema=schema))
378
+ self._exec(
379
+ base.AddColumn(
380
+ table_name,
381
+ column,
382
+ schema=schema,
383
+ if_not_exists=if_not_exists,
384
+ )
385
+ )
375
386
 
376
387
  def drop_column(
377
388
  self,
378
389
  table_name: str,
379
390
  column: Column[Any],
391
+ *,
380
392
  schema: Optional[str] = None,
393
+ if_exists: Optional[bool] = None,
381
394
  **kw,
382
395
  ) -> None:
383
- self._exec(base.DropColumn(table_name, column, schema=schema))
396
+ self._exec(
397
+ base.DropColumn(
398
+ table_name, column, schema=schema, if_exists=if_exists
399
+ )
400
+ )
384
401
 
385
402
  def add_constraint(self, const: Any) -> None:
386
403
  if const._create_rule is None or const._create_rule(self):
387
404
  self._exec(schema.AddConstraint(const))
388
405
 
389
- def drop_constraint(self, const: Constraint) -> None:
390
- self._exec(schema.DropConstraint(const))
406
+ def drop_constraint(self, const: Constraint, **kw: Any) -> None:
407
+ self._exec(schema.DropConstraint(const, **kw))
391
408
 
392
409
  def rename_table(
393
410
  self,
@@ -440,7 +457,7 @@ class DefaultImpl(metaclass=ImplMeta):
440
457
  def drop_table_comment(self, table: Table) -> None:
441
458
  self._exec(schema.DropTableComment(table))
442
459
 
443
- def create_column_comment(self, column: ColumnElement[Any]) -> None:
460
+ def create_column_comment(self, column: Column[Any]) -> None:
444
461
  self._exec(schema.SetColumnComment(column))
445
462
 
446
463
  def drop_index(self, index: Index, **kw: Any) -> None:
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( # type:ignore[override]
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( # type:ignore[override]
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: Union[_ServerDefault, Literal[False]] = False,
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( # type:ignore[override]
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: Union[_ServerDefault, Literal[False]] = False,
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, column: Column[Any], *, schema: Optional[str] = None
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,12 +154,14 @@ def alter_column(
146
154
  *,
147
155
  nullable: Optional[bool] = None,
148
156
  comment: Union[str, Literal[False], None] = False,
149
- server_default: Any = False,
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,
153
163
  existing_server_default: Union[
154
- str, bool, Identity, Computed, None
164
+ str, bool, Identity, Computed, TextClause, None
155
165
  ] = False,
156
166
  existing_nullable: Optional[bool] = None,
157
167
  existing_comment: Optional[str] = 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:
@@ -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
  ...
@@ -705,14 +710,16 @@ class Operations(AbstractOperations):
705
710
  *,
706
711
  nullable: Optional[bool] = None,
707
712
  comment: Union[str, Literal[False], None] = False,
708
- server_default: Any = False,
713
+ server_default: Union[
714
+ str, bool, Identity, Computed, TextClause, None
715
+ ] = False,
709
716
  new_column_name: Optional[str] = None,
710
717
  type_: Union[TypeEngine[Any], Type[TypeEngine[Any]], None] = None,
711
718
  existing_type: Union[
712
719
  TypeEngine[Any], Type[TypeEngine[Any]], None
713
720
  ] = None,
714
721
  existing_server_default: Union[
715
- str, bool, Identity, Computed, None
722
+ str, bool, Identity, Computed, TextClause, None
716
723
  ] = False,
717
724
  existing_nullable: Optional[bool] = None,
718
725
  existing_comment: Optional[str] = None,
@@ -1359,6 +1366,11 @@ class Operations(AbstractOperations):
1359
1366
  quoting of the schema outside of the default behavior, use
1360
1367
  the SQLAlchemy construct
1361
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
+
1362
1374
  :param mssql_drop_check: Optional boolean. When ``True``, on
1363
1375
  Microsoft SQL Server only, first
1364
1376
  drop the CHECK constraint on the column using a
@@ -1380,7 +1392,6 @@ class Operations(AbstractOperations):
1380
1392
  then exec's a separate DROP CONSTRAINT for that default. Only
1381
1393
  works if the column has exactly one FK constraint which refers to
1382
1394
  it, at the moment.
1383
-
1384
1395
  """ # noqa: E501
1385
1396
  ...
1386
1397
 
@@ -1391,6 +1402,7 @@ class Operations(AbstractOperations):
1391
1402
  type_: Optional[str] = None,
1392
1403
  *,
1393
1404
  schema: Optional[str] = None,
1405
+ if_exists: Optional[bool] = None,
1394
1406
  ) -> None:
1395
1407
  r"""Drop a constraint of the given name, typically via DROP CONSTRAINT.
1396
1408
 
@@ -1402,6 +1414,10 @@ class Operations(AbstractOperations):
1402
1414
  quoting of the schema outside of the default behavior, use
1403
1415
  the SQLAlchemy construct
1404
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
1405
1421
 
1406
1422
  """ # noqa: E501
1407
1423
  ...
@@ -1644,6 +1660,7 @@ class BatchOperations(AbstractOperations):
1644
1660
  *,
1645
1661
  insert_before: Optional[str] = None,
1646
1662
  insert_after: Optional[str] = None,
1663
+ if_not_exists: Optional[bool] = None,
1647
1664
  ) -> None:
1648
1665
  """Issue an "add column" instruction using the current
1649
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(constraint_name, table_name, type_=type_, schema=schema)
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
@@ -1840,14 +1855,16 @@ class AlterColumnOp(AlterTableOp):
1840
1855
  *,
1841
1856
  nullable: Optional[bool] = None,
1842
1857
  comment: Optional[Union[str, Literal[False]]] = False,
1843
- server_default: Any = False,
1858
+ server_default: Union[
1859
+ str, bool, Identity, Computed, TextClause, None
1860
+ ] = False,
1844
1861
  new_column_name: Optional[str] = None,
1845
1862
  type_: Optional[Union[TypeEngine[Any], Type[TypeEngine[Any]]]] = None,
1846
1863
  existing_type: Optional[
1847
1864
  Union[TypeEngine[Any], Type[TypeEngine[Any]]]
1848
1865
  ] = None,
1849
- existing_server_default: Optional[
1850
- Union[str, bool, Identity, Computed]
1866
+ existing_server_default: Union[
1867
+ str, bool, Identity, Computed, TextClause, None
1851
1868
  ] = False,
1852
1869
  existing_nullable: Optional[bool] = None,
1853
1870
  existing_comment: Optional[str] = None,
@@ -2032,16 +2049,20 @@ class AddColumnOp(AlterTableOp):
2032
2049
  column: Column[Any],
2033
2050
  *,
2034
2051
  schema: Optional[str] = None,
2052
+ if_not_exists: Optional[bool] = None,
2035
2053
  **kw: Any,
2036
2054
  ) -> None:
2037
2055
  super().__init__(table_name, schema=schema)
2038
2056
  self.column = column
2057
+ self.if_not_exists = if_not_exists
2039
2058
  self.kw = kw
2040
2059
 
2041
2060
  def reverse(self) -> DropColumnOp:
2042
- return DropColumnOp.from_column_and_tablename(
2061
+ op = DropColumnOp.from_column_and_tablename(
2043
2062
  self.schema, self.table_name, self.column
2044
2063
  )
2064
+ op.if_exists = self.if_not_exists
2065
+ return op
2045
2066
 
2046
2067
  def to_diff_tuple(
2047
2068
  self,
@@ -2072,6 +2093,7 @@ class AddColumnOp(AlterTableOp):
2072
2093
  column: Column[Any],
2073
2094
  *,
2074
2095
  schema: Optional[str] = None,
2096
+ if_not_exists: Optional[bool] = None,
2075
2097
  ) -> None:
2076
2098
  """Issue an "add column" instruction using the current
2077
2099
  migration context.
@@ -2148,10 +2170,19 @@ class AddColumnOp(AlterTableOp):
2148
2170
  quoting of the schema outside of the default behavior, use
2149
2171
  the SQLAlchemy construct
2150
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
2151
2177
 
2152
2178
  """
2153
2179
 
2154
- op = cls(table_name, column, schema=schema)
2180
+ op = cls(
2181
+ table_name,
2182
+ column,
2183
+ schema=schema,
2184
+ if_not_exists=if_not_exists,
2185
+ )
2155
2186
  return operations.invoke(op)
2156
2187
 
2157
2188
  @classmethod
@@ -2162,6 +2193,7 @@ class AddColumnOp(AlterTableOp):
2162
2193
  *,
2163
2194
  insert_before: Optional[str] = None,
2164
2195
  insert_after: Optional[str] = None,
2196
+ if_not_exists: Optional[bool] = None,
2165
2197
  ) -> None:
2166
2198
  """Issue an "add column" instruction using the current
2167
2199
  batch migration context.
@@ -2182,6 +2214,7 @@ class AddColumnOp(AlterTableOp):
2182
2214
  operations.impl.table_name,
2183
2215
  column,
2184
2216
  schema=operations.impl.schema,
2217
+ if_not_exists=if_not_exists,
2185
2218
  **kw,
2186
2219
  )
2187
2220
  return operations.invoke(op)
@@ -2198,12 +2231,14 @@ class DropColumnOp(AlterTableOp):
2198
2231
  column_name: str,
2199
2232
  *,
2200
2233
  schema: Optional[str] = None,
2234
+ if_exists: Optional[bool] = None,
2201
2235
  _reverse: Optional[AddColumnOp] = None,
2202
2236
  **kw: Any,
2203
2237
  ) -> None:
2204
2238
  super().__init__(table_name, schema=schema)
2205
2239
  self.column_name = column_name
2206
2240
  self.kw = kw
2241
+ self.if_exists = if_exists
2207
2242
  self._reverse = _reverse
2208
2243
 
2209
2244
  def to_diff_tuple(
@@ -2223,9 +2258,11 @@ class DropColumnOp(AlterTableOp):
2223
2258
  "original column is not present"
2224
2259
  )
2225
2260
 
2226
- return AddColumnOp.from_column_and_tablename(
2261
+ op = AddColumnOp.from_column_and_tablename(
2227
2262
  self.schema, self.table_name, self._reverse.column
2228
2263
  )
2264
+ op.if_not_exists = self.if_exists
2265
+ return op
2229
2266
 
2230
2267
  @classmethod
2231
2268
  def from_column_and_tablename(
@@ -2272,6 +2309,11 @@ class DropColumnOp(AlterTableOp):
2272
2309
  quoting of the schema outside of the default behavior, use
2273
2310
  the SQLAlchemy construct
2274
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
+
2275
2317
  :param mssql_drop_check: Optional boolean. When ``True``, on
2276
2318
  Microsoft SQL Server only, first
2277
2319
  drop the CHECK constraint on the column using a
@@ -2293,7 +2335,6 @@ class DropColumnOp(AlterTableOp):
2293
2335
  then exec's a separate DROP CONSTRAINT for that default. Only
2294
2336
  works if the column has exactly one FK constraint which refers to
2295
2337
  it, at the moment.
2296
-
2297
2338
  """
2298
2339
 
2299
2340
  op = cls(table_name, column_name, schema=schema, **kw)
@@ -2708,7 +2749,7 @@ class MigrationScript(MigrateOperation):
2708
2749
  head: Optional[str] = None,
2709
2750
  splice: Optional[bool] = None,
2710
2751
  branch_label: Optional[_RevIdType] = None,
2711
- version_path: Optional[str] = None,
2752
+ version_path: Union[str, os.PathLike[str], None] = None,
2712
2753
  depends_on: Optional[_RevIdType] = None,
2713
2754
  ) -> None:
2714
2755
  self.rev_id = rev_id
@@ -2717,7 +2758,9 @@ class MigrationScript(MigrateOperation):
2717
2758
  self.head = head
2718
2759
  self.splice = splice
2719
2760
  self.branch_label = branch_label
2720
- self.version_path = version_path
2761
+ self.version_path = (
2762
+ pathlib.Path(version_path).as_posix() if version_path else None
2763
+ )
2721
2764
  self.depends_on = depends_on
2722
2765
  self.upgrade_ops = upgrade_ops
2723
2766
  self.downgrade_ops = downgrade_ops