Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

The Enum's name property is lost within an autogenerated migration #1551

Open
@mberdyshev

Description

Describe the bug
A migration doesn't provide the name property of Enum if sqlalchemy.Enum is augmented with sqlalchemy.types.Decorator. Even if the name property is explicitly given.

Expected behavior
The property has to be provided in Enum's definition inside a migration.

To Reproduce
sql_types.py

from typing import Any
from sqlalchemy import Enum, TypeDecorator
class Enum1(Enum):
 def __init__(self, *enums: object, **kw: Any):
 validate_strings = kw.pop("validate_strings", True)
 super().__init__(*enums, **kw, validate_strings=validate_strings)
class Enum2(TypeDecorator):
 impl = Enum
 cache_ok = True
 def __init__(self, *enums: object, **kw: Any):
 validate_strings = kw.pop("validate_strings", True)
 super().__init__(*enums, **kw, validate_strings=validate_strings)

tables.py

import enum
from sqlalchemy import Column, MetaData, Table
from sql_types import Enum1, Enum2
class TestEnum(str, enum.Enum):
 FIRST = enum.auto()
 SECOND = enum.auto()
metadata = MetaData()
test_table = Table(
 "test",
 metadata,
 Column("col1", Enum1(TestEnum), nullable=False),
 Column("col2", Enum2(TestEnum, name="enum2"), nullable=False),
)

alembic revision --autogenerate -m "Enums" provides (shortened):

def upgrade() -> None:
 # ### commands auto generated by Alembic - please adjust! ###
 op.create_table('test',
 sa.Column('col1', db.sql_types.Enum1('FIRST', 'SECOND', name='testenum'), nullable=False),
 sa.Column('col2', db.sql_types.Enum2('FIRST', 'SECOND'), nullable=False)
 )
 # ### end Alembic commands ###
def downgrade() -> None:
 # ### commands auto generated by Alembic - please adjust! ###
 op.drop_table('test')
 # ### end Alembic commands ###

Error
As you can see from the migration enums are defined differently - the second one misses its name property.
If I try to run it on PostgreSQL I get the error:

Stacktrace
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Generating static SQL
INFO [alembic.runtime.migration] Will assume transactional DDL.
BEGIN;
CREATE TABLE alembic_version (
 version_num VARCHAR(32) NOT NULL,
 CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);
INFO [alembic.runtime.migration] Running upgrade -> 264b6f57ae76, Enums
-- Running upgrade -> 264b6f57ae76
CREATE TYPE testenum AS ENUM ('FIRST', 'SECOND');
Traceback (most recent call last):
 File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\runpy.py", line 196, in _run_module_as_main
 return _run_code(code, main_globals, None,
 File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\runpy.py", line 86, in _run_code
 exec(code, run_globals)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\__main__.py", line 4, in <module>
 main(prog="alembic")
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\config.py", line 636, in main
 CommandLine(prog=prog).main(argv=argv)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\config.py", line 626, in main
 self.run_cmd(cfg, options)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\config.py", line 603, in run_cmd
 fn(
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\command.py", line 406, in upgrade
 script.run_env()
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\script\base.py", line 586, in run_env
 util.load_python_file(self.dir, "env.py")
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\util\pyfiles.py", line 95, in load_python_file
 module = load_module_py(module_id, path)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\util\pyfiles.py", line 113, in load_module_py
 spec.loader.exec_module(module) # type: ignore
 File "<frozen importlib._bootstrap_external>", line 883, in exec_module
 File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
 File "c:\Users\Михаил\PycharmProjects\Example Project\db\alembic\env.py", line 78, in <module>
 run_migrations_offline()
 File "c:\Users\Михаил\PycharmProjects\Example Project\db\alembic\env.py", line 52, in run_migrations_offline
 context.run_migrations()
 File "<string>", line 8, in run_migrations
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\runtime\environment.py", line 946, in run_migrations
 self.get_context().run_migrations(**kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\runtime\migration.py", line 628, in run_migrations
 step.migration_fn(**kw)
 File "C:\Users\Михаил\PycharmProjects\Example Project\db\alembic\versions264円b6f57ae76_enums.py", line 24, in upgrade
 op.create_table('test',
 File "<string>", line 8, in create_table
 File "<string>", line 3, in create_table
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\operations\ops.py", line 1318, in create_table
 return operations.invoke(op)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\operations\base.py", line 442, in invoke
 return fn(self, operation)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\operations\toimpl.py", line 143, in create_table
 operations.impl.create_table(table, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\ddl\impl.py", line 366, in create_table
 table.dispatch.before_create(
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\event\attr.py", line 497, in __call__
 fn(*args, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\util\langhelpers.py", line 852, in __call__
 return getattr(self.target, self.name)(*arg, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\sqltypes.py", line 1130, in _on_table_create
 t._on_table_create(target, bind, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\dialects\postgresql\named_types.py", line 98, in _on_table_create
 self.create(bind=bind, checkfirst=checkfirst)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\dialects\postgresql\named_types.py", line 338, in create
 super().create(bind, checkfirst=checkfirst)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\dialects\postgresql\named_types.py", line 51, in create
 bind._run_ddl_visitor(self.DDLGenerator, self, checkfirst=checkfirst)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\engine\mock.py", line 61, in _run_ddl_visitor
 visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\visitors.py", line 664, in traverse_single
 return meth(obj, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\dialects\postgresql\named_types.py", line 153, in visit_enum
 self.connection.execute(CreateEnumType(enum))
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\engine\mock.py", line 69, in execute
 return self._execute_impl(obj, parameters)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\runtime\migration.py", line 675, in dump
 self.impl._exec(construct)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\alembic\ddl\impl.py", line 190, in _exec
 compiled = construct.compile(dialect=self.dialect, **compile_kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\elements.py", line 308, in compile
 return self._compiler(dialect, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\ddl.py", line 69, in _compiler
 return dialect.ddl_compiler(dialect, self, **kw)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\compiler.py", line 870, in __init__
 self.string = self.process(self.statement, **compile_kwargs)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\compiler.py", line 915, in process
 return obj._compiler_dispatch(self, **kwargs)
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\sql\visitors.py", line 141, in _compiler_dispatch
 return meth(self, **kw) # type: ignore # noqa: E501
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\dialects\postgresql\base.py", line 2236, in visit_create_enum_type
 self.preparer.format_type(type_),
 File "C:\Users\Михаил\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\sqlalchemy\dialects\postgresql\base.py", line 2728, in format_type
 raise exc.CompileError(
sqlalchemy.exc.CompileError: PostgreSQL ENUM type requires a name.

Versions.

  • OS: Windows 11 23H2
  • Python: 3.10.11
  • Alembic: 1.13.3
  • SQLAlchemy: 2.0.35
  • Database: PostgreSQL 17.0.1
  • DBAPI: psycopg2 2.9.9

Additional context
The docs state that subclassing from TypeDecorator should be preferred:

This method is preferred to direct subclassing of SQLAlchemy’s built-in types as it ensures that all required functionality of the underlying type is kept in place.

Have a nice day!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /