38
38
import re
39
39
import sys
40
40
import codecs
41
- from typing import Optional , Union , AnyStr , IO , Mapping
41
+ from typing import (
42
+ Dict ,
43
+ Any ,
44
+ cast ,
45
+ Optional ,
46
+ Union ,
47
+ AnyStr ,
48
+ IO ,
49
+ Mapping ,
50
+ Callable ,
51
+ TypeVar ,
52
+ MutableMapping ,
53
+ Type ,
54
+ List ,
55
+ Mapping ,
56
+ )
42
57
43
58
try :
44
59
from urllib import quote # type: ignore
48
63
49
64
import isodate # type: ignore
50
65
51
- from typing import Dict , Any , cast
52
-
53
66
from azure .core .exceptions import DeserializationError , SerializationError , raise_with_traceback
67
+ from azure .core .serialization import NULL as AzureCoreNull
54
68
55
69
_BOM = codecs .BOM_UTF8 .decode (encoding = "utf-8" )
56
70
71
+ ModelType = TypeVar ("ModelType" , bound = "Model" )
72
+ JSON = MutableMapping [str , Any ]
73
+
57
74
58
75
class RawDeserializer :
59
76
@@ -277,8 +294,8 @@ class Model(object):
277
294
_attribute_map : Dict [str , Dict [str , Any ]] = {}
278
295
_validation : Dict [str , Dict [str , Any ]] = {}
279
296
280
- def __init__ (self , ** kwargs ) :
281
- self .additional_properties = {}
297
+ def __init__ (self , ** kwargs : Any ) -> None :
298
+ self .additional_properties : Dict [ str , Any ] = {}
282
299
for k in kwargs :
283
300
if k not in self ._attribute_map :
284
301
_LOGGER .warning ("%s is not a known attribute of class %s and will be ignored" , k , self .__class__ )
@@ -287,25 +304,25 @@ def __init__(self, **kwargs):
287
304
else :
288
305
setattr (self , k , kwargs [k ])
289
306
290
- def __eq__ (self , other ) :
307
+ def __eq__ (self , other : Any ) -> bool :
291
308
"""Compare objects by comparing all attributes."""
292
309
if isinstance (other , self .__class__ ):
293
310
return self .__dict__ == other .__dict__
294
311
return False
295
312
296
- def __ne__ (self , other ) :
313
+ def __ne__ (self , other : Any ) -> bool :
297
314
"""Compare objects by comparing all attributes."""
298
315
return not self .__eq__ (other )
299
316
300
- def __str__ (self ):
317
+ def __str__ (self ) -> str :
301
318
return str (self .__dict__ )
302
319
303
320
@classmethod
304
- def enable_additional_properties_sending (cls ):
321
+ def enable_additional_properties_sending (cls ) -> None :
305
322
cls ._attribute_map ["additional_properties" ] = {"key" : "" , "type" : "{object}" }
306
323
307
324
@classmethod
308
- def is_xml_model (cls ):
325
+ def is_xml_model (cls ) -> bool :
309
326
try :
310
327
cls ._xml_map # type: ignore
311
328
except AttributeError :
@@ -322,7 +339,7 @@ def _create_xml_node(cls):
322
339
323
340
return _create_xml_node (xml_map .get ("name" , cls .__name__ ), xml_map .get ("prefix" , None ), xml_map .get ("ns" , None ))
324
341
325
- def serialize (self , keep_readonly = False , ** kwargs ) :
342
+ def serialize (self , keep_readonly : bool = False , ** kwargs : Any ) -> JSON :
326
343
"""Return the JSON that would be sent to azure from this model.
327
344
328
345
This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`.
@@ -336,8 +353,13 @@ def serialize(self, keep_readonly=False, **kwargs):
336
353
serializer = Serializer (self ._infer_class_models ())
337
354
return serializer ._serialize (self , keep_readonly = keep_readonly , ** kwargs )
338
355
339
- def as_dict (self , keep_readonly = True , key_transformer = attribute_transformer , ** kwargs ):
340
- """Return a dict that can be JSONify using json.dump.
356
+ def as_dict (
357
+ self ,
358
+ keep_readonly : bool = True ,
359
+ key_transformer : Callable [[str , Dict [str , Any ], Any ], Any ] = attribute_transformer ,
360
+ ** kwargs : Any
361
+ ) -> JSON :
362
+ """Return a dict that can be serialized using json.dump.
341
363
342
364
Advanced usage might optionally use a callback as parameter:
343
365
@@ -384,7 +406,7 @@ def _infer_class_models(cls):
384
406
return client_models
385
407
386
408
@classmethod
387
- def deserialize (cls , data , content_type = None ):
409
+ def deserialize (cls : Type [ ModelType ] , data : Any , content_type : Optional [ str ] = None ) -> ModelType :
388
410
"""Parse a str using the RestAPI syntax and return a model.
389
411
390
412
:param str data: A str using RestAPI structure. JSON by default.
@@ -396,7 +418,12 @@ def deserialize(cls, data, content_type=None):
396
418
return deserializer (cls .__name__ , data , content_type = content_type )
397
419
398
420
@classmethod
399
- def from_dict (cls , data , key_extractors = None , content_type = None ):
421
+ def from_dict (
422
+ cls : Type [ModelType ],
423
+ data : Any ,
424
+ key_extractors : Optional [Callable [[str , Dict [str , Any ], Any ], Any ]] = None ,
425
+ content_type : Optional [str ] = None ,
426
+ ) -> ModelType :
400
427
"""Parse a dict using given key extractor return a model.
401
428
402
429
By default consider key
@@ -409,8 +436,8 @@ def from_dict(cls, data, key_extractors=None, content_type=None):
409
436
:raises: DeserializationError if something went wrong
410
437
"""
411
438
deserializer = Deserializer (cls ._infer_class_models ())
412
- deserializer .key_extractors = (
413
- [
439
+ deserializer .key_extractors = ( # type: ignore
440
+ [ # type: ignore
414
441
attribute_key_case_insensitive_extractor ,
415
442
rest_key_case_insensitive_extractor ,
416
443
last_rest_key_case_insensitive_extractor ,
@@ -518,7 +545,7 @@ class Serializer(object):
518
545
"multiple" : lambda x , y : x % y != 0 ,
519
546
}
520
547
521
- def __init__ (self , classes = None ):
548
+ def __init__ (self , classes : Optional [ Mapping [ str , Type [ ModelType ]]] = None ):
522
549
self .serialize_type = {
523
550
"iso-8601" : Serializer .serialize_iso ,
524
551
"rfc-1123" : Serializer .serialize_rfc ,
@@ -534,7 +561,7 @@ def __init__(self, classes=None):
534
561
"[]" : self .serialize_iter ,
535
562
"{}" : self .serialize_dict ,
536
563
}
537
- self .dependencies = dict (classes ) if classes else {}
564
+ self .dependencies : Dict [ str , Type [ ModelType ]] = dict (classes ) if classes else {}
538
565
self .key_transformer = full_restapi_key_transformer
539
566
self .client_side_validation = True
540
567
@@ -626,8 +653,7 @@ def _serialize(self, target_obj, data_type=None, **kwargs):
626
653
serialized .append (local_node ) # type: ignore
627
654
else : # JSON
628
655
for k in reversed (keys ): # type: ignore
629
- unflattened = {k : new_attr }
630
- new_attr = unflattened
656
+ new_attr = {k : new_attr }
631
657
632
658
_new_attr = new_attr
633
659
_serialized = serialized
@@ -656,8 +682,8 @@ def body(self, data, data_type, **kwargs):
656
682
"""
657
683
658
684
# Just in case this is a dict
659
- internal_data_type = data_type .strip ("[]{}" )
660
- internal_data_type = self .dependencies .get (internal_data_type , None )
685
+ internal_data_type_str = data_type .strip ("[]{}" )
686
+ internal_data_type = self .dependencies .get (internal_data_type_str , None )
661
687
try :
662
688
is_xml_model_serialization = kwargs ["is_xml" ]
663
689
except KeyError :
@@ -777,6 +803,8 @@ def serialize_data(self, data, data_type, **kwargs):
777
803
raise ValueError ("No value for given attribute" )
778
804
779
805
try :
806
+ if data is AzureCoreNull :
807
+ return None
780
808
if data_type in self .basic_types .values ():
781
809
return self .serialize_basic (data , data_type , ** kwargs )
782
810
@@ -1161,7 +1189,8 @@ def rest_key_extractor(attr, attr_desc, data):
1161
1189
working_data = data
1162
1190
1163
1191
while "." in key :
1164
- dict_keys = _FLATTEN .split (key )
1192
+ # Need the cast, as for some reasons "split" is typed as list[str | Any]
1193
+ dict_keys = cast (List [str ], _FLATTEN .split (key ))
1165
1194
if len (dict_keys ) == 1 :
1166
1195
key = _decode_attribute_map_key (dict_keys [0 ])
1167
1196
break
@@ -1332,7 +1361,7 @@ class Deserializer(object):
1332
1361
1333
1362
valid_date = re .compile (r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}" r"\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?" )
1334
1363
1335
- def __init__ (self , classes = None ):
1364
+ def __init__ (self , classes : Optional [ Mapping [ str , Type [ ModelType ]]] = None ):
1336
1365
self .deserialize_type = {
1337
1366
"iso-8601" : Deserializer .deserialize_iso ,
1338
1367
"rfc-1123" : Deserializer .deserialize_rfc ,
@@ -1352,7 +1381,7 @@ def __init__(self, classes=None):
1352
1381
"duration" : (isodate .Duration , datetime .timedelta ),
1353
1382
"iso-8601" : (datetime .datetime ),
1354
1383
}
1355
- self .dependencies = dict (classes ) if classes else {}
1384
+ self .dependencies : Dict [ str , Type [ ModelType ]] = dict (classes ) if classes else {}
1356
1385
self .key_extractors = [rest_key_extractor , xml_key_extractor ]
1357
1386
# Additional properties only works if the "rest_key_extractor" is used to
1358
1387
# extract the keys. Making it to work whatever the key extractor is too much
@@ -1471,7 +1500,7 @@ def _classify_target(self, target, data):
1471
1500
Once classification has been determined, initialize object.
1472
1501
1473
1502
:param str target: The target object type to deserialize to.
1474
- :param str/dict data: The response data to deseralize .
1503
+ :param str/dict data: The response data to deserialize .
1475
1504
"""
1476
1505
if target is None :
1477
1506
return None , None
@@ -1486,7 +1515,7 @@ def _classify_target(self, target, data):
1486
1515
target = target ._classify (data , self .dependencies )
1487
1516
except AttributeError :
1488
1517
pass # Target is not a Model, no classify
1489
- return target , target .__class__ .__name__
1518
+ return target , target .__class__ .__name__ # type: ignore
1490
1519
1491
1520
def failsafe_deserialize (self , target_obj , data , content_type = None ):
1492
1521
"""Ignores any errors encountered in deserialization,
@@ -1496,7 +1525,7 @@ def failsafe_deserialize(self, target_obj, data, content_type=None):
1496
1525
a deserialization error.
1497
1526
1498
1527
:param str target_obj: The target object type to deserialize to.
1499
- :param str/dict data: The response data to deseralize .
1528
+ :param str/dict data: The response data to deserialize .
1500
1529
:param str content_type: Swagger "produces" if available.
1501
1530
"""
1502
1531
try :
0 commit comments