1.20.0
Released: September 11, 2026
usecase
-
[usecase] [batch] Added a warning for the case where an unnamed CHECK constraint on a
reflected table is omitted from a batch "recreate" operation. An unnamed
CHECK constraint can't be reliably carried over in a batch recreate
as it may refer to columns that are being dropped or changed. This
omission was previously a silent operation. The presence of any
~sqlalchemy.schema.CheckConstraintin
Operations.batch_alter_table.table_argsis taken to indicate
that the case has been accommodated, and no warning is emitted.References: #1846
-
[usecase] [autogenerate] Autogenerate now renders a warning comment above any rendered
Operations.drop_constraint()directive for which the constraint name
isNone, as is the case when a constraint that has no name in the model
is dropped, most typically within thedowngrade()function of a
migration that adds an unnamed constraint. A warning is also emitted on
the console when the migration script is generated. The directive
requires a non-None name in order to be able to emit a "DROP CONSTRAINT"
command.References: #916
bug
-
[bug] [batch] Fixed bug in batch mode where adding a column with a type that generates
its own CHECK constraint, such as~sqlalchemy.types.Booleanor
~sqlalchemy.types.Enumwith
~sqlalchemy.types.Boolean.create_constraintset toTrue,
would emit the constraint twice when the table was recreated, once under
the name generated by the naming convention in use and once under the
name given to the type. The constraint is now emitted once, using the
same name that would be used outside of batch mode.References: #1768
-
[bug] [batch] Fixed bug in batch mode where a CHECK constraint generated by a type such
as~sqlalchemy.types.Booleanor~sqlalchemy.types.Enum
would lose the name established for it by the naming convention in use
when the table was recreated, as the constraint was regenerated against
the temporary table used for the recreate operation. The naming
convention is now resolved against the name of the table being replaced.As part of this change, a type that generates a CHECK constraint but has
no name of its own, used in conjunction with a naming convention that
includes the%(constraint_name)stoken, now emits a warning, as the
convention has no name to interpolate; the constraint continues to be
emitted without a name. As noted atbatch_check_constraints,
these datatypes should be given a name in order to participate fully in
batch mode.References: #1844
-
[bug] [batch] Fixed bug in batch mode where the
Operations.batch_alter_table.naming_conventionparameter
would re-generate the names of constraints that already had a name when
reflected, in the case where the convention included the
%(constraint_name)stoken, leading to a name that included the
convention's own prefix twice. The convention is now applied only to
those constraints that are reflected without a name, which is the use
case the parameter is documented for.References: #1845
-
[bug] [mysql] Fixed bug where autogenerate with
EnvironmentContext.configure.compare_server_defaultwould
report a persistent server default change forFloat,Numericand
other decimal columns on MySQL. MySQL reports a literal server default
for such a column either in quoted form, e.g.'1', or, when the
value is fractional, as a parenthesized expression, e.g.(2.5);
neither form was accommodated for columns other than those of
Integeraffinity, so that a default such asserver_default="1"
on asqlalchemy.Floatcolumn would never compare as equal to
the reflected value.References: #1866
-
[bug] [mysql] Fixed bug where autogenerate with
EnvironmentContext.configure.compare_server_defaultwould
report a persistent server default change for an expression server
default such as(rand()). MySQL reports such a default with the
surrounding parenthesis included whereas MariaDB reports it without
them, so that the parenthesis are now disregarded when comparing.References: #1866
misc
-
[change] [general] Support for SQLAlchemy 1.4 is dropped as of Alembic 1.20.0; SQLAlchemy
2.0.0 is now the minimum required version. SQLAlchemy 1.4 has no support
for Python 3.13 and above, and the version-conditional code paths it
required throughout Alembic have been removed in favor of the SQLAlchemy
2.0 API.References: #1851