From: Mike Bayer Date: Wed, 4 Sep 2024 03:08:21 +0000 (-0400) Subject: use proper functions to get typing origin, args X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e51ff826b9374cadb8eded370a808bc4dcbe56ba;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git use proper functions to get typing origin, args Fixed regression caused by issue :ticket:`11814` which broke support for certain flavors of :pep:`593` ``Annotated`` in the type_annotation_map when builtin types such as ``list``, ``dict`` were used without an element type. While this is an incomplete style of typing, these types nonetheless previously would be located in the type_annotation_map correctly. Fixes: #11831 Change-Id: I6ea7fc1bce462d44ffcf67ef18b60050dfc2c91e --- diff --git a/doc/build/changelog/unreleased_20/11831.rst b/doc/build/changelog/unreleased_20/11831.rst new file mode 100644 index 0000000000..65699bf5d8 --- /dev/null +++ b/doc/build/changelog/unreleased_20/11831.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, orm + :tickets: 11831 + + Fixed regression caused by issue :ticket:`11814` which broke support for + certain flavors of :pep:`593` ``Annotated`` in the type_annotation_map when + builtin types such as ``list``, ``dict`` were used without an element type. + While this is an incomplete style of typing, these types nonetheless + previously would be located in the type_annotation_map correctly. diff --git a/lib/sqlalchemy/util/typing.py b/lib/sqlalchemy/util/typing.py index f4f14e1b56..7be6589e03 100644 --- a/lib/sqlalchemy/util/typing.py +++ b/lib/sqlalchemy/util/typing.py @@ -201,9 +201,10 @@ def fixup_container_fwd_refs( and similar for list, set """ + if ( is_generic(type_) - and type_.__origin__ + and typing_get_origin(type_) in ( dict, set, @@ -223,11 +224,11 @@ def fixup_container_fwd_refs( ) ): # compat with py3.10 and earlier - return type_.__origin__.__class_getitem__( # type: ignore + return typing_get_origin(type_).__class_getitem__( # type: ignore tuple( [ ForwardRef(elem) if isinstance(elem, str) else elem - for elem in type_.__args__ + for elem in typing_get_args(type_) ] ) ) diff --git a/test/orm/declarative/test_tm_future_annotations_sync.py b/test/orm/declarative/test_tm_future_annotations_sync.py index e9b74b0d93..eb1e605d10 100644 --- a/test/orm/declarative/test_tm_future_annotations_sync.py +++ b/test/orm/declarative/test_tm_future_annotations_sync.py @@ -1419,6 +1419,16 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): Dict, (str, str), ), + (list, None, testing.requires.python310), + ( + List, + None, + ), + (dict, None, testing.requires.python310), + ( + Dict, + None, + ), id_="sa", argnames="container_typ,args", ) @@ -1428,22 +1438,30 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): test #11814 + test #11831, regression from #11814 """ global TestType if style.pep593: - TestType = Annotated[container_typ[args], 0] + if args is None: + TestType = Annotated[container_typ, 0] + else: + TestType = Annotated[container_typ[args], 0] elif style.alias: - TestType = container_typ[args] + if args is None: + TestType = container_typ + else: + TestType = container_typ[args] elif style.direct: TestType = container_typ - double_strings = args == (str, str) class Base(DeclarativeBase): if style.direct: - if double_strings: + if args == (str, str): type_annotation_map = {TestType[str, str]: JSON()} + elif args is None: + type_annotation_map = {TestType: JSON()} else: type_annotation_map = {TestType[str]: JSON()} else: @@ -1455,8 +1473,10 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): id: Mapped[int] = mapped_column(primary_key=True) if style.direct: - if double_strings: + if args == (str, str): data: Mapped[TestType[str, str]] = mapped_column() + elif args is None: + data: Mapped[TestType] = mapped_column() else: data: Mapped[TestType[str]] = mapped_column() else: diff --git a/test/orm/declarative/test_typed_mapping.py b/test/orm/declarative/test_typed_mapping.py index 5060ac6131..c9eacbae7d 100644 --- a/test/orm/declarative/test_typed_mapping.py +++ b/test/orm/declarative/test_typed_mapping.py @@ -1410,6 +1410,16 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): Dict, (str, str), ), + (list, None, testing.requires.python310), + ( + List, + None, + ), + (dict, None, testing.requires.python310), + ( + Dict, + None, + ), id_="sa", argnames="container_typ,args", ) @@ -1419,22 +1429,30 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): test #11814 + test #11831, regression from #11814 """ global TestType if style.pep593: - TestType = Annotated[container_typ[args], 0] + if args is None: + TestType = Annotated[container_typ, 0] + else: + TestType = Annotated[container_typ[args], 0] elif style.alias: - TestType = container_typ[args] + if args is None: + TestType = container_typ + else: + TestType = container_typ[args] elif style.direct: TestType = container_typ - double_strings = args == (str, str) class Base(DeclarativeBase): if style.direct: - if double_strings: + if args == (str, str): type_annotation_map = {TestType[str, str]: JSON()} + elif args is None: + type_annotation_map = {TestType: JSON()} else: type_annotation_map = {TestType[str]: JSON()} else: @@ -1446,8 +1464,10 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): id: Mapped[int] = mapped_column(primary_key=True) if style.direct: - if double_strings: + if args == (str, str): data: Mapped[TestType[str, str]] = mapped_column() + elif args is None: + data: Mapped[TestType] = mapped_column() else: data: Mapped[TestType[str]] = mapped_column() else: