Added support for the :pep:`695` ``TypeAliasType`` construct as well as the
python 3.12 native ``type`` keyword to work with ORM Annotated Declarative
form when using these constructs to link to a :pep:`593` ``Annotated``
container, allowing the resolution of the ``Annotated`` to proceed when
these constructs are used in a :class:`_orm.Mapped` typing container.
Fixes: #11130
Change-Id: I9a386943966de2107f15f08dfe6ed2aa84f7e86c
(cherry picked from commit
985193c407ffb891c8eed042fac6f9547a34d694)
--- /dev/null
+.. change::
+ :tags: usecase, orm
+ :tickets: 11130
+
+ Added support for the :pep:`695` ``TypeAliasType`` construct as well as the
+ python 3.12 native ``type`` keyword to work with ORM Annotated Declarative
+ form when using these constructs to link to a :pep:`593` ``Annotated``
+ container, allowing the resolution of the ``Annotated`` to proceed when
+ these constructs are used in a :class:`_orm.Mapped` typing container.
from ..util.typing import is_fwd_ref
from ..util.typing import is_optional_union
from ..util.typing import is_pep593
+from ..util.typing import is_pep695
from ..util.typing import is_union
from ..util.typing import Self
from ..util.typing import typing_get_args
use_args_from = None
+ our_original_type = our_type
+
+ if is_pep695(our_type):
+ our_type = our_type.__value__
+
if is_pep593(our_type):
our_type_is_pep593 = True
new_sqltype = None
if our_type_is_pep593:
- checks = [our_type, raw_pep_593_type]
+ checks = [our_original_type, raw_pep_593_type]
else:
- checks = [our_type]
+ checks = [our_original_type]
for check_type in checks:
new_sqltype = registry._resolve_type(check_type)
"""
type _UnionPep695 = _SomeDict1 | _SomeDict2
type _StrPep695 = str
+
+type strtypalias_keyword = Annotated[str, mapped_column(info={"hi": "there"})]
+
+strtypalias_tat: typing.TypeAliasType = Annotated[
+ str, mapped_column(info={"hi": "there"})]
+
+strtypalias_plain = Annotated[str, mapped_column(info={"hi": "there"})]
""",
globals(),
)
eq_(Test.__table__.c.data.type.length, 30)
is_(Test.__table__.c.structure.type._type_affinity, JSON)
+ @testing.variation("alias_type", ["none", "typekeyword", "typealiastype"])
+ @testing.requires.python312
+ def test_extract_pep593_from_pep695(
+ self, decl_base: Type[DeclarativeBase], alias_type
+ ):
+ """test #11130"""
+
+ class MyClass(decl_base):
+ __tablename__ = "my_table"
+
+ id: Mapped[int] = mapped_column(primary_key=True)
+
+ if alias_type.typekeyword:
+ data_one: Mapped[strtypalias_keyword] # noqa: F821
+ elif alias_type.typealiastype:
+ data_one: Mapped[strtypalias_tat] # noqa: F821
+ elif alias_type.none:
+ data_one: Mapped[strtypalias_plain] # noqa: F821
+ else:
+ alias_type.fail()
+
+ table = MyClass.__table__
+ assert table is not None
+
+ eq_(MyClass.data_one.expression.info, {"hi": "there"})
+
@testing.requires.python310
def test_we_got_all_attrs_test_annotated(self):
argnames = _py_inspect.getfullargspec(mapped_column)
"""
type _UnionPep695 = _SomeDict1 | _SomeDict2
type _StrPep695 = str
+
+type strtypalias_keyword = Annotated[str, mapped_column(info={"hi": "there"})]
+
+strtypalias_tat: typing.TypeAliasType = Annotated[
+ str, mapped_column(info={"hi": "there"})]
+
+strtypalias_plain = Annotated[str, mapped_column(info={"hi": "there"})]
""",
globals(),
)
eq_(Test.__table__.c.data.type.length, 30)
is_(Test.__table__.c.structure.type._type_affinity, JSON)
+ @testing.variation("alias_type", ["none", "typekeyword", "typealiastype"])
+ @testing.requires.python312
+ def test_extract_pep593_from_pep695(
+ self, decl_base: Type[DeclarativeBase], alias_type
+ ):
+ """test #11130"""
+
+ class MyClass(decl_base):
+ __tablename__ = "my_table"
+
+ id: Mapped[int] = mapped_column(primary_key=True)
+
+ if alias_type.typekeyword:
+ data_one: Mapped[strtypalias_keyword] # noqa: F821
+ elif alias_type.typealiastype:
+ data_one: Mapped[strtypalias_tat] # noqa: F821
+ elif alias_type.none:
+ data_one: Mapped[strtypalias_plain] # noqa: F821
+ else:
+ alias_type.fail()
+
+ table = MyClass.__table__
+ assert table is not None
+
+ eq_(MyClass.data_one.expression.info, {"hi": "there"})
+
@testing.requires.python310
def test_we_got_all_attrs_test_annotated(self):
argnames = _py_inspect.getfullargspec(mapped_column)