-
-
Notifications
You must be signed in to change notification settings - Fork 249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The Enum's name
property is lost within an autogenerated migration
#1551
Comments
Hi, Managing all attributes of enum with a type decorator is not easy, so it's likely missing something here. If your use case I would more simply do something like def Enum1(*args,**kwargs):
kwargs.set_default('validate_strings', True)
return Enum(*args, **kwargs) In any case it's a valid bug |
I've looked up the source code and found that type rendering depends on enum = Enum(TestEnum)
print(util.generic_repr(enum)) # TypeDecorator
# Enum('FIRST', 'SECOND')
print(util.generic_repr(enum, to_inspect=[Enum, SchemaType])) # Enum
# Enum('FIRST', 'SECOND', name='testenum') It seems now that this bug is more related to SQLAlchemy. Probably TypeDecorator's |
nice finding. Seems like that may be the issue. I'm not sure why there is a reason for that repr in type decorator (there usually is). @zzzeek maybe a type should have a generic method to format itself that type decorator could hook into? |
But the TypeDecorator does not repr() as the inner type does, it has its ownr repr() that does something different: from sqlalchemy import *
print(repr(Enum("a", "b", "c", name="e1")))
class MyType(TypeDecorator):
impl = Enum
print(repr(MyType("a", "b", "c", name="e2"))) prints:
note it uses so there's no quick fix here. choices include:
|
this would be the most expedient fix for the moment, but it wouldn't get the extra arguments used by enum beyond those used for schema type: diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index bc2d898ab..6676a61e0 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -3826,3 +3826,4 @@ type_api.MATCHTYPE = MATCHTYPE
type_api.INDEXABLE = INDEXABLE = Indexable
type_api.TABLEVALUE = TABLEVALUE
type_api._resolve_value_to_type = _resolve_value_to_type
+type_api.SchemaType = SchemaType
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index 9f40905fa..f484e26db 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -58,6 +58,7 @@ if typing.TYPE_CHECKING:
from .sqltypes import NUMERICTYPE as NUMERICTYPE # noqa: F401
from .sqltypes import STRINGTYPE as STRINGTYPE # noqa: F401
from .sqltypes import TABLEVALUE as TABLEVALUE # noqa: F401
+ from .sqltypes import SchemaType as SchemaType # noqa: F401
from ..engine.interfaces import Dialect
from ..util.typing import GenericProtocol
@@ -2276,7 +2277,13 @@ class TypeDecorator(SchemaEventTarget, ExternalType, TypeEngine[_T]):
return self.impl_instance.sort_key_function
def __repr__(self) -> str:
- return util.generic_repr(self, to_inspect=self.impl_instance)
+ inst = self.impl_instance
+ if isinstance(inst, SchemaType):
+ to_inspect=[inst, SchemaType]
+ else:
+ to_inspect = [inst]
+
+ return util.generic_repr(self, to_inspect=to_inspect)
class Variant(TypeDecorator[_T]):
|
I know, that's why I suggested to have new methods for this. |
For what it's worth, I ran into a similar issue. I have a class PydanticModelType(TypeDecorator, Generic[T]):
"""Generic class representing a pydantic model that can be serialized to Python."""
cache_ok = True
impl = JSON()
def __init__(self, pydantic_type: type[T]) -> None:
"""Initializes class with the type of the pydantic model."""
self.pydantic_type = pydantic_type
super().__init__()
@override
def load_dialect_impl(self, dialect: Dialect) -> TypeEngine:
# Use JSONB for PostgreSQL and JSON for other databases.
if dialect.name == "postgresql":
return dialect.type_descriptor(JSONB())
return dialect.type_descriptor(JSON())
@override
def process_bind_param(self, value: T | None, _dialect: Dialect) -> str | None:
if value is not None:
value = self.pydantic_type.model_dump_json(value)
return value
@override
def process_result_value(
self, value: str | None, _dialect: Dialect
) -> BaseModel | None:
if value is not None:
value = self.pydantic_type.model_validate_json(value)
return value And when I declare it in my class configuration: Mapped[Config] = mapped_column(
PydanticModelType(Config), nullable=False
) Alembic generates this:
Not sure if it's the same bug. I'll try overriding repr later. |
Describe the bug
A migration doesn't provide the
name
property of Enum ifsqlalchemy.Enum
is augmented withsqlalchemy.types.Decorator
. Even if thename
property is explicitly given.Expected behavior
The property has to be provided in Enum's definition inside a migration.
To Reproduce
sql_types.py
tables.py
alembic revision --autogenerate -m "Enums"
provides (shortened):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
Versions.
Additional context
The docs state that subclassing from
TypeDecorator
should be preferred:Have a nice day!
The text was updated successfully, but these errors were encountered: