--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 9963
+
+ Fixed issue in support for the :class:`.Enum` datatype in the
+ :paramref:`_orm.registry.type_annotation_map` first added as part of
+ :ticket:`8859` where using a custom :class:`.Enum` with fixed configuration
+ in the map would fail to transfer the :paramref:`.Enum.name` parameter,
+ which among other issues would prevent PostgreSQL enums from working if the
+ enum values were passed as individual values. Logic has been updated so
+ that "name" is transferred over, but also that the default :class:`.Enum`
+ which is against the plain Python `enum.Enum` class or other "empty" enum
+ won't set a hardcoded name of ``"enum"`` either.
super().__init__(length=length)
- if self.enum_class:
+ # assign name to the given enum class if no other name, and this
+ # enum is not an "empty" enum. if the enum is "empty" we assume
+ # this is a template enum that will be used to generate
+ # new Enum classes.
+ if self.enum_class and values:
kw.setdefault("name", self.enum_class.__name__.lower())
SchemaType.__init__(
self,
enum_args = self._enums_argument
# make a new Enum that looks like this one.
- # pop the "name" so that it gets generated based on the enum
# arguments or other rules
kw = self._make_enum_kw({})
- kw.pop("name", None)
if native_enum is False:
kw["native_enum"] = False
def _make_enum_kw(self, kw):
kw.setdefault("validate_strings", self.validate_strings)
- kw.setdefault("name", self.name)
+ if self.name:
+ kw.setdefault("name", self.name)
kw.setdefault("schema", self.schema)
kw.setdefault("inherit_schema", self.inherit_schema)
kw.setdefault("metadata", self.metadata)
class EnumOrLiteralTypeMapTest(fixtures.TestBase, testing.AssertsCompiledSQL):
__dialect__ = "default"
- @testing.variation("use_callable", [True, False])
+ @testing.variation("use_explicit_name", [True, False])
+ @testing.variation("use_individual_values", [True, False])
@testing.variation("include_generic", [True, False])
@testing.variation("set_native_enum", ["none", True, False])
def test_enum_explicit(
- self, use_callable, include_generic, set_native_enum: Variation
+ self,
+ include_generic,
+ set_native_enum: Variation,
+ use_explicit_name,
+ use_individual_values,
):
global FooEnum
kw = {"length": 500}
+ if use_explicit_name:
+ kw["name"] = "my_foo_enum"
+
if set_native_enum.none:
expected_native_enum = True
elif set_native_enum.set_native_enum:
else:
set_native_enum.fail()
- if use_callable:
- tam = {FooEnum: Enum(FooEnum, **kw)}
+ if use_individual_values:
+ tam = {FooEnum: Enum("foo", "bar", **kw)}
else:
tam = {FooEnum: Enum(FooEnum, **kw)}
id: Mapped[int] = mapped_column(primary_key=True)
data: Mapped[FooEnum]
+ if use_explicit_name:
+ eq_(MyClass.__table__.c.data.type.name, "my_foo_enum")
+ elif use_individual_values:
+ is_(MyClass.__table__.c.data.type.enum_class, None)
+ eq_(MyClass.__table__.c.data.type.name, None)
+ else:
+ is_(MyClass.__table__.c.data.type.enum_class, FooEnum)
+ eq_(MyClass.__table__.c.data.type.name, "fooenum")
+
is_true(isinstance(MyClass.__table__.c.data.type, Enum))
eq_(MyClass.__table__.c.data.type.length, 500)
- is_(MyClass.__table__.c.data.type.enum_class, FooEnum)
+
is_(MyClass.__table__.c.data.type.native_enum, expected_native_enum)
@testing.variation("set_native_enum", ["none", True, False])
is_true(isinstance(MyClass.__table__.c.data.type, Enum))
eq_(MyClass.__table__.c.data.type.length, 9)
is_(MyClass.__table__.c.data.type.enum_class, FooEnum)
+ eq_(MyClass.__table__.c.data.type.name, "fooenum") # and not 'enum'
@testing.variation(
- "sqltype", ["custom", "base_enum", "specific_enum", "string"]
+ "sqltype",
+ [
+ "custom",
+ "base_enum_name_none",
+ "base_enum_default_name",
+ "specific_unnamed_enum",
+ "specific_named_enum",
+ "string",
+ ],
)
@testing.variation("indicate_type_explicitly", [True, False])
def test_pep586_literal(
self._possible_values = get_args(literal_type)
our_type = mapped_col_type = LiteralSqlType(Status)
- elif sqltype.specific_enum:
+ elif sqltype.specific_unnamed_enum:
our_type = mapped_col_type = Enum(
"to-do", "in-progress", "done", native_enum=False
)
- elif sqltype.base_enum:
+ elif sqltype.specific_named_enum:
+ our_type = mapped_col_type = Enum(
+ "to-do", "in-progress", "done", name="specific_name"
+ )
+ elif sqltype.base_enum_name_none:
+ our_type = Enum(enum.Enum, native_enum=False, name=None)
+ mapped_col_type = Enum(
+ "to-do", "in-progress", "done", native_enum=False
+ )
+ elif sqltype.base_enum_default_name:
our_type = Enum(enum.Enum, native_enum=False)
mapped_col_type = Enum(
"to-do", "in-progress", "done", native_enum=False
Foo.__table__.c.status.type._possible_values,
("to-do", "in-progress", "done"),
)
- elif sqltype.specific_enum or sqltype.base_enum:
+ elif (
+ sqltype.specific_unnamed_enum
+ or sqltype.base_enum_name_none
+ or sqltype.base_enum_default_name
+ ):
eq_(
Foo.__table__.c.status.type.enums,
["to-do", "in-progress", "done"],
)
is_(Foo.__table__.c.status.type.native_enum, False)
+ elif sqltype.specific_named_enum:
+ is_(Foo.__table__.c.status.type.native_enum, True)
+
+ if (
+ sqltype.specific_unnamed_enum
+ or sqltype.base_enum_name_none
+ or sqltype.base_enum_default_name
+ ):
+ eq_(Foo.__table__.c.status.type.name, None)
+ elif sqltype.specific_named_enum:
+ eq_(Foo.__table__.c.status.type.name, "specific_name")
@testing.variation("indicate_type_explicitly", [True, False])
def test_pep586_literal_defaults_to_enum(
class EnumOrLiteralTypeMapTest(fixtures.TestBase, testing.AssertsCompiledSQL):
__dialect__ = "default"
- @testing.variation("use_callable", [True, False])
+ @testing.variation("use_explicit_name", [True, False])
+ @testing.variation("use_individual_values", [True, False])
@testing.variation("include_generic", [True, False])
@testing.variation("set_native_enum", ["none", True, False])
def test_enum_explicit(
- self, use_callable, include_generic, set_native_enum: Variation
+ self,
+ include_generic,
+ set_native_enum: Variation,
+ use_explicit_name,
+ use_individual_values,
):
# anno only: global FooEnum
kw = {"length": 500}
+ if use_explicit_name:
+ kw["name"] = "my_foo_enum"
+
if set_native_enum.none:
expected_native_enum = True
elif set_native_enum.set_native_enum:
else:
set_native_enum.fail()
- if use_callable:
- tam = {FooEnum: Enum(FooEnum, **kw)}
+ if use_individual_values:
+ tam = {FooEnum: Enum("foo", "bar", **kw)}
else:
tam = {FooEnum: Enum(FooEnum, **kw)}
id: Mapped[int] = mapped_column(primary_key=True)
data: Mapped[FooEnum]
+ if use_explicit_name:
+ eq_(MyClass.__table__.c.data.type.name, "my_foo_enum")
+ elif use_individual_values:
+ is_(MyClass.__table__.c.data.type.enum_class, None)
+ eq_(MyClass.__table__.c.data.type.name, None)
+ else:
+ is_(MyClass.__table__.c.data.type.enum_class, FooEnum)
+ eq_(MyClass.__table__.c.data.type.name, "fooenum")
+
is_true(isinstance(MyClass.__table__.c.data.type, Enum))
eq_(MyClass.__table__.c.data.type.length, 500)
- is_(MyClass.__table__.c.data.type.enum_class, FooEnum)
+
is_(MyClass.__table__.c.data.type.native_enum, expected_native_enum)
@testing.variation("set_native_enum", ["none", True, False])
is_true(isinstance(MyClass.__table__.c.data.type, Enum))
eq_(MyClass.__table__.c.data.type.length, 9)
is_(MyClass.__table__.c.data.type.enum_class, FooEnum)
+ eq_(MyClass.__table__.c.data.type.name, "fooenum") # and not 'enum'
@testing.variation(
- "sqltype", ["custom", "base_enum", "specific_enum", "string"]
+ "sqltype",
+ [
+ "custom",
+ "base_enum_name_none",
+ "base_enum_default_name",
+ "specific_unnamed_enum",
+ "specific_named_enum",
+ "string",
+ ],
)
@testing.variation("indicate_type_explicitly", [True, False])
def test_pep586_literal(
self._possible_values = get_args(literal_type)
our_type = mapped_col_type = LiteralSqlType(Status)
- elif sqltype.specific_enum:
+ elif sqltype.specific_unnamed_enum:
our_type = mapped_col_type = Enum(
"to-do", "in-progress", "done", native_enum=False
)
- elif sqltype.base_enum:
+ elif sqltype.specific_named_enum:
+ our_type = mapped_col_type = Enum(
+ "to-do", "in-progress", "done", name="specific_name"
+ )
+ elif sqltype.base_enum_name_none:
+ our_type = Enum(enum.Enum, native_enum=False, name=None)
+ mapped_col_type = Enum(
+ "to-do", "in-progress", "done", native_enum=False
+ )
+ elif sqltype.base_enum_default_name:
our_type = Enum(enum.Enum, native_enum=False)
mapped_col_type = Enum(
"to-do", "in-progress", "done", native_enum=False
Foo.__table__.c.status.type._possible_values,
("to-do", "in-progress", "done"),
)
- elif sqltype.specific_enum or sqltype.base_enum:
+ elif (
+ sqltype.specific_unnamed_enum
+ or sqltype.base_enum_name_none
+ or sqltype.base_enum_default_name
+ ):
eq_(
Foo.__table__.c.status.type.enums,
["to-do", "in-progress", "done"],
)
is_(Foo.__table__.c.status.type.native_enum, False)
+ elif sqltype.specific_named_enum:
+ is_(Foo.__table__.c.status.type.native_enum, True)
+
+ if (
+ sqltype.specific_unnamed_enum
+ or sqltype.base_enum_name_none
+ or sqltype.base_enum_default_name
+ ):
+ eq_(Foo.__table__.c.status.type.name, None)
+ elif sqltype.specific_named_enum:
+ eq_(Foo.__table__.c.status.type.name, "specific_name")
@testing.variation("indicate_type_explicitly", [True, False])
def test_pep586_literal_defaults_to_enum(