99import functools
1010import typing
1111from dataclasses import dataclass , is_dataclass
12- from typing import Any , Callable , Dict , List , Optional , TypeVar , Generic , overload
12+ from typing import Any , Callable , Dict , Generic , List , Optional , TypeVar , overload
1313
1414import jinja2
1515from typing_extensions import Type , dataclass_transform
2424 get_args ,
2525 get_generic_arg ,
2626 get_origin ,
27+ get_type_var_names ,
2728 has_default ,
2829 has_default_factory ,
2930 is_any ,
@@ -602,6 +603,10 @@ def render(self, arg: DeField) -> str:
602603 """
603604 if arg .deserializer and arg .deserializer .inner is not default_deserializer :
604605 res = self .custom_field_deserializer (arg )
606+ elif is_generic (arg .type ):
607+ arg .type_args = get_args (arg .type )
608+ arg .type = get_origin (arg .type )
609+ res = self .render (arg )
605610 elif is_dataclass (arg .type ):
606611 res = self .dataclass (arg )
607612 elif is_opt (arg .type ):
@@ -639,12 +644,10 @@ def render(self, arg: DeField) -> str:
639644 elif isinstance (arg .type , TypeVar ):
640645 index = find_generic_arg (self .cls , arg .type )
641646 res = (
642- f"from_obj(get_generic_arg(maybe_generic, { index } ), "
643- f" { arg .data } , named={ not arg .iterbased } , reuse_instances=reuse_instances)"
647+ f"from_obj(get_generic_arg(maybe_generic, maybe_generic_type_vars, "
648+ f"variable_type_args, { index } ), { arg .data } , named={ not arg .iterbased } , "
649+ "reuse_instances=reuse_instances)"
644650 )
645- elif is_generic (arg .type ):
646- arg .type = get_origin (arg .type )
647- res = self .render (arg )
648651 elif is_literal (arg .type ):
649652 res = self .literal (arg )
650653 else :
@@ -690,7 +693,12 @@ def dataclass(self, arg: DeField) -> str:
690693 else :
691694 var = arg .datavar
692695
693- opts = "maybe_generic=maybe_generic, reuse_instances=reuse_instances"
696+ type_args_str = [str (t ).lstrip ("~" ) for t in arg .type_args ] if arg .type_args else None
697+
698+ opts = (
699+ "maybe_generic=maybe_generic, maybe_generic_type_vars=maybe_generic_type_vars, "
700+ f"variable_type_args={ type_args_str } , reuse_instances=reuse_instances"
701+ )
694702
695703 if arg .is_self_referencing ():
696704 class_name = "cls"
@@ -718,6 +726,7 @@ def opt(self, arg: DeField) -> str:
718726 ... o: Optional[List[int]]
719727 >>> Renderer('foo').render(DeField(Optional[Foo], 'f', datavar='data'))
720728 '(Foo.__serde__.funcs[\\ 'foo\\ '](data=data["f"], maybe_generic=maybe_generic, \
729+ maybe_generic_type_vars=maybe_generic_type_vars, variable_type_args=None, \
721730 reuse_instances=reuse_instances)) if data.get("f") is not None else None'
722731 """
723732 value = arg [0 ]
@@ -771,13 +780,16 @@ def tuple(self, arg: DeField) -> str:
771780 >>> Renderer('foo').render(DeField(Tuple[str, int, List[int], Foo], 'd', datavar='data'))
772781 '(coerce(str, data["d"][0]), coerce(int, data["d"][1]), \
773782 [coerce(int, v) for v in data["d"][2]], \
774- Foo.__serde__.funcs[\\ 'foo\\ '](data=data["d"][3], maybe_generic=maybe_generic, reuse_instances=reuse_instances),)'
783+ Foo.__serde__.funcs[\\ 'foo\\ '](data=data["d"][3], maybe_generic=maybe_generic, \
784+ maybe_generic_type_vars=maybe_generic_type_vars, variable_type_args=None, \
785+ reuse_instances=reuse_instances),)'
775786
776787 >>> field = DeField(Tuple[str, int, List[int], Foo], 'd', datavar='data', index=0, iterbased=True)
777788 >>> Renderer('foo').render(field)
778789 "(coerce(str, data[0][0]), coerce(int, data[0][1]), \
779790 [coerce(int, v) for v in data[0][2]], Foo.__serde__.funcs['foo'](data=data[0][3], \
780- maybe_generic=maybe_generic, reuse_instances=reuse_instances),)"
791+ maybe_generic=maybe_generic, maybe_generic_type_vars=maybe_generic_type_vars, \
792+ variable_type_args=None, reuse_instances=reuse_instances),)"
781793 """
782794 if is_bare_tuple (arg .type ) or is_variable_tuple (arg .type ):
783795 return f"tuple({ arg .data } )"
@@ -799,9 +811,10 @@ def dict(self, arg: DeField) -> str:
799811 >>> @deserialize
800812 ... class Foo: pass
801813 >>> Renderer('foo').render(DeField(Dict[Foo, List[Foo]], 'f', datavar='data'))
802- '{Foo.__serde__.funcs[\\ 'foo\\ '](data=k, maybe_generic=maybe_generic, reuse_instances=reuse_instances): \
803- [Foo.__serde__.funcs[\\ 'foo\\ '](data=v, maybe_generic=maybe_generic, reuse_instances=reuse_instances) for v in v] \
804- for k, v in data["f"].items()}'
814+ '{Foo.__serde__.funcs[\\ 'foo\\ '](data=k, maybe_generic=maybe_generic, \
815+ maybe_generic_type_vars=maybe_generic_type_vars, variable_type_args=None, reuse_instances=reuse_instances): \
816+ [Foo.__serde__.funcs[\\ 'foo\\ '](data=v, maybe_generic=maybe_generic, maybe_generic_type_vars=maybe_generic_type_vars, \
817+ variable_type_args=None, reuse_instances=reuse_instances) for v in v] for k, v in data["f"].items()}'
805818 """
806819 if is_bare_dict (arg .type ):
807820 return arg .data
@@ -898,13 +911,16 @@ def renderable(f: DeField) -> bool:
898911
899912def render_from_iter (cls : Type [Any ], custom : Optional [DeserializeFunc ] = None , type_check : TypeCheck = NoCheck ) -> str :
900913 template = """
901- def {{func}}(cls=cls, maybe_generic=None, data=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
914+ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
915+ variable_type_args=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
902916 if reuse_instances is Ellipsis:
903917 reuse_instances = {{serde_scope.reuse_instances_default}}
904918
905919 if data is None:
906920 return None
907921
922+ maybe_generic_type_vars = maybe_generic_type_vars or {{cls_type_vars}}
923+
908924 {% for f in fields %}
909925 __{{f.name}} = {{f|arg(loop.index-1)|rvalue}}
910926 {% endfor %}
@@ -924,7 +940,12 @@ def {{func}}(cls=cls, maybe_generic=None, data=None, reuse_instances = {{serde_s
924940 env .filters .update ({"rvalue" : renderer .render })
925941 env .filters .update ({"arg" : to_iter_arg })
926942 fields = list (filter (renderable , defields (cls )))
927- res = env .get_template ("iter" ).render (func = FROM_ITER , serde_scope = getattr (cls , SERDE_SCOPE ), fields = fields )
943+ res = env .get_template ("iter" ).render (
944+ func = FROM_ITER ,
945+ serde_scope = getattr (cls , SERDE_SCOPE ),
946+ fields = fields ,
947+ cls_type_vars = get_type_var_names (cls ),
948+ )
928949
929950 if renderer .import_numpy :
930951 res = "import numpy\n " + res
@@ -939,14 +960,16 @@ def render_from_dict(
939960 type_check : TypeCheck = NoCheck ,
940961) -> str :
941962 template = """
942- def {{func}}(cls=cls, maybe_generic=None, data=None,
943- reuse_instances = {{serde_scope.reuse_instances_default}}):
963+ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
964+ variable_type_args=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
944965 if reuse_instances is Ellipsis:
945966 reuse_instances = {{serde_scope.reuse_instances_default}}
946967
947968 if data is None:
948969 return None
949970
971+ maybe_generic_type_vars = maybe_generic_type_vars or {{cls_type_vars}}
972+
950973 {% for f in fields %}
951974 __{{f.name}} = {{f|arg(loop.index-1)|rvalue}}
952975 {% endfor %}
@@ -973,7 +996,11 @@ def {{func}}(cls=cls, maybe_generic=None, data=None,
973996 env .filters .update ({"arg" : functools .partial (to_arg , rename_all = rename_all )})
974997 fields = list (filter (renderable , defields (cls )))
975998 res = env .get_template ("dict" ).render (
976- func = FROM_DICT , serde_scope = getattr (cls , SERDE_SCOPE ), fields = fields , type_check = type_check
999+ func = FROM_DICT ,
1000+ serde_scope = getattr (cls , SERDE_SCOPE ),
1001+ fields = fields ,
1002+ type_check = type_check ,
1003+ cls_type_vars = get_type_var_names (cls ),
9771004 )
9781005
9791006 if renderer .import_numpy :
@@ -984,7 +1011,8 @@ def {{func}}(cls=cls, maybe_generic=None, data=None,
9841011
9851012def render_union_func (cls : Type [Any ], union_args : List [Type [Any ]], tagging : Tagging = DefaultTagging ) -> str :
9861013 template = """
987- def {{func}}(cls=cls, maybe_generic=None, data=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
1014+ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
1015+ variable_type_args=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
9881016 errors = []
9891017 {% for t in union_args %}
9901018 try:
@@ -1042,7 +1070,8 @@ def {{func}}(cls=cls, maybe_generic=None, data=None, reuse_instances = {{serde_s
10421070
10431071def render_literal_func (cls : Type [Any ], literal_args : List [Any ], tagging : Tagging = DefaultTagging ) -> str :
10441072 template = """
1045- def {{func}}(cls=cls, maybe_generic=None, data=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
1073+ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
1074+ variable_type_args=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
10461075 if data in ({%- for v in literal_args -%}{{v|repr}},{%- endfor -%}):
10471076 return data
10481077 raise SerdeError("Can not deserialize " + repr(data) + " as {{literal_name}}.")
0 commit comments