@@ -66,7 +66,6 @@ class User:
6666)
6767
6868import marshmallow
69- import typing_extensions
7069import typing_inspect
7170
7271from marshmallow_dataclass .generic_resolver import (
@@ -78,9 +77,9 @@ class User:
7877from marshmallow_dataclass .lazy_class_attribute import lazy_class_attribute
7978
8079if sys .version_info >= (3 , 9 ):
81- from typing import Annotated
80+ from typing import Annotated , get_args , get_origin
8281else :
83- from typing_extensions import Annotated
82+ from typing_extensions import Annotated , get_args , get_origin
8483
8584if sys .version_info >= (3 , 11 ):
8685 from typing import dataclass_transform
@@ -540,7 +539,7 @@ def _internal_class_schema(
540539) -> Type [marshmallow .Schema ]:
541540 schema_ctx = _schema_ctx_stack .top
542541
543- if typing_extensions . get_origin (clazz ) is Annotated and sys .version_info < (3 , 10 ):
542+ if get_origin (clazz ) is Annotated and sys .version_info < (3 , 10 ):
544543 # https://github.com/python/cpython/blob/3.10/Lib/typing.py#L977
545544 class_name = clazz ._name or clazz .__origin__ .__name__ # type: ignore[attr-defined]
546545 else :
@@ -597,7 +596,7 @@ def _internal_class_schema(
597596 (
598597 type_hints [field .name ]
599598 if not is_generic_type (clazz )
600- else _get_type_hint_of_generic_object (field .type , schema_ctx )
599+ else _resolve_forward_type_refs (field .type , schema_ctx )
601600 ),
602601 _get_field_default (field ),
603602 field .metadata ,
@@ -659,8 +658,8 @@ def _field_by_supertype(
659658 )
660659
661660
662- def _generic_type_add_any (typ : type ) -> type :
663- """if typ is generic type without arguments, replace them by Any."""
661+ def _container_type_add_any (typ : type ) -> type :
662+ """if typ is container type without arguments, replace them by Any."""
664663 if typ is list or typ is List :
665664 typ = List [Any ]
666665 elif typ is dict or typ is Dict :
@@ -676,18 +675,20 @@ def _generic_type_add_any(typ: type) -> type:
676675 return typ
677676
678677
679- def _field_for_generic_type (
678+ def _field_for_container_type (
680679 typ : type ,
681680 base_schema : Optional [Type [marshmallow .Schema ]],
682681 ** metadata : Any ,
683682) -> Optional [marshmallow .fields .Field ]:
684683 """
685- If the type is a generic interface, resolve the arguments and construct the appropriate Field.
684+ If the type is a container interface, resolve the arguments and construct the appropriate Field.
685+
686+ We use the term 'container' to differentiate from the Generic support
686687 """
687- origin = typing_extensions . get_origin (typ )
688- arguments = typing_extensions . get_args (typ )
688+ origin = get_origin (typ )
689+ arguments = get_args (typ )
689690 if origin :
690- # Override base_schema.TYPE_MAPPING to change the class used for generic types below
691+ # Override base_schema.TYPE_MAPPING to change the class used for container types below
691692 type_mapping = base_schema .TYPE_MAPPING if base_schema else {}
692693
693694 if origin in (list , List ):
@@ -749,18 +750,15 @@ def _field_for_annotated_type(
749750 """
750751 If the type is an Annotated interface, resolve the arguments and construct the appropriate Field.
751752 """
752- origin = typing_extensions . get_origin (typ )
753- arguments = typing_extensions . get_args (typ )
753+ origin = get_origin (typ )
754+ arguments = get_args (typ )
754755 if origin and origin is Annotated :
755756 marshmallow_annotations = [
756757 arg
757758 for arg in arguments [1 :]
758759 if _is_marshmallow_field (arg )
759760 # Support `CustomGenericField[mf.String]`
760- or (
761- is_generic_type (arg )
762- and _is_marshmallow_field (typing_extensions .get_origin (arg ))
763- )
761+ or (is_generic_type (arg ) and _is_marshmallow_field (get_origin (arg )))
764762 ]
765763 if marshmallow_annotations :
766764 if len (marshmallow_annotations ) > 1 :
@@ -782,7 +780,7 @@ def _field_for_union_type(
782780 base_schema : Optional [Type [marshmallow .Schema ]],
783781 ** metadata : Any ,
784782) -> Optional [marshmallow .fields .Field ]:
785- arguments = typing_extensions . get_args (typ )
783+ arguments = get_args (typ )
786784 if typing_inspect .is_union_type (typ ):
787785 if typing_inspect .is_optional_type (typ ):
788786 metadata ["allow_none" ] = metadata .get ("allow_none" , True )
@@ -886,8 +884,8 @@ def _field_for_schema(
886884 if predefined_field :
887885 return predefined_field
888886
889- # Generic types specified without type arguments
890- typ = _generic_type_add_any (typ )
887+ # Container types (generics like List) specified without type arguments
888+ typ = _container_type_add_any (typ )
891889
892890 # Base types
893891 field = _field_by_type (typ , base_schema )
@@ -900,7 +898,7 @@ def _field_for_schema(
900898
901899 # i.e.: Literal['abc']
902900 if typing_inspect .is_literal_type (typ ):
903- arguments = typing_extensions . get_args (typ )
901+ arguments = get_args (typ )
904902 return marshmallow .fields .Raw (
905903 validate = (
906904 marshmallow .validate .Equal (arguments [0 ])
@@ -912,7 +910,7 @@ def _field_for_schema(
912910
913911 # i.e.: Final[str] = 'abc'
914912 if typing_inspect .is_final_type (typ ):
915- arguments = typing_extensions . get_args (typ )
913+ arguments = get_args (typ )
916914 if arguments :
917915 subtyp = arguments [0 ]
918916 elif default is not marshmallow .missing :
@@ -953,10 +951,10 @@ def _field_for_schema(
953951 if union_field :
954952 return union_field
955953
956- # Generic types
957- generic_field = _field_for_generic_type (typ , base_schema , ** metadata )
958- if generic_field :
959- return generic_field
954+ # Container types
955+ container_field = _field_for_container_type (typ , base_schema , ** metadata )
956+ if container_field :
957+ return container_field
960958
961959 # typing.NewType returns a function (in python <= 3.9) or a class (python >= 3.10) with a
962960 # __supertype__ attribute
@@ -1034,9 +1032,7 @@ def is_generic_alias_of_dataclass(clazz: type) -> bool:
10341032 Check if given class is a generic alias of a dataclass, if the dataclass is
10351033 defined as `class A(Generic[T])`, this method will return true if `A[int]` is passed
10361034 """
1037- return is_generic_alias (clazz ) and dataclasses .is_dataclass (
1038- typing_extensions .get_origin (clazz )
1039- )
1035+ return is_generic_alias (clazz ) and dataclasses .is_dataclass (get_origin (clazz ))
10401036
10411037
10421038def _get_type_hints (
@@ -1058,11 +1054,13 @@ def _get_type_hints(
10581054 return type_hints
10591055
10601056
1061- def _get_type_hint_of_generic_object (
1057+ def _resolve_forward_type_refs (
10621058 obj ,
10631059 schema_ctx : _SchemaContext ,
10641060) -> type :
1065- """typing.get_type_hints doesn't work with generic aliases, i.e.: A[int]. But this 'hack' works."""
1061+ """
1062+ Resolve forward references, mainly applies to Generics i.e.: `A["int"]` -> `A[int]`
1063+ """
10661064
10671065 class X :
10681066 x : obj # type: ignore[name-defined]
0 commit comments