From da40b925662408ba5075256474017ad0a90b9cbd Mon Sep 17 00:00:00 2001 From: khanjan2708 Date: Mon, 23 Feb 2026 00:52:10 +0530 Subject: [PATCH] Fix TypeDecorator rendering to preserve SchemaType name/schema (fixes #1551) --- alembic/autogenerate/render.py | 22 ++++++++++++++++++---- tests/test_autogen_render.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/alembic/autogenerate/render.py b/alembic/autogenerate/render.py index 7f32838d..6a103ddb 100644 --- a/alembic/autogenerate/render.py +++ b/alembic/autogenerate/render.py @@ -698,7 +698,7 @@ def _uq_constraint( def _user_autogenerate_prefix(autogen_context, target): - prefix = autogen_context.opts["user_module_prefix"] + prefix = autogen_context.opts.get("user_module_prefix", None) if prefix is None: return "%s." % target.__module__ else: @@ -856,6 +856,20 @@ def _render_fetched_value(autogen_context: AutogenContext) -> str: return "%(prefix)sFetchedValue()" % { "prefix": _sqlalchemy_autogenerate_prefix(autogen_context), } +def _type_repr(type_: sqltypes.TypeEngine) -> str: + res = repr(type_) + if isinstance(type_, sqltypes.TypeDecorator) and isinstance( + type_.impl, sqltypes.SchemaType + ): + for attr in ("name", "schema"): + val = getattr(type_.impl, attr, None) + if val is not None and f"{attr}=" not in res: + if res.endswith("()"): + res = res[:-1] + "%s=%r)" % (attr, val) + else: + res = res[:-1] + ", %s=%r)" % (attr, val) + return res + def _repr_type( @@ -888,7 +902,7 @@ def _repr_type( if impl_rt: return impl_rt else: - return "%s.%r" % (dname, type_) + return "%s.%s" % (dname, _type_repr(type_)) elif impl_rt: return impl_rt elif mod.startswith("sqlalchemy."): @@ -897,10 +911,10 @@ def _repr_type( return fn(type_, autogen_context) else: prefix = _sqlalchemy_autogenerate_prefix(autogen_context) - return "%s%r" % (prefix, type_) + return "%s%s" % (prefix, _type_repr(type_)) else: prefix = _user_autogenerate_prefix(autogen_context, type_) - return "%s%r" % (prefix, type_) + return "%s%s" % (prefix, _type_repr(type_)) def _render_ARRAY_type(type_: ARRAY, autogen_context: AutogenContext) -> str: diff --git a/tests/test_autogen_render.py b/tests/test_autogen_render.py index c5f5565c..ce28b979 100644 --- a/tests/test_autogen_render.py +++ b/tests/test_autogen_render.py @@ -1797,6 +1797,38 @@ def test_render_non_native_enum(self): f"sa.Enum('one', 'two', 'three'{extra}, native_enum=False)", ) + def test_render_enum_subclass(self): + class Enum1(Enum): + pass + + enum = Enum1("one", "two", name="enum1") + eq_ignore_whitespace( + autogenerate.render._repr_type(enum, self.autogen_context), + f"{self.__class__.__module__}.Enum1('one', 'two', name='enum1')", + ) + + def test_render_typedecorator_enum(self): + class Enum2(types.TypeDecorator): + impl = Enum + cache_ok = True + + enum = Enum2("one", "two", name="enum2") + eq_ignore_whitespace( + autogenerate.render._repr_type(enum, self.autogen_context), + f"{self.__class__.__module__}.Enum2('one', 'two', name='enum2')", + ) + + def test_render_typedecorator_boolean(self): + class MyBool(types.TypeDecorator): + impl = Boolean + cache_ok = True + + type_ = MyBool(name="bool_ck") + eq_ignore_whitespace( + autogenerate.render._repr_type(type_, self.autogen_context), + f"{self.__class__.__module__}.MyBool(name='bool_ck')", + ) + def test_repr_plain_sqla_type(self): type_ = Integer() eq_ignore_whitespace(