@@ -202,7 +202,8 @@ def dataclass(
202
202
frozen : bool = False ,
203
203
base_schema : Optional [Type [marshmallow .Schema ]] = None ,
204
204
cls_frame : Optional [types .FrameType ] = None ,
205
- ) -> Type [_U ]: ...
205
+ ) -> Type [_U ]:
206
+ ...
206
207
207
208
208
209
@overload
@@ -215,7 +216,8 @@ def dataclass(
215
216
frozen : bool = False ,
216
217
base_schema : Optional [Type [marshmallow .Schema ]] = None ,
217
218
cls_frame : Optional [types .FrameType ] = None ,
218
- ) -> Callable [[Type [_U ]], Type [_U ]]: ...
219
+ ) -> Callable [[Type [_U ]], Type [_U ]]:
220
+ ...
219
221
220
222
221
223
# _cls should never be specified by keyword, so start it with an
@@ -280,13 +282,15 @@ def decorator(cls: Type[_U], stacklevel: int = 1) -> Type[_U]:
280
282
281
283
282
284
@overload
283
- def add_schema (_cls : Type [_U ]) -> Type [_U ]: ...
285
+ def add_schema (_cls : Type [_U ]) -> Type [_U ]:
286
+ ...
284
287
285
288
286
289
@overload
287
290
def add_schema (
288
291
base_schema : Optional [Type [marshmallow .Schema ]] = None ,
289
- ) -> Callable [[Type [_U ]], Type [_U ]]: ...
292
+ ) -> Callable [[Type [_U ]], Type [_U ]]:
293
+ ...
290
294
291
295
292
296
@overload
@@ -295,7 +299,8 @@ def add_schema(
295
299
base_schema : Optional [Type [marshmallow .Schema ]] = None ,
296
300
cls_frame : Optional [types .FrameType ] = None ,
297
301
stacklevel : int = 1 ,
298
- ) -> Type [_U ]: ...
302
+ ) -> Type [_U ]:
303
+ ...
299
304
300
305
301
306
def add_schema (_cls = None , base_schema = None , cls_frame = None , stacklevel = 1 ):
@@ -348,7 +353,8 @@ def class_schema(
348
353
* ,
349
354
globalns : Optional [Dict [str , Any ]] = None ,
350
355
localns : Optional [Dict [str , Any ]] = None ,
351
- ) -> Type [marshmallow .Schema ]: ...
356
+ ) -> Type [marshmallow .Schema ]:
357
+ ...
352
358
353
359
354
360
@overload
@@ -358,7 +364,8 @@ def class_schema(
358
364
clazz_frame : Optional [types .FrameType ] = None ,
359
365
* ,
360
366
globalns : Optional [Dict [str , Any ]] = None ,
361
- ) -> Type [marshmallow .Schema ]: ...
367
+ ) -> Type [marshmallow .Schema ]:
368
+ ...
362
369
363
370
364
371
def class_schema (
@@ -573,7 +580,8 @@ def _internal_class_schema(
573
580
# https://github.com/python/cpython/blob/3.10/Lib/typing.py#L977
574
581
class_name = clazz ._name or clazz .__origin__ .__name__ # type: ignore[attr-defined]
575
582
else :
576
- class_name = clazz .__name__
583
+ # generic aliases do not have a __name__ prior python 3.10
584
+ class_name = getattr (clazz , "__name__" , repr (clazz ))
577
585
578
586
schema_ctx .seen_classes [clazz ] = class_name
579
587
@@ -613,11 +621,20 @@ def _internal_class_schema(
613
621
# Determine whether we should include non-init fields
614
622
include_non_init = getattr (getattr (clazz , "Meta" , None ), "include_non_init" , False )
615
623
624
+ # Update the schema members to contain marshmallow fields instead of dataclass fields
625
+ type_hints = {}
626
+ if not is_generic_type (clazz ):
627
+ type_hints = _get_type_hints (clazz , schema_ctx )
628
+
616
629
attributes .update (
617
630
(
618
631
field .name ,
619
- field_for_schema (
620
- _get_field_type_hints (field , schema_ctx ),
632
+ _field_for_schema (
633
+ (
634
+ type_hints [field .name ]
635
+ if not is_generic_type (clazz )
636
+ else _get_generic_type_hints (field .type , schema_ctx )
637
+ ),
621
638
_get_field_default (field ),
622
639
field .metadata ,
623
640
base_schema ,
@@ -710,7 +727,7 @@ def _field_for_generic_type(
710
727
type_mapping = base_schema .TYPE_MAPPING if base_schema else {}
711
728
712
729
if origin in (list , List ):
713
- child_type = field_for_schema (
730
+ child_type = _field_for_schema (
714
731
arguments [0 ],
715
732
base_schema = base_schema ,
716
733
)
@@ -726,15 +743,15 @@ def _field_for_generic_type(
726
743
):
727
744
from . import collection_field
728
745
729
- child_type = field_for_schema (
746
+ child_type = _field_for_schema (
730
747
arguments [0 ],
731
748
base_schema = base_schema ,
732
749
)
733
750
return collection_field .Sequence (cls_or_instance = child_type , ** metadata )
734
751
if origin in (set , Set ):
735
752
from . import collection_field
736
753
737
- child_type = field_for_schema (
754
+ child_type = _field_for_schema (
738
755
arguments [0 ],
739
756
base_schema = base_schema ,
740
757
)
@@ -744,7 +761,7 @@ def _field_for_generic_type(
744
761
if origin in (frozenset , FrozenSet ):
745
762
from . import collection_field
746
763
747
- child_type = field_for_schema (
764
+ child_type = _field_for_schema (
748
765
arguments [0 ],
749
766
base_schema = base_schema ,
750
767
)
@@ -753,7 +770,7 @@ def _field_for_generic_type(
753
770
)
754
771
if origin in (tuple , Tuple ):
755
772
children = tuple (
756
- field_for_schema (
773
+ _field_for_schema (
757
774
arg ,
758
775
base_schema = base_schema ,
759
776
)
@@ -980,7 +997,7 @@ def _field_for_schema(
980
997
)
981
998
else :
982
999
subtyp = Any
983
- return field_for_schema (subtyp , default , metadata , base_schema )
1000
+ return _field_for_schema (subtyp , default , metadata , base_schema )
984
1001
985
1002
annotated_field = _field_for_annotated_type (typ , ** metadata )
986
1003
if annotated_field :
@@ -1081,30 +1098,37 @@ def _is_generic_alias_of_dataclass(clazz: type) -> bool:
1081
1098
)
1082
1099
1083
1100
1084
- def _get_field_type_hints (
1085
- field : dataclasses .Field ,
1086
- schema_ctx : Optional [_SchemaContext ] = None ,
1087
- ) -> type :
1088
- """typing.get_type_hints doesn't work with generic aliasses. But this 'hack' works."""
1089
-
1090
- class X :
1091
- x : field .type # type: ignore[name-defined]
1092
-
1101
+ def _get_type_hints (
1102
+ obj ,
1103
+ schema_ctx : _SchemaContext ,
1104
+ ):
1093
1105
if sys .version_info >= (3 , 9 ):
1094
1106
type_hints = get_type_hints (
1095
- X ,
1107
+ obj ,
1096
1108
globalns = schema_ctx .globalns ,
1097
1109
localns = schema_ctx .localns ,
1098
1110
include_extras = True ,
1099
- )[ "x" ]
1111
+ )
1100
1112
else :
1101
1113
type_hints = get_type_hints (
1102
- X , globalns = schema_ctx .globalns , localns = schema_ctx .localns
1103
- )[ "x" ]
1114
+ obj , globalns = schema_ctx .globalns , localns = schema_ctx .localns
1115
+ )
1104
1116
1105
1117
return type_hints
1106
1118
1107
1119
1120
+ def _get_generic_type_hints (
1121
+ obj ,
1122
+ schema_ctx : _SchemaContext ,
1123
+ ) -> type :
1124
+ """typing.get_type_hints doesn't work with generic aliasses. But this 'hack' works."""
1125
+
1126
+ class X :
1127
+ x : obj # type: ignore[name-defined]
1128
+
1129
+ return _get_type_hints (X , schema_ctx )["x" ]
1130
+
1131
+
1108
1132
def _is_generic_alias (clazz : type ) -> bool :
1109
1133
"""
1110
1134
Check if given class is a generic alias of a class is
0 commit comments