diff --git a/alembic/__init__.py b/alembic/__init__.py index e9698de5..f391826a 100644 --- a/alembic/__init__.py +++ b/alembic/__init__.py @@ -3,4 +3,4 @@ from . import context from . import op -__version__ = "1.11.4" +__version__ = "1.12.0" diff --git a/alembic/context.pyi b/alembic/context.pyi index 265d723c..46979763 100644 --- a/alembic/context.pyi +++ b/alembic/context.pyi @@ -26,6 +26,7 @@ if TYPE_CHECKING: from sqlalchemy.sql.schema import FetchedValue from sqlalchemy.sql.schema import MetaData from sqlalchemy.sql.schema import SchemaItem + from sqlalchemy.sql.type_api import TypeEngine from .autogenerate.api import AutogenContext from .config import Config @@ -145,7 +146,19 @@ def configure( [MigrationContext, Tuple[str, str], List[MigrateOperation]], None ] ] = None, - compare_type: bool = False, + compare_type: Union[ + bool, + Callable[ + [ + MigrationContext, + Column[Any], + Column[Any], + TypeEngine, + TypeEngine, + ], + Optional[bool], + ], + ] = True, compare_server_default: Union[ bool, Callable[ @@ -308,12 +321,16 @@ def configure( to produce candidate upgrade/downgrade operations. :param compare_type: Indicates type comparison behavior during an autogenerate - operation. Defaults to ``False`` which disables type - comparison. Set to - ``True`` to turn on default type comparison, which has varied - accuracy depending on backend. See :ref:`compare_types` + operation. Defaults to ``True`` turning on type comparison, which + has good accuracy on most backends. See :ref:`compare_types` for an example as well as information on other type - comparison options. + comparison options. Set to ``False`` which disables type + comparison. A callable can also be passed to provide custom type + comparison, see :ref:`compare_types` for additional details. + + .. versionchanged:: 1.12.0 The default value of + :paramref:`.EnvironmentContext.configure.compare_type` has been + changed to ``True``. .. seealso:: diff --git a/alembic/runtime/environment.py b/alembic/runtime/environment.py index 7efa0f02..d729da19 100644 --- a/alembic/runtime/environment.py +++ b/alembic/runtime/environment.py @@ -30,6 +30,7 @@ from sqlalchemy.sql.elements import ClauseElement from sqlalchemy.sql.schema import MetaData from sqlalchemy.sql.schema import SchemaItem + from sqlalchemy.sql.type_api import TypeEngine from .migration import MigrationInfo from ..autogenerate.api import AutogenContext @@ -92,6 +93,17 @@ Optional[bool], ] +CompareType = Callable[ + [ + MigrationContext, + "Column[Any]", + "Column[Any]", + "TypeEngine[Any]", + "TypeEngine[Any]", + ], + Optional[bool], +] + class EnvironmentContext(util.ModuleClsProxy): @@ -410,7 +422,7 @@ def configure( process_revision_directives: Optional[ ProcessRevisionDirectiveFn ] = None, - compare_type: bool = False, + compare_type: Union[bool, CompareType] = True, compare_server_default: Union[bool, CompareServerDefault] = False, render_item: Optional[RenderItemFn] = None, literal_binds: bool = False, @@ -548,12 +560,16 @@ def configure( to produce candidate upgrade/downgrade operations. :param compare_type: Indicates type comparison behavior during an autogenerate - operation. Defaults to ``False`` which disables type - comparison. Set to - ``True`` to turn on default type comparison, which has varied - accuracy depending on backend. See :ref:`compare_types` + operation. Defaults to ``True`` turning on type comparison, which + has good accuracy on most backends. See :ref:`compare_types` for an example as well as information on other type - comparison options. + comparison options. Set to ``False`` which disables type + comparison. A callable can also be passed to provide custom type + comparison, see :ref:`compare_types` for additional details. + + .. versionchanged:: 1.12.0 The default value of + :paramref:`.EnvironmentContext.configure.compare_type` has been + changed to ``True``. .. seealso:: @@ -880,8 +896,7 @@ def process_revision_directives(context, revision, directives): if render_item is not None: opts["render_item"] = render_item - if compare_type is not None: - opts["compare_type"] = compare_type + opts["compare_type"] = compare_type if compare_server_default is not None: opts["compare_server_default"] = compare_server_default opts["script"] = self.script diff --git a/alembic/runtime/migration.py b/alembic/runtime/migration.py index 76742294..50518ffe 100644 --- a/alembic/runtime/migration.py +++ b/alembic/runtime/migration.py @@ -178,7 +178,7 @@ def __init__( else: self.output_buffer = opts.get("output_buffer", sys.stdout) - self._user_compare_type = opts.get("compare_type", False) + self._user_compare_type = opts.get("compare_type", True) self._user_compare_server_default = opts.get( "compare_server_default", False ) diff --git a/docs/build/autogenerate.rst b/docs/build/autogenerate.rst index 5f34c0a0..7a03c905 100644 --- a/docs/build/autogenerate.rst +++ b/docs/build/autogenerate.rst @@ -126,9 +126,9 @@ Autogenerate **will detect**: Autogenerate can **optionally detect**: -* Change of column type. This will occur if you set - the :paramref:`.EnvironmentContext.configure.compare_type` parameter to - ``True``. The default implementation will reliably detect major changes, +* Change of column type. This will occur by default unless the parameter + :paramref:`.EnvironmentContext.configure.compare_type` is set to ``False``. + The default implementation will reliably detect major changes, such as between :class:`.Numeric` and :class:`.String`, as well as accommodate for the types generated by SQLAlchemy's "generic" types such as :class:`.Boolean`. Arguments that are shared between both types, such as @@ -587,15 +587,19 @@ Comparing Types ^^^^^^^^^^^^^^^^ The default type comparison logic will work for SQLAlchemy built in types as -well as basic user defined types. This logic is only enabled if the -:paramref:`.EnvironmentContext.configure.compare_type` parameter -is set to True:: +well as basic user defined types. This logic is enabled by default. +It can be disabled by setting the +:paramref:`.EnvironmentContext.configure.compare_type` to ``False``:: context.configure( # ... - compare_type = True + compare_type = False ) +.. versionchanged:: 1.12.0 The default value of + :paramref:`.EnvironmentContext.configure.compare_type` has been changed + to ``True``. + .. note:: The default type comparison logic (which is end-user extensible) currently @@ -604,7 +608,7 @@ is set to True:: * First, it compares the outer type of each column such as ``VARCHAR`` or ``TEXT``. Dialect implementations can have synonyms that are considered - equivalent- this is because some databases support types by converting them + equivalent, this is because some databases support types by converting them to another type. For example, NUMERIC and DECIMAL are considered equivalent on all backends, while on the Oracle backend the additional synonyms BIGINT, INTEGER, NUMBER, SMALLINT are added to this list of equivalents @@ -670,10 +674,10 @@ will proceed:: The boolean return values for the above ``compare_against_backend`` method, which is part of SQLAlchemy and not - Alembic,are **the opposite** of that of the + Alembic, are **the opposite** of that of the :paramref:`.EnvironmentContext.configure.compare_type` callable, returning ``True`` for types that are the same vs. ``False`` for types that are - different.The :paramref:`.EnvironmentContext.configure.compare_type` + different. The :paramref:`.EnvironmentContext.configure.compare_type` callable on the other hand should return ``True`` for types that are **different**. @@ -683,7 +687,7 @@ type itself implementing ``compare_against_backend`` is that the :paramref:`.EnvironmentContext.configure.compare_type` callable is favored first; if it returns ``None``, then the ``compare_against_backend`` method will be used, if present on the metadata type. If that returns ``None``, -then a basic check for type equivalence is run. +then the default check for type equivalence is run. .. _post_write_hooks: diff --git a/docs/build/unreleased/1248.rst b/docs/build/unreleased/1248.rst new file mode 100644 index 00000000..5e9984ee --- /dev/null +++ b/docs/build/unreleased/1248.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: usecase, autogenerate + :tickets: 1248 + + Change the default value of + :paramref:`.EnvironmentContext.configure.compare_type` to ``True``. + As Alembic's autogenerate for types was dramatically improved in + version 1.4 released in 2020, the type comparison feature is now much + more reliable so is now enabled by default. diff --git a/tests/test_autogen_diffs.py b/tests/test_autogen_diffs.py index ebba04bb..d03771ee 100644 --- a/tests/test_autogen_diffs.py +++ b/tests/test_autogen_diffs.py @@ -1755,9 +1755,14 @@ def test_compare_metadata_schema(self): diffs[4][3], ) - eq_(diffs[5][0][0], "modify_nullable") - eq_(diffs[5][0][5], False) - eq_(diffs[5][0][6], True) + eq_(diffs[5][0][0], "modify_type") + eq_(diffs[5][0][1:4], ("test_schema", "order", "amount")) + eq_(diffs[5][0][5].precision, 8) + eq_(diffs[5][0][6].precision, 10) + + eq_(diffs[5][1][0], "modify_nullable") + eq_(diffs[5][1][5], False) + eq_(diffs[5][1][6], True) class OrigObjectTest(TestBase):