39
39
AnyMethod ,
40
40
BoolMethod ,
41
41
CoercerMethod ,
42
- CollectionMethod ,
42
+ ListMethod ,
43
+ ListCheckOnlyMethod ,
43
44
ConstrainedFloatMethod ,
44
45
ConstrainedIntMethod ,
45
46
ConstrainedStrMethod ,
55
56
IntMethod ,
56
57
LiteralMethod ,
57
58
MappingMethod ,
59
+ MappingCheckOnly ,
58
60
NoneMethod ,
59
61
ObjectMethod ,
60
62
OptionalMethod ,
61
63
PatternField ,
62
64
RecMethod ,
63
65
SetMethod ,
66
+ SimpleObjectMethod ,
64
67
StrMethod ,
65
68
SubprimitiveMethod ,
66
69
TupleMethod ,
107
110
Factory = Callable [[Optional [Constraints ], Sequence [Validator ]], DeserializationMethod ]
108
111
109
112
JSON_TYPES = {dict , list , * PRIMITIVE_TYPES }
113
+ # FloatMethod can require "copy", because it can cast integer to float
114
+ CHECK_ONLY_METHODS = (
115
+ NoneMethod ,
116
+ BoolMethod ,
117
+ IntMethod ,
118
+ StrMethod ,
119
+ ListCheckOnlyMethod ,
120
+ MappingCheckOnly ,
121
+ )
122
+
123
+
124
+ def check_only (method : DeserializationMethod ) -> bool :
125
+ return (
126
+ isinstance (method , CHECK_ONLY_METHODS )
127
+ or (
128
+ isinstance (method , OptionalMethod )
129
+ and method .coercer is None
130
+ and check_only (method .value_method )
131
+ )
132
+ or (
133
+ isinstance (method , UnionMethod ) and all (map (check_only , method .alt_methods ))
134
+ )
135
+ or (
136
+ isinstance (method , UnionByTypeMethod )
137
+ and all (map (check_only , method .method_by_cls .values ()))
138
+ )
139
+ or (isinstance (method , TypeCheckMethod ) and check_only (method .fallback ))
140
+ )
110
141
111
142
112
143
@dataclass (frozen = True )
@@ -190,14 +221,16 @@ def __init__(
190
221
coercer : Optional [Coercer ],
191
222
default_conversion : DefaultConversion ,
192
223
fall_back_on_default : bool ,
224
+ no_copy : bool ,
193
225
):
194
226
super ().__init__ (default_conversion )
195
227
self .additional_properties = additional_properties
196
228
self .aliaser = aliaser
197
- self .coercer = coercer
198
- self .fall_back_on_default = fall_back_on_default
199
229
self .allowed_types = allowed_types
200
230
self .allow_type = as_predicate (allowed_types )
231
+ self .coercer = coercer
232
+ self .fall_back_on_default = fall_back_on_default
233
+ self .no_copy = no_copy
201
234
202
235
def _recursive_result (
203
236
self , lazy : Lazy [DeserializationMethodFactory ]
@@ -219,6 +252,7 @@ def visit_not_recursive(self, tp: AnyType) -> DeserializationMethodFactory:
219
252
self ._conversion ,
220
253
self .default_conversion ,
221
254
self .fall_back_on_default ,
255
+ self .no_copy ,
222
256
)
223
257
224
258
def annotated (
@@ -266,16 +300,16 @@ def collection(
266
300
value_factory = self .visit (value_type )
267
301
268
302
def factory (constraints : Optional [Constraints ], _ ) -> DeserializationMethod :
269
- method_cls : Type [CollectionMethod ]
303
+ value_method = value_factory .method
304
+ list_constraints = constraints_validators (constraints )[list ]
305
+ method : DeserializationMethod
270
306
if issubclass (cls , collections .abc .Set ):
271
- method_cls = SetMethod
272
- elif isinstance ( cls , tuple ):
273
- method_cls = VariadicTupleMethod
307
+ return SetMethod ( list_constraints , value_method )
308
+ elif self . no_copy and check_only ( value_method ):
309
+ method = ListCheckOnlyMethod ( list_constraints , value_method )
274
310
else :
275
- method_cls = CollectionMethod
276
- return method_cls (
277
- constraints_validators (constraints )[list ], value_factory .method
278
- )
311
+ method = ListMethod (list_constraints , value_method )
312
+ return VariadicTupleMethod (method ) if isinstance (cls , tuple ) else method
279
313
280
314
return self ._factory (factory , list )
281
315
@@ -302,11 +336,12 @@ def mapping(
302
336
key_factory , value_factory = self .visit (key_type ), self .visit (value_type )
303
337
304
338
def factory (constraints : Optional [Constraints ], _ ) -> DeserializationMethod :
305
- return MappingMethod (
306
- constraints_validators (constraints )[dict ],
307
- key_factory .method ,
308
- value_factory .method ,
309
- )
339
+ key_method , value_method = key_factory .method , value_factory .method
340
+ dict_constraints = constraints_validators (constraints )[dict ]
341
+ if self .no_copy and check_only (key_method ) and check_only (value_method ):
342
+ return MappingCheckOnly (dict_constraints , key_method , value_method )
343
+ else :
344
+ return MappingMethod (dict_constraints , key_method , value_method )
310
345
311
346
return self ._factory (factory , dict )
312
347
@@ -380,14 +415,39 @@ def factory(
380
415
fall_back_on_default ,
381
416
)
382
417
)
418
+ object_constraints = constraints_validators (constraints )[dict ]
419
+ all_alliases = set (alias_by_name .values ())
420
+ if (
421
+ not object_constraints
422
+ and not flattened_fields
423
+ and not pattern_fields
424
+ and not additional_field
425
+ and not self .additional_properties
426
+ and not validators
427
+ and not (is_typed_dict (cls ) and self .no_copy )
428
+ and all (
429
+ check_only (f .method )
430
+ and f .alias == f .name
431
+ and not f .fall_back_on_default
432
+ and not f .required_by
433
+ for f in normal_fields
434
+ )
435
+ ):
436
+ return SimpleObjectMethod (
437
+ cls ,
438
+ tuple (normal_fields ),
439
+ all_alliases ,
440
+ settings .errors .missing_property ,
441
+ settings .errors .unexpected_property ,
442
+ )
383
443
return ObjectMethod (
384
444
cls ,
385
- constraints_validators ( constraints )[ dict ] ,
445
+ object_constraints ,
386
446
tuple (normal_fields ),
387
447
tuple (flattened_fields ),
388
448
tuple (pattern_fields ),
389
449
additional_field ,
390
- set ( alias_by_name . values ()) ,
450
+ all_alliases ,
391
451
self .additional_properties ,
392
452
tuple (validators ),
393
453
tuple (
@@ -562,6 +622,7 @@ def deserialization_method_factory(
562
622
conversion : Optional [AnyConversion ],
563
623
default_conversion : DefaultConversion ,
564
624
fall_back_on_default : bool ,
625
+ no_copy : bool ,
565
626
) -> DeserializationMethodFactory :
566
627
return DeserializationMethodVisitor (
567
628
additional_properties ,
@@ -570,6 +631,7 @@ def deserialization_method_factory(
570
631
coercer ,
571
632
default_conversion ,
572
633
fall_back_on_default ,
634
+ no_copy ,
573
635
).visit_with_conv (tp , conversion )
574
636
575
637
@@ -584,6 +646,7 @@ def deserialization_method(
584
646
conversion : AnyConversion = None ,
585
647
default_conversion : DefaultConversion = None ,
586
648
fall_back_on_default : bool = None ,
649
+ no_copy : bool = None ,
587
650
schema : Schema = None ,
588
651
validators : Collection [Callable ] = ()
589
652
) -> Callable [[Any ], T ]:
@@ -601,6 +664,7 @@ def deserialization_method(
601
664
conversion : AnyConversion = None ,
602
665
default_conversion : DefaultConversion = None ,
603
666
fall_back_on_default : bool = None ,
667
+ no_copy : bool = None ,
604
668
schema : Schema = None ,
605
669
validators : Collection [Callable ] = ()
606
670
) -> Callable [[Any ], Any ]:
@@ -617,6 +681,7 @@ def deserialization_method(
617
681
conversion : AnyConversion = None ,
618
682
default_conversion : DefaultConversion = None ,
619
683
fall_back_on_default : bool = None ,
684
+ no_copy : bool = None ,
620
685
schema : Schema = None ,
621
686
validators : Collection [Callable ] = ()
622
687
) -> Callable [[Any ], Any ]:
@@ -640,6 +705,7 @@ def deserialization_method(
640
705
conversion ,
641
706
opt_or (default_conversion , settings .deserialization .default_conversion ),
642
707
opt_or (fall_back_on_default , settings .deserialization .fall_back_on_default ),
708
+ opt_or (no_copy , settings .deserialization .no_copy ),
643
709
)
644
710
.merge (get_constraints (schema ), tuple (map (Validator , validators )))
645
711
.method .deserialize
@@ -658,6 +724,7 @@ def deserialize(
658
724
conversion : AnyConversion = None ,
659
725
default_conversion : DefaultConversion = None ,
660
726
fall_back_on_default : bool = None ,
727
+ no_copy : bool = None ,
661
728
schema : Schema = None ,
662
729
validators : Collection [Callable ] = ()
663
730
) -> T :
@@ -676,6 +743,7 @@ def deserialize(
676
743
conversion : AnyConversion = None ,
677
744
default_conversion : DefaultConversion = None ,
678
745
fall_back_on_default : bool = None ,
746
+ no_copy : bool = None ,
679
747
schema : Schema = None ,
680
748
validators : Collection [Callable ] = ()
681
749
) -> Any :
@@ -700,6 +768,7 @@ def deserialize(
700
768
conversion : AnyConversion = None ,
701
769
default_conversion : DefaultConversion = None ,
702
770
fall_back_on_default : bool = None ,
771
+ no_copy : bool = None ,
703
772
schema : Schema = None ,
704
773
validators : Collection [Callable ] = ()
705
774
) -> Any :
@@ -712,6 +781,7 @@ def deserialize(
712
781
conversion = conversion ,
713
782
default_conversion = default_conversion ,
714
783
fall_back_on_default = fall_back_on_default ,
784
+ no_copy = no_copy ,
715
785
schema = schema ,
716
786
validators = validators ,
717
787
)(data )
0 commit comments