azure-storage-blob 12.23.1__py3-none-any.whl → 12.24.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- azure/storage/blob/_blob_client.py +34 -10
- azure/storage/blob/_blob_client_helpers.py +7 -3
- azure/storage/blob/_blob_service_client.py +1 -1
- azure/storage/blob/_container_client.py +2 -2
- azure/storage/blob/_container_client_helpers.py +4 -4
- azure/storage/blob/_deserialize.py +2 -2
- azure/storage/blob/_encryption.py +2 -0
- azure/storage/blob/_generated/_azure_blob_storage.py +1 -1
- azure/storage/blob/_generated/_configuration.py +2 -2
- azure/storage/blob/_generated/_serialization.py +265 -150
- azure/storage/blob/_generated/aio/_azure_blob_storage.py +1 -1
- azure/storage/blob/_generated/aio/_configuration.py +2 -2
- azure/storage/blob/_generated/aio/operations/_append_blob_operations.py +22 -4
- azure/storage/blob/_generated/aio/operations/_blob_operations.py +116 -26
- azure/storage/blob/_generated/aio/operations/_block_blob_operations.py +40 -6
- azure/storage/blob/_generated/aio/operations/_container_operations.py +36 -18
- azure/storage/blob/_generated/aio/operations/_page_blob_operations.py +32 -9
- azure/storage/blob/_generated/aio/operations/_service_operations.py +16 -8
- azure/storage/blob/_generated/models/_azure_blob_storage_enums.py +1 -0
- azure/storage/blob/_generated/operations/_append_blob_operations.py +34 -8
- azure/storage/blob/_generated/operations/_blob_operations.py +166 -51
- azure/storage/blob/_generated/operations/_block_blob_operations.py +62 -12
- azure/storage/blob/_generated/operations/_container_operations.py +54 -36
- azure/storage/blob/_generated/operations/_page_blob_operations.py +49 -18
- azure/storage/blob/_generated/operations/_service_operations.py +24 -16
- azure/storage/blob/_list_blobs_helper.py +1 -1
- azure/storage/blob/_models.py +4 -3
- azure/storage/blob/_serialize.py +1 -0
- azure/storage/blob/_shared/avro/schema.py +1 -0
- azure/storage/blob/_shared/base_client.py +8 -8
- azure/storage/blob/_shared/base_client_async.py +5 -5
- azure/storage/blob/_shared/models.py +5 -2
- azure/storage/blob/_shared/policies.py +6 -7
- azure/storage/blob/_shared/policies_async.py +1 -1
- azure/storage/blob/_shared/request_handlers.py +2 -3
- azure/storage/blob/_shared/response_handlers.py +2 -2
- azure/storage/blob/_shared/uploads.py +4 -4
- azure/storage/blob/_shared/uploads_async.py +4 -4
- azure/storage/blob/_shared_access_signature.py +0 -1
- azure/storage/blob/_version.py +1 -1
- azure/storage/blob/aio/_blob_client_async.py +36 -13
- azure/storage/blob/aio/_blob_service_client_async.py +7 -3
- azure/storage/blob/aio/_container_client_async.py +4 -4
- azure/storage/blob/aio/_lease_async.py +1 -1
- azure/storage/blob/aio/_list_blobs_helper.py +1 -2
- azure/storage/blob/aio/_models.py +1 -2
- {azure_storage_blob-12.23.1.dist-info → azure_storage_blob-12.24.0.dist-info}/METADATA +9 -9
- azure_storage_blob-12.24.0.dist-info/RECORD +84 -0
- {azure_storage_blob-12.23.1.dist-info → azure_storage_blob-12.24.0.dist-info}/WHEEL +1 -1
- azure_storage_blob-12.23.1.dist-info/RECORD +0 -84
- {azure_storage_blob-12.23.1.dist-info → azure_storage_blob-12.24.0.dist-info}/LICENSE +0 -0
- {azure_storage_blob-12.23.1.dist-info → azure_storage_blob-12.24.0.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
# pylint: disable=too-many-lines
|
1
2
|
# --------------------------------------------------------------------------
|
2
3
|
#
|
3
4
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
@@ -24,7 +25,6 @@
|
|
24
25
|
#
|
25
26
|
# --------------------------------------------------------------------------
|
26
27
|
|
27
|
-
# pylint: skip-file
|
28
28
|
# pyright: reportUnnecessaryTypeIgnoreComment=false
|
29
29
|
|
30
30
|
from base64 import b64decode, b64encode
|
@@ -52,7 +52,6 @@ from typing import (
|
|
52
52
|
MutableMapping,
|
53
53
|
Type,
|
54
54
|
List,
|
55
|
-
Mapping,
|
56
55
|
)
|
57
56
|
|
58
57
|
try:
|
@@ -91,6 +90,8 @@ class RawDeserializer:
|
|
91
90
|
:param data: Input, could be bytes or stream (will be decoded with UTF8) or text
|
92
91
|
:type data: str or bytes or IO
|
93
92
|
:param str content_type: The content type.
|
93
|
+
:return: The deserialized data.
|
94
|
+
:rtype: object
|
94
95
|
"""
|
95
96
|
if hasattr(data, "read"):
|
96
97
|
# Assume a stream
|
@@ -112,7 +113,7 @@ class RawDeserializer:
|
|
112
113
|
try:
|
113
114
|
return json.loads(data_as_str)
|
114
115
|
except ValueError as err:
|
115
|
-
raise DeserializationError("JSON is invalid: {}".format(err), err)
|
116
|
+
raise DeserializationError("JSON is invalid: {}".format(err), err) from err
|
116
117
|
elif "xml" in (content_type or []):
|
117
118
|
try:
|
118
119
|
|
@@ -155,6 +156,11 @@ class RawDeserializer:
|
|
155
156
|
Use bytes and headers to NOT use any requests/aiohttp or whatever
|
156
157
|
specific implementation.
|
157
158
|
Headers will tested for "content-type"
|
159
|
+
|
160
|
+
:param bytes body_bytes: The body of the response.
|
161
|
+
:param dict headers: The headers of the response.
|
162
|
+
:returns: The deserialized data.
|
163
|
+
:rtype: object
|
158
164
|
"""
|
159
165
|
# Try to use content-type from headers if available
|
160
166
|
content_type = None
|
@@ -184,15 +190,30 @@ class UTC(datetime.tzinfo):
|
|
184
190
|
"""Time Zone info for handling UTC"""
|
185
191
|
|
186
192
|
def utcoffset(self, dt):
|
187
|
-
"""UTF offset for UTC is 0.
|
193
|
+
"""UTF offset for UTC is 0.
|
194
|
+
|
195
|
+
:param datetime.datetime dt: The datetime
|
196
|
+
:returns: The offset
|
197
|
+
:rtype: datetime.timedelta
|
198
|
+
"""
|
188
199
|
return datetime.timedelta(0)
|
189
200
|
|
190
201
|
def tzname(self, dt):
|
191
|
-
"""Timestamp representation.
|
202
|
+
"""Timestamp representation.
|
203
|
+
|
204
|
+
:param datetime.datetime dt: The datetime
|
205
|
+
:returns: The timestamp representation
|
206
|
+
:rtype: str
|
207
|
+
"""
|
192
208
|
return "Z"
|
193
209
|
|
194
210
|
def dst(self, dt):
|
195
|
-
"""No daylight saving for UTC.
|
211
|
+
"""No daylight saving for UTC.
|
212
|
+
|
213
|
+
:param datetime.datetime dt: The datetime
|
214
|
+
:returns: The daylight saving time
|
215
|
+
:rtype: datetime.timedelta
|
216
|
+
"""
|
196
217
|
return datetime.timedelta(hours=1)
|
197
218
|
|
198
219
|
|
@@ -235,24 +256,26 @@ except ImportError:
|
|
235
256
|
_FLATTEN = re.compile(r"(?<!\\)\.")
|
236
257
|
|
237
258
|
|
238
|
-
def attribute_transformer(key, attr_desc, value):
|
259
|
+
def attribute_transformer(key, attr_desc, value): # pylint: disable=unused-argument
|
239
260
|
"""A key transformer that returns the Python attribute.
|
240
261
|
|
241
262
|
:param str key: The attribute name
|
242
263
|
:param dict attr_desc: The attribute metadata
|
243
264
|
:param object value: The value
|
244
265
|
:returns: A key using attribute name
|
266
|
+
:rtype: str
|
245
267
|
"""
|
246
268
|
return (key, value)
|
247
269
|
|
248
270
|
|
249
|
-
def full_restapi_key_transformer(key, attr_desc, value):
|
271
|
+
def full_restapi_key_transformer(key, attr_desc, value): # pylint: disable=unused-argument
|
250
272
|
"""A key transformer that returns the full RestAPI key path.
|
251
273
|
|
252
|
-
:param str
|
274
|
+
:param str key: The attribute name
|
253
275
|
:param dict attr_desc: The attribute metadata
|
254
276
|
:param object value: The value
|
255
277
|
:returns: A list of keys using RestAPI syntax.
|
278
|
+
:rtype: list
|
256
279
|
"""
|
257
280
|
keys = _FLATTEN.split(attr_desc["key"])
|
258
281
|
return ([_decode_attribute_map_key(k) for k in keys], value)
|
@@ -265,19 +288,26 @@ def last_restapi_key_transformer(key, attr_desc, value):
|
|
265
288
|
:param dict attr_desc: The attribute metadata
|
266
289
|
:param object value: The value
|
267
290
|
:returns: The last RestAPI key.
|
291
|
+
:rtype: str
|
268
292
|
"""
|
269
293
|
key, value = full_restapi_key_transformer(key, attr_desc, value)
|
270
294
|
return (key[-1], value)
|
271
295
|
|
272
296
|
|
273
297
|
def _create_xml_node(tag, prefix=None, ns=None):
|
274
|
-
"""Create a XML node.
|
298
|
+
"""Create a XML node.
|
299
|
+
|
300
|
+
:param str tag: The tag name
|
301
|
+
:param str prefix: The prefix
|
302
|
+
:param str ns: The namespace
|
303
|
+
:return: The XML node
|
304
|
+
:rtype: xml.etree.ElementTree.Element
|
305
|
+
"""
|
275
306
|
if prefix and ns:
|
276
307
|
ET.register_namespace(prefix, ns)
|
277
308
|
if ns:
|
278
309
|
return ET.Element("{" + ns + "}" + tag)
|
279
|
-
|
280
|
-
return ET.Element(tag)
|
310
|
+
return ET.Element(tag)
|
281
311
|
|
282
312
|
|
283
313
|
class Model(object):
|
@@ -291,7 +321,7 @@ class Model(object):
|
|
291
321
|
|
292
322
|
def __init__(self, **kwargs: Any) -> None:
|
293
323
|
self.additional_properties: Optional[Dict[str, Any]] = {}
|
294
|
-
for k in kwargs:
|
324
|
+
for k in kwargs: # pylint: disable=consider-using-dict-items
|
295
325
|
if k not in self._attribute_map:
|
296
326
|
_LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__)
|
297
327
|
elif k in self._validation and self._validation[k].get("readonly", False):
|
@@ -300,13 +330,23 @@ class Model(object):
|
|
300
330
|
setattr(self, k, kwargs[k])
|
301
331
|
|
302
332
|
def __eq__(self, other: Any) -> bool:
|
303
|
-
"""Compare objects by comparing all attributes.
|
333
|
+
"""Compare objects by comparing all attributes.
|
334
|
+
|
335
|
+
:param object other: The object to compare
|
336
|
+
:returns: True if objects are equal
|
337
|
+
:rtype: bool
|
338
|
+
"""
|
304
339
|
if isinstance(other, self.__class__):
|
305
340
|
return self.__dict__ == other.__dict__
|
306
341
|
return False
|
307
342
|
|
308
343
|
def __ne__(self, other: Any) -> bool:
|
309
|
-
"""Compare objects by comparing all attributes.
|
344
|
+
"""Compare objects by comparing all attributes.
|
345
|
+
|
346
|
+
:param object other: The object to compare
|
347
|
+
:returns: True if objects are not equal
|
348
|
+
:rtype: bool
|
349
|
+
"""
|
310
350
|
return not self.__eq__(other)
|
311
351
|
|
312
352
|
def __str__(self) -> str:
|
@@ -326,7 +366,11 @@ class Model(object):
|
|
326
366
|
|
327
367
|
@classmethod
|
328
368
|
def _create_xml_node(cls):
|
329
|
-
"""Create XML node.
|
369
|
+
"""Create XML node.
|
370
|
+
|
371
|
+
:returns: The XML node
|
372
|
+
:rtype: xml.etree.ElementTree.Element
|
373
|
+
"""
|
330
374
|
try:
|
331
375
|
xml_map = cls._xml_map # type: ignore
|
332
376
|
except AttributeError:
|
@@ -346,7 +390,9 @@ class Model(object):
|
|
346
390
|
:rtype: dict
|
347
391
|
"""
|
348
392
|
serializer = Serializer(self._infer_class_models())
|
349
|
-
return serializer._serialize(
|
393
|
+
return serializer._serialize( # type: ignore # pylint: disable=protected-access
|
394
|
+
self, keep_readonly=keep_readonly, **kwargs
|
395
|
+
)
|
350
396
|
|
351
397
|
def as_dict(
|
352
398
|
self,
|
@@ -380,12 +426,15 @@ class Model(object):
|
|
380
426
|
|
381
427
|
If you want XML serialization, you can pass the kwargs is_xml=True.
|
382
428
|
|
429
|
+
:param bool keep_readonly: If you want to serialize the readonly attributes
|
383
430
|
:param function key_transformer: A key transformer function.
|
384
431
|
:returns: A dict JSON compatible object
|
385
432
|
:rtype: dict
|
386
433
|
"""
|
387
434
|
serializer = Serializer(self._infer_class_models())
|
388
|
-
return serializer._serialize(
|
435
|
+
return serializer._serialize( # type: ignore # pylint: disable=protected-access
|
436
|
+
self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs
|
437
|
+
)
|
389
438
|
|
390
439
|
@classmethod
|
391
440
|
def _infer_class_models(cls):
|
@@ -395,7 +444,7 @@ class Model(object):
|
|
395
444
|
client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)}
|
396
445
|
if cls.__name__ not in client_models:
|
397
446
|
raise ValueError("Not Autorest generated code")
|
398
|
-
except Exception:
|
447
|
+
except Exception: # pylint: disable=broad-exception-caught
|
399
448
|
# Assume it's not Autorest generated (tests?). Add ourselves as dependencies.
|
400
449
|
client_models = {cls.__name__: cls}
|
401
450
|
return client_models
|
@@ -408,6 +457,7 @@ class Model(object):
|
|
408
457
|
:param str content_type: JSON by default, set application/xml if XML.
|
409
458
|
:returns: An instance of this model
|
410
459
|
:raises: DeserializationError if something went wrong
|
460
|
+
:rtype: ModelType
|
411
461
|
"""
|
412
462
|
deserializer = Deserializer(cls._infer_class_models())
|
413
463
|
return deserializer(cls.__name__, data, content_type=content_type) # type: ignore
|
@@ -426,9 +476,11 @@ class Model(object):
|
|
426
476
|
and last_rest_key_case_insensitive_extractor)
|
427
477
|
|
428
478
|
:param dict data: A dict using RestAPI structure
|
479
|
+
:param function key_extractors: A key extractor function.
|
429
480
|
:param str content_type: JSON by default, set application/xml if XML.
|
430
481
|
:returns: An instance of this model
|
431
482
|
:raises: DeserializationError if something went wrong
|
483
|
+
:rtype: ModelType
|
432
484
|
"""
|
433
485
|
deserializer = Deserializer(cls._infer_class_models())
|
434
486
|
deserializer.key_extractors = ( # type: ignore
|
@@ -448,7 +500,7 @@ class Model(object):
|
|
448
500
|
return {}
|
449
501
|
result = dict(cls._subtype_map[key])
|
450
502
|
for valuetype in cls._subtype_map[key].values():
|
451
|
-
result.update(objects[valuetype]._flatten_subtype(key, objects))
|
503
|
+
result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access
|
452
504
|
return result
|
453
505
|
|
454
506
|
@classmethod
|
@@ -456,6 +508,11 @@ class Model(object):
|
|
456
508
|
"""Check the class _subtype_map for any child classes.
|
457
509
|
We want to ignore any inherited _subtype_maps.
|
458
510
|
Remove the polymorphic key from the initial data.
|
511
|
+
|
512
|
+
:param dict response: The initial data
|
513
|
+
:param dict objects: The class objects
|
514
|
+
:returns: The class to be used
|
515
|
+
:rtype: class
|
459
516
|
"""
|
460
517
|
for subtype_key in cls.__dict__.get("_subtype_map", {}).keys():
|
461
518
|
subtype_value = None
|
@@ -501,11 +558,13 @@ def _decode_attribute_map_key(key):
|
|
501
558
|
inside the received data.
|
502
559
|
|
503
560
|
:param str key: A key string from the generated code
|
561
|
+
:returns: The decoded key
|
562
|
+
:rtype: str
|
504
563
|
"""
|
505
564
|
return key.replace("\\.", ".")
|
506
565
|
|
507
566
|
|
508
|
-
class Serializer(object):
|
567
|
+
class Serializer(object): # pylint: disable=too-many-public-methods
|
509
568
|
"""Request object model serializer."""
|
510
569
|
|
511
570
|
basic_types = {str: "str", int: "int", bool: "bool", float: "float"}
|
@@ -560,13 +619,16 @@ class Serializer(object):
|
|
560
619
|
self.key_transformer = full_restapi_key_transformer
|
561
620
|
self.client_side_validation = True
|
562
621
|
|
563
|
-
def _serialize(
|
622
|
+
def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals
|
623
|
+
self, target_obj, data_type=None, **kwargs
|
624
|
+
):
|
564
625
|
"""Serialize data into a string according to type.
|
565
626
|
|
566
|
-
:param target_obj: The data to be serialized.
|
627
|
+
:param object target_obj: The data to be serialized.
|
567
628
|
:param str data_type: The type to be serialized from.
|
568
629
|
:rtype: str, dict
|
569
630
|
:raises: SerializationError if serialization fails.
|
631
|
+
:returns: The serialized data.
|
570
632
|
"""
|
571
633
|
key_transformer = kwargs.get("key_transformer", self.key_transformer)
|
572
634
|
keep_readonly = kwargs.get("keep_readonly", False)
|
@@ -592,12 +654,14 @@ class Serializer(object):
|
|
592
654
|
|
593
655
|
serialized = {}
|
594
656
|
if is_xml_model_serialization:
|
595
|
-
serialized = target_obj._create_xml_node()
|
657
|
+
serialized = target_obj._create_xml_node() # pylint: disable=protected-access
|
596
658
|
try:
|
597
|
-
attributes = target_obj._attribute_map
|
659
|
+
attributes = target_obj._attribute_map # pylint: disable=protected-access
|
598
660
|
for attr, attr_desc in attributes.items():
|
599
661
|
attr_name = attr
|
600
|
-
if not keep_readonly and target_obj._validation.get(
|
662
|
+
if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access
|
663
|
+
attr_name, {}
|
664
|
+
).get("readonly", False):
|
601
665
|
continue
|
602
666
|
|
603
667
|
if attr_name == "additional_properties" and attr_desc["key"] == "":
|
@@ -633,7 +697,8 @@ class Serializer(object):
|
|
633
697
|
if isinstance(new_attr, list):
|
634
698
|
serialized.extend(new_attr) # type: ignore
|
635
699
|
elif isinstance(new_attr, ET.Element):
|
636
|
-
# If the down XML has no XML/Name,
|
700
|
+
# If the down XML has no XML/Name,
|
701
|
+
# we MUST replace the tag with the local tag. But keeping the namespaces.
|
637
702
|
if "name" not in getattr(orig_attr, "_xml_map", {}):
|
638
703
|
splitted_tag = new_attr.tag.split("}")
|
639
704
|
if len(splitted_tag) == 2: # Namespace
|
@@ -664,17 +729,17 @@ class Serializer(object):
|
|
664
729
|
except (AttributeError, KeyError, TypeError) as err:
|
665
730
|
msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj))
|
666
731
|
raise SerializationError(msg) from err
|
667
|
-
|
668
|
-
return serialized
|
732
|
+
return serialized
|
669
733
|
|
670
734
|
def body(self, data, data_type, **kwargs):
|
671
735
|
"""Serialize data intended for a request body.
|
672
736
|
|
673
|
-
:param data: The data to be serialized.
|
737
|
+
:param object data: The data to be serialized.
|
674
738
|
:param str data_type: The type to be serialized from.
|
675
739
|
:rtype: dict
|
676
740
|
:raises: SerializationError if serialization fails.
|
677
741
|
:raises: ValueError if data is None
|
742
|
+
:returns: The serialized request body
|
678
743
|
"""
|
679
744
|
|
680
745
|
# Just in case this is a dict
|
@@ -703,7 +768,7 @@ class Serializer(object):
|
|
703
768
|
attribute_key_case_insensitive_extractor,
|
704
769
|
last_rest_key_case_insensitive_extractor,
|
705
770
|
]
|
706
|
-
data = deserializer._deserialize(data_type, data)
|
771
|
+
data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access
|
707
772
|
except DeserializationError as err:
|
708
773
|
raise SerializationError("Unable to build a model: " + str(err)) from err
|
709
774
|
|
@@ -712,9 +777,11 @@ class Serializer(object):
|
|
712
777
|
def url(self, name, data, data_type, **kwargs):
|
713
778
|
"""Serialize data intended for a URL path.
|
714
779
|
|
715
|
-
:param
|
780
|
+
:param str name: The name of the URL path parameter.
|
781
|
+
:param object data: The data to be serialized.
|
716
782
|
:param str data_type: The type to be serialized from.
|
717
783
|
:rtype: str
|
784
|
+
:returns: The serialized URL path
|
718
785
|
:raises: TypeError if serialization fails.
|
719
786
|
:raises: ValueError if data is None
|
720
787
|
"""
|
@@ -728,21 +795,20 @@ class Serializer(object):
|
|
728
795
|
output = output.replace("{", quote("{")).replace("}", quote("}"))
|
729
796
|
else:
|
730
797
|
output = quote(str(output), safe="")
|
731
|
-
except SerializationError:
|
732
|
-
raise TypeError("{} must be type {}.".format(name, data_type))
|
733
|
-
|
734
|
-
return output
|
798
|
+
except SerializationError as exc:
|
799
|
+
raise TypeError("{} must be type {}.".format(name, data_type)) from exc
|
800
|
+
return output
|
735
801
|
|
736
802
|
def query(self, name, data, data_type, **kwargs):
|
737
803
|
"""Serialize data intended for a URL query.
|
738
804
|
|
739
|
-
:param
|
805
|
+
:param str name: The name of the query parameter.
|
806
|
+
:param object data: The data to be serialized.
|
740
807
|
:param str data_type: The type to be serialized from.
|
741
|
-
:keyword bool skip_quote: Whether to skip quote the serialized result.
|
742
|
-
Defaults to False.
|
743
808
|
:rtype: str, list
|
744
809
|
:raises: TypeError if serialization fails.
|
745
810
|
:raises: ValueError if data is None
|
811
|
+
:returns: The serialized query parameter
|
746
812
|
"""
|
747
813
|
try:
|
748
814
|
# Treat the list aside, since we don't want to encode the div separator
|
@@ -759,19 +825,20 @@ class Serializer(object):
|
|
759
825
|
output = str(output)
|
760
826
|
else:
|
761
827
|
output = quote(str(output), safe="")
|
762
|
-
except SerializationError:
|
763
|
-
raise TypeError("{} must be type {}.".format(name, data_type))
|
764
|
-
|
765
|
-
return str(output)
|
828
|
+
except SerializationError as exc:
|
829
|
+
raise TypeError("{} must be type {}.".format(name, data_type)) from exc
|
830
|
+
return str(output)
|
766
831
|
|
767
832
|
def header(self, name, data, data_type, **kwargs):
|
768
833
|
"""Serialize data intended for a request header.
|
769
834
|
|
770
|
-
:param
|
835
|
+
:param str name: The name of the header.
|
836
|
+
:param object data: The data to be serialized.
|
771
837
|
:param str data_type: The type to be serialized from.
|
772
838
|
:rtype: str
|
773
839
|
:raises: TypeError if serialization fails.
|
774
840
|
:raises: ValueError if data is None
|
841
|
+
:returns: The serialized header
|
775
842
|
"""
|
776
843
|
try:
|
777
844
|
if data_type in ["[str]"]:
|
@@ -780,21 +847,20 @@ class Serializer(object):
|
|
780
847
|
output = self.serialize_data(data, data_type, **kwargs)
|
781
848
|
if data_type == "bool":
|
782
849
|
output = json.dumps(output)
|
783
|
-
except SerializationError:
|
784
|
-
raise TypeError("{} must be type {}.".format(name, data_type))
|
785
|
-
|
786
|
-
return str(output)
|
850
|
+
except SerializationError as exc:
|
851
|
+
raise TypeError("{} must be type {}.".format(name, data_type)) from exc
|
852
|
+
return str(output)
|
787
853
|
|
788
854
|
def serialize_data(self, data, data_type, **kwargs):
|
789
855
|
"""Serialize generic data according to supplied data type.
|
790
856
|
|
791
|
-
:param data: The data to be serialized.
|
857
|
+
:param object data: The data to be serialized.
|
792
858
|
:param str data_type: The type to be serialized from.
|
793
|
-
:param bool required: Whether it's essential that the data not be
|
794
|
-
empty or None
|
795
859
|
:raises: AttributeError if required data is None.
|
796
860
|
:raises: ValueError if data is None
|
797
861
|
:raises: SerializationError if serialization fails.
|
862
|
+
:returns: The serialized data.
|
863
|
+
:rtype: str, int, float, bool, dict, list
|
798
864
|
"""
|
799
865
|
if data is None:
|
800
866
|
raise ValueError("No value for given attribute")
|
@@ -805,7 +871,7 @@ class Serializer(object):
|
|
805
871
|
if data_type in self.basic_types.values():
|
806
872
|
return self.serialize_basic(data, data_type, **kwargs)
|
807
873
|
|
808
|
-
|
874
|
+
if data_type in self.serialize_type:
|
809
875
|
return self.serialize_type[data_type](data, **kwargs)
|
810
876
|
|
811
877
|
# If dependencies is empty, try with current data class
|
@@ -821,11 +887,10 @@ class Serializer(object):
|
|
821
887
|
except (ValueError, TypeError) as err:
|
822
888
|
msg = "Unable to serialize value: {!r} as type: {!r}."
|
823
889
|
raise SerializationError(msg.format(data, data_type)) from err
|
824
|
-
|
825
|
-
return self._serialize(data, **kwargs)
|
890
|
+
return self._serialize(data, **kwargs)
|
826
891
|
|
827
892
|
@classmethod
|
828
|
-
def _get_custom_serializers(cls, data_type, **kwargs):
|
893
|
+
def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements
|
829
894
|
custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type)
|
830
895
|
if custom_serializer:
|
831
896
|
return custom_serializer
|
@@ -841,23 +906,26 @@ class Serializer(object):
|
|
841
906
|
- basic_types_serializers dict[str, callable] : If set, use the callable as serializer
|
842
907
|
- is_xml bool : If set, use xml_basic_types_serializers
|
843
908
|
|
844
|
-
:param data: Object to be serialized.
|
909
|
+
:param obj data: Object to be serialized.
|
845
910
|
:param str data_type: Type of object in the iterable.
|
911
|
+
:rtype: str, int, float, bool
|
912
|
+
:return: serialized object
|
846
913
|
"""
|
847
914
|
custom_serializer = cls._get_custom_serializers(data_type, **kwargs)
|
848
915
|
if custom_serializer:
|
849
916
|
return custom_serializer(data)
|
850
917
|
if data_type == "str":
|
851
918
|
return cls.serialize_unicode(data)
|
852
|
-
return eval(data_type)(data) # nosec
|
919
|
+
return eval(data_type)(data) # nosec # pylint: disable=eval-used
|
853
920
|
|
854
921
|
@classmethod
|
855
922
|
def serialize_unicode(cls, data):
|
856
923
|
"""Special handling for serializing unicode strings in Py2.
|
857
924
|
Encode to UTF-8 if unicode, otherwise handle as a str.
|
858
925
|
|
859
|
-
:param data: Object to be serialized.
|
926
|
+
:param str data: Object to be serialized.
|
860
927
|
:rtype: str
|
928
|
+
:return: serialized object
|
861
929
|
"""
|
862
930
|
try: # If I received an enum, return its value
|
863
931
|
return data.value
|
@@ -871,8 +939,7 @@ class Serializer(object):
|
|
871
939
|
return data
|
872
940
|
except NameError:
|
873
941
|
return str(data)
|
874
|
-
|
875
|
-
return str(data)
|
942
|
+
return str(data)
|
876
943
|
|
877
944
|
def serialize_iter(self, data, iter_type, div=None, **kwargs):
|
878
945
|
"""Serialize iterable.
|
@@ -882,15 +949,13 @@ class Serializer(object):
|
|
882
949
|
serialization_ctxt['type'] should be same as data_type.
|
883
950
|
- is_xml bool : If set, serialize as XML
|
884
951
|
|
885
|
-
:param list
|
952
|
+
:param list data: Object to be serialized.
|
886
953
|
:param str iter_type: Type of object in the iterable.
|
887
|
-
:param bool required: Whether the objects in the iterable must
|
888
|
-
not be None or empty.
|
889
954
|
:param str div: If set, this str will be used to combine the elements
|
890
955
|
in the iterable into a combined string. Default is 'None'.
|
891
|
-
:keyword bool do_quote: Whether to quote the serialized result of each iterable element.
|
892
956
|
Defaults to False.
|
893
957
|
:rtype: list, str
|
958
|
+
:return: serialized iterable
|
894
959
|
"""
|
895
960
|
if isinstance(data, str):
|
896
961
|
raise SerializationError("Refuse str type as a valid iter type.")
|
@@ -945,9 +1010,8 @@ class Serializer(object):
|
|
945
1010
|
|
946
1011
|
:param dict attr: Object to be serialized.
|
947
1012
|
:param str dict_type: Type of object in the dictionary.
|
948
|
-
:param bool required: Whether the objects in the dictionary must
|
949
|
-
not be None or empty.
|
950
1013
|
:rtype: dict
|
1014
|
+
:return: serialized dictionary
|
951
1015
|
"""
|
952
1016
|
serialization_ctxt = kwargs.get("serialization_ctxt", {})
|
953
1017
|
serialized = {}
|
@@ -971,7 +1035,7 @@ class Serializer(object):
|
|
971
1035
|
|
972
1036
|
return serialized
|
973
1037
|
|
974
|
-
def serialize_object(self, attr, **kwargs):
|
1038
|
+
def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements
|
975
1039
|
"""Serialize a generic object.
|
976
1040
|
This will be handled as a dictionary. If object passed in is not
|
977
1041
|
a basic type (str, int, float, dict, list) it will simply be
|
@@ -979,6 +1043,7 @@ class Serializer(object):
|
|
979
1043
|
|
980
1044
|
:param dict attr: Object to be serialized.
|
981
1045
|
:rtype: dict or str
|
1046
|
+
:return: serialized object
|
982
1047
|
"""
|
983
1048
|
if attr is None:
|
984
1049
|
return None
|
@@ -1003,7 +1068,7 @@ class Serializer(object):
|
|
1003
1068
|
return self.serialize_decimal(attr)
|
1004
1069
|
|
1005
1070
|
# If it's a model or I know this dependency, serialize as a Model
|
1006
|
-
|
1071
|
+
if obj_type in self.dependencies.values() or isinstance(attr, Model):
|
1007
1072
|
return self._serialize(attr)
|
1008
1073
|
|
1009
1074
|
if obj_type == dict:
|
@@ -1034,56 +1099,61 @@ class Serializer(object):
|
|
1034
1099
|
try:
|
1035
1100
|
enum_obj(result) # type: ignore
|
1036
1101
|
return result
|
1037
|
-
except ValueError:
|
1102
|
+
except ValueError as exc:
|
1038
1103
|
for enum_value in enum_obj: # type: ignore
|
1039
1104
|
if enum_value.value.lower() == str(attr).lower():
|
1040
1105
|
return enum_value.value
|
1041
1106
|
error = "{!r} is not valid value for enum {!r}"
|
1042
|
-
raise SerializationError(error.format(attr, enum_obj))
|
1107
|
+
raise SerializationError(error.format(attr, enum_obj)) from exc
|
1043
1108
|
|
1044
1109
|
@staticmethod
|
1045
|
-
def serialize_bytearray(attr, **kwargs):
|
1110
|
+
def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument
|
1046
1111
|
"""Serialize bytearray into base-64 string.
|
1047
1112
|
|
1048
|
-
:param attr: Object to be serialized.
|
1113
|
+
:param str attr: Object to be serialized.
|
1049
1114
|
:rtype: str
|
1115
|
+
:return: serialized base64
|
1050
1116
|
"""
|
1051
1117
|
return b64encode(attr).decode()
|
1052
1118
|
|
1053
1119
|
@staticmethod
|
1054
|
-
def serialize_base64(attr, **kwargs):
|
1120
|
+
def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument
|
1055
1121
|
"""Serialize str into base-64 string.
|
1056
1122
|
|
1057
|
-
:param attr: Object to be serialized.
|
1123
|
+
:param str attr: Object to be serialized.
|
1058
1124
|
:rtype: str
|
1125
|
+
:return: serialized base64
|
1059
1126
|
"""
|
1060
1127
|
encoded = b64encode(attr).decode("ascii")
|
1061
1128
|
return encoded.strip("=").replace("+", "-").replace("/", "_")
|
1062
1129
|
|
1063
1130
|
@staticmethod
|
1064
|
-
def serialize_decimal(attr, **kwargs):
|
1131
|
+
def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument
|
1065
1132
|
"""Serialize Decimal object to float.
|
1066
1133
|
|
1067
|
-
:param attr: Object to be serialized.
|
1134
|
+
:param decimal attr: Object to be serialized.
|
1068
1135
|
:rtype: float
|
1136
|
+
:return: serialized decimal
|
1069
1137
|
"""
|
1070
1138
|
return float(attr)
|
1071
1139
|
|
1072
1140
|
@staticmethod
|
1073
|
-
def serialize_long(attr, **kwargs):
|
1141
|
+
def serialize_long(attr, **kwargs): # pylint: disable=unused-argument
|
1074
1142
|
"""Serialize long (Py2) or int (Py3).
|
1075
1143
|
|
1076
|
-
:param attr: Object to be serialized.
|
1144
|
+
:param int attr: Object to be serialized.
|
1077
1145
|
:rtype: int/long
|
1146
|
+
:return: serialized long
|
1078
1147
|
"""
|
1079
1148
|
return _long_type(attr)
|
1080
1149
|
|
1081
1150
|
@staticmethod
|
1082
|
-
def serialize_date(attr, **kwargs):
|
1151
|
+
def serialize_date(attr, **kwargs): # pylint: disable=unused-argument
|
1083
1152
|
"""Serialize Date object into ISO-8601 formatted string.
|
1084
1153
|
|
1085
1154
|
:param Date attr: Object to be serialized.
|
1086
1155
|
:rtype: str
|
1156
|
+
:return: serialized date
|
1087
1157
|
"""
|
1088
1158
|
if isinstance(attr, str):
|
1089
1159
|
attr = isodate.parse_date(attr)
|
@@ -1091,11 +1161,12 @@ class Serializer(object):
|
|
1091
1161
|
return t
|
1092
1162
|
|
1093
1163
|
@staticmethod
|
1094
|
-
def serialize_time(attr, **kwargs):
|
1164
|
+
def serialize_time(attr, **kwargs): # pylint: disable=unused-argument
|
1095
1165
|
"""Serialize Time object into ISO-8601 formatted string.
|
1096
1166
|
|
1097
1167
|
:param datetime.time attr: Object to be serialized.
|
1098
1168
|
:rtype: str
|
1169
|
+
:return: serialized time
|
1099
1170
|
"""
|
1100
1171
|
if isinstance(attr, str):
|
1101
1172
|
attr = isodate.parse_time(attr)
|
@@ -1105,30 +1176,32 @@ class Serializer(object):
|
|
1105
1176
|
return t
|
1106
1177
|
|
1107
1178
|
@staticmethod
|
1108
|
-
def serialize_duration(attr, **kwargs):
|
1179
|
+
def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument
|
1109
1180
|
"""Serialize TimeDelta object into ISO-8601 formatted string.
|
1110
1181
|
|
1111
1182
|
:param TimeDelta attr: Object to be serialized.
|
1112
1183
|
:rtype: str
|
1184
|
+
:return: serialized duration
|
1113
1185
|
"""
|
1114
1186
|
if isinstance(attr, str):
|
1115
1187
|
attr = isodate.parse_duration(attr)
|
1116
1188
|
return isodate.duration_isoformat(attr)
|
1117
1189
|
|
1118
1190
|
@staticmethod
|
1119
|
-
def serialize_rfc(attr, **kwargs):
|
1191
|
+
def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument
|
1120
1192
|
"""Serialize Datetime object into RFC-1123 formatted string.
|
1121
1193
|
|
1122
1194
|
:param Datetime attr: Object to be serialized.
|
1123
1195
|
:rtype: str
|
1124
1196
|
:raises: TypeError if format invalid.
|
1197
|
+
:return: serialized rfc
|
1125
1198
|
"""
|
1126
1199
|
try:
|
1127
1200
|
if not attr.tzinfo:
|
1128
1201
|
_LOGGER.warning("Datetime with no tzinfo will be considered UTC.")
|
1129
1202
|
utc = attr.utctimetuple()
|
1130
|
-
except AttributeError:
|
1131
|
-
raise TypeError("RFC1123 object must be valid Datetime object.")
|
1203
|
+
except AttributeError as exc:
|
1204
|
+
raise TypeError("RFC1123 object must be valid Datetime object.") from exc
|
1132
1205
|
|
1133
1206
|
return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format(
|
1134
1207
|
Serializer.days[utc.tm_wday],
|
@@ -1141,12 +1214,13 @@ class Serializer(object):
|
|
1141
1214
|
)
|
1142
1215
|
|
1143
1216
|
@staticmethod
|
1144
|
-
def serialize_iso(attr, **kwargs):
|
1217
|
+
def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument
|
1145
1218
|
"""Serialize Datetime object into ISO-8601 formatted string.
|
1146
1219
|
|
1147
1220
|
:param Datetime attr: Object to be serialized.
|
1148
1221
|
:rtype: str
|
1149
1222
|
:raises: SerializationError if format invalid.
|
1223
|
+
:return: serialized iso
|
1150
1224
|
"""
|
1151
1225
|
if isinstance(attr, str):
|
1152
1226
|
attr = isodate.parse_datetime(attr)
|
@@ -1172,13 +1246,14 @@ class Serializer(object):
|
|
1172
1246
|
raise TypeError(msg) from err
|
1173
1247
|
|
1174
1248
|
@staticmethod
|
1175
|
-
def serialize_unix(attr, **kwargs):
|
1249
|
+
def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument
|
1176
1250
|
"""Serialize Datetime object into IntTime format.
|
1177
1251
|
This is represented as seconds.
|
1178
1252
|
|
1179
1253
|
:param Datetime attr: Object to be serialized.
|
1180
1254
|
:rtype: int
|
1181
1255
|
:raises: SerializationError if format invalid
|
1256
|
+
:return: serialied unix
|
1182
1257
|
"""
|
1183
1258
|
if isinstance(attr, int):
|
1184
1259
|
return attr
|
@@ -1186,11 +1261,11 @@ class Serializer(object):
|
|
1186
1261
|
if not attr.tzinfo:
|
1187
1262
|
_LOGGER.warning("Datetime with no tzinfo will be considered UTC.")
|
1188
1263
|
return int(calendar.timegm(attr.utctimetuple()))
|
1189
|
-
except AttributeError:
|
1190
|
-
raise TypeError("Unix time object must be valid Datetime object.")
|
1264
|
+
except AttributeError as exc:
|
1265
|
+
raise TypeError("Unix time object must be valid Datetime object.") from exc
|
1191
1266
|
|
1192
1267
|
|
1193
|
-
def rest_key_extractor(attr, attr_desc, data):
|
1268
|
+
def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument
|
1194
1269
|
key = attr_desc["key"]
|
1195
1270
|
working_data = data
|
1196
1271
|
|
@@ -1211,7 +1286,9 @@ def rest_key_extractor(attr, attr_desc, data):
|
|
1211
1286
|
return working_data.get(key)
|
1212
1287
|
|
1213
1288
|
|
1214
|
-
def rest_key_case_insensitive_extractor(
|
1289
|
+
def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements
|
1290
|
+
attr, attr_desc, data
|
1291
|
+
):
|
1215
1292
|
key = attr_desc["key"]
|
1216
1293
|
working_data = data
|
1217
1294
|
|
@@ -1232,17 +1309,29 @@ def rest_key_case_insensitive_extractor(attr, attr_desc, data):
|
|
1232
1309
|
return attribute_key_case_insensitive_extractor(key, None, working_data)
|
1233
1310
|
|
1234
1311
|
|
1235
|
-
def last_rest_key_extractor(attr, attr_desc, data):
|
1236
|
-
"""Extract the attribute in "data" based on the last part of the JSON path key.
|
1312
|
+
def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument
|
1313
|
+
"""Extract the attribute in "data" based on the last part of the JSON path key.
|
1314
|
+
|
1315
|
+
:param str attr: The attribute to extract
|
1316
|
+
:param dict attr_desc: The attribute description
|
1317
|
+
:param dict data: The data to extract from
|
1318
|
+
:rtype: object
|
1319
|
+
:returns: The extracted attribute
|
1320
|
+
"""
|
1237
1321
|
key = attr_desc["key"]
|
1238
1322
|
dict_keys = _FLATTEN.split(key)
|
1239
1323
|
return attribute_key_extractor(dict_keys[-1], None, data)
|
1240
1324
|
|
1241
1325
|
|
1242
|
-
def last_rest_key_case_insensitive_extractor(attr, attr_desc, data):
|
1326
|
+
def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument
|
1243
1327
|
"""Extract the attribute in "data" based on the last part of the JSON path key.
|
1244
1328
|
|
1245
1329
|
This is the case insensitive version of "last_rest_key_extractor"
|
1330
|
+
:param str attr: The attribute to extract
|
1331
|
+
:param dict attr_desc: The attribute description
|
1332
|
+
:param dict data: The data to extract from
|
1333
|
+
:rtype: object
|
1334
|
+
:returns: The extracted attribute
|
1246
1335
|
"""
|
1247
1336
|
key = attr_desc["key"]
|
1248
1337
|
dict_keys = _FLATTEN.split(key)
|
@@ -1279,7 +1368,7 @@ def _extract_name_from_internal_type(internal_type):
|
|
1279
1368
|
return xml_name
|
1280
1369
|
|
1281
1370
|
|
1282
|
-
def xml_key_extractor(attr, attr_desc, data):
|
1371
|
+
def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements
|
1283
1372
|
if isinstance(data, dict):
|
1284
1373
|
return None
|
1285
1374
|
|
@@ -1331,22 +1420,21 @@ def xml_key_extractor(attr, attr_desc, data):
|
|
1331
1420
|
if is_iter_type:
|
1332
1421
|
if is_wrapped:
|
1333
1422
|
return None # is_wrapped no node, we want None
|
1334
|
-
|
1335
|
-
return [] # not wrapped, assume empty list
|
1423
|
+
return [] # not wrapped, assume empty list
|
1336
1424
|
return None # Assume it's not there, maybe an optional node.
|
1337
1425
|
|
1338
1426
|
# If is_iter_type and not wrapped, return all found children
|
1339
1427
|
if is_iter_type:
|
1340
1428
|
if not is_wrapped:
|
1341
1429
|
return children
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
)
|
1430
|
+
# Iter and wrapped, should have found one node only (the wrap one)
|
1431
|
+
if len(children) != 1:
|
1432
|
+
raise DeserializationError(
|
1433
|
+
"Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( # pylint: disable=line-too-long
|
1434
|
+
xml_name
|
1348
1435
|
)
|
1349
|
-
|
1436
|
+
)
|
1437
|
+
return list(children[0]) # Might be empty list and that's ok.
|
1350
1438
|
|
1351
1439
|
# Here it's not a itertype, we should have found one element only or empty
|
1352
1440
|
if len(children) > 1:
|
@@ -1363,7 +1451,7 @@ class Deserializer(object):
|
|
1363
1451
|
|
1364
1452
|
basic_types = {str: "str", int: "int", bool: "bool", float: "float"}
|
1365
1453
|
|
1366
|
-
valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}
|
1454
|
+
valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?")
|
1367
1455
|
|
1368
1456
|
def __init__(self, classes: Optional[Mapping[str, type]] = None):
|
1369
1457
|
self.deserialize_type = {
|
@@ -1403,11 +1491,12 @@ class Deserializer(object):
|
|
1403
1491
|
:param str content_type: Swagger "produces" if available.
|
1404
1492
|
:raises: DeserializationError if deserialization fails.
|
1405
1493
|
:return: Deserialized object.
|
1494
|
+
:rtype: object
|
1406
1495
|
"""
|
1407
1496
|
data = self._unpack_content(response_data, content_type)
|
1408
1497
|
return self._deserialize(target_obj, data)
|
1409
1498
|
|
1410
|
-
def _deserialize(self, target_obj, data):
|
1499
|
+
def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements
|
1411
1500
|
"""Call the deserializer on a model.
|
1412
1501
|
|
1413
1502
|
Data needs to be already deserialized as JSON or XML ElementTree
|
@@ -1416,12 +1505,13 @@ class Deserializer(object):
|
|
1416
1505
|
:param object data: Object to deserialize.
|
1417
1506
|
:raises: DeserializationError if deserialization fails.
|
1418
1507
|
:return: Deserialized object.
|
1508
|
+
:rtype: object
|
1419
1509
|
"""
|
1420
1510
|
# This is already a model, go recursive just in case
|
1421
1511
|
if hasattr(data, "_attribute_map"):
|
1422
1512
|
constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")]
|
1423
1513
|
try:
|
1424
|
-
for attr, mapconfig in data._attribute_map.items():
|
1514
|
+
for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access
|
1425
1515
|
if attr in constants:
|
1426
1516
|
continue
|
1427
1517
|
value = getattr(data, attr)
|
@@ -1440,13 +1530,13 @@ class Deserializer(object):
|
|
1440
1530
|
|
1441
1531
|
if isinstance(response, str):
|
1442
1532
|
return self.deserialize_data(data, response)
|
1443
|
-
|
1533
|
+
if isinstance(response, type) and issubclass(response, Enum):
|
1444
1534
|
return self.deserialize_enum(data, response)
|
1445
1535
|
|
1446
1536
|
if data is None or data is CoreNull:
|
1447
1537
|
return data
|
1448
1538
|
try:
|
1449
|
-
attributes = response._attribute_map # type: ignore
|
1539
|
+
attributes = response._attribute_map # type: ignore # pylint: disable=protected-access
|
1450
1540
|
d_attrs = {}
|
1451
1541
|
for attr, attr_desc in attributes.items():
|
1452
1542
|
# Check empty string. If it's not empty, someone has a real "additionalProperties"...
|
@@ -1476,9 +1566,8 @@ class Deserializer(object):
|
|
1476
1566
|
except (AttributeError, TypeError, KeyError) as err:
|
1477
1567
|
msg = "Unable to deserialize to object: " + class_name # type: ignore
|
1478
1568
|
raise DeserializationError(msg) from err
|
1479
|
-
|
1480
|
-
|
1481
|
-
return self._instantiate_model(response, d_attrs, additional_properties)
|
1569
|
+
additional_properties = self._build_additional_properties(attributes, data)
|
1570
|
+
return self._instantiate_model(response, d_attrs, additional_properties)
|
1482
1571
|
|
1483
1572
|
def _build_additional_properties(self, attribute_map, data):
|
1484
1573
|
if not self.additional_properties_detection:
|
@@ -1505,6 +1594,8 @@ class Deserializer(object):
|
|
1505
1594
|
|
1506
1595
|
:param str target: The target object type to deserialize to.
|
1507
1596
|
:param str/dict data: The response data to deserialize.
|
1597
|
+
:return: The classified target object and its class name.
|
1598
|
+
:rtype: tuple
|
1508
1599
|
"""
|
1509
1600
|
if target is None:
|
1510
1601
|
return None, None
|
@@ -1516,7 +1607,7 @@ class Deserializer(object):
|
|
1516
1607
|
return target, target
|
1517
1608
|
|
1518
1609
|
try:
|
1519
|
-
target = target._classify(data, self.dependencies) # type: ignore
|
1610
|
+
target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access
|
1520
1611
|
except AttributeError:
|
1521
1612
|
pass # Target is not a Model, no classify
|
1522
1613
|
return target, target.__class__.__name__ # type: ignore
|
@@ -1531,10 +1622,12 @@ class Deserializer(object):
|
|
1531
1622
|
:param str target_obj: The target object type to deserialize to.
|
1532
1623
|
:param str/dict data: The response data to deserialize.
|
1533
1624
|
:param str content_type: Swagger "produces" if available.
|
1625
|
+
:return: Deserialized object.
|
1626
|
+
:rtype: object
|
1534
1627
|
"""
|
1535
1628
|
try:
|
1536
1629
|
return self(target_obj, data, content_type=content_type)
|
1537
|
-
except:
|
1630
|
+
except: # pylint: disable=bare-except
|
1538
1631
|
_LOGGER.debug(
|
1539
1632
|
"Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True
|
1540
1633
|
)
|
@@ -1552,10 +1645,12 @@ class Deserializer(object):
|
|
1552
1645
|
|
1553
1646
|
If raw_data is something else, bypass all logic and return it directly.
|
1554
1647
|
|
1555
|
-
:param raw_data: Data to be processed.
|
1556
|
-
:param content_type: How to parse if raw_data is a string/bytes.
|
1648
|
+
:param obj raw_data: Data to be processed.
|
1649
|
+
:param str content_type: How to parse if raw_data is a string/bytes.
|
1557
1650
|
:raises JSONDecodeError: If JSON is requested and parsing is impossible.
|
1558
1651
|
:raises UnicodeDecodeError: If bytes is not UTF8
|
1652
|
+
:rtype: object
|
1653
|
+
:return: Unpacked content.
|
1559
1654
|
"""
|
1560
1655
|
# Assume this is enough to detect a Pipeline Response without importing it
|
1561
1656
|
context = getattr(raw_data, "context", {})
|
@@ -1579,14 +1674,21 @@ class Deserializer(object):
|
|
1579
1674
|
def _instantiate_model(self, response, attrs, additional_properties=None):
|
1580
1675
|
"""Instantiate a response model passing in deserialized args.
|
1581
1676
|
|
1582
|
-
:param response: The response model class.
|
1583
|
-
:param
|
1677
|
+
:param Response response: The response model class.
|
1678
|
+
:param dict attrs: The deserialized response attributes.
|
1679
|
+
:param dict additional_properties: Additional properties to be set.
|
1680
|
+
:rtype: Response
|
1681
|
+
:return: The instantiated response model.
|
1584
1682
|
"""
|
1585
1683
|
if callable(response):
|
1586
1684
|
subtype = getattr(response, "_subtype_map", {})
|
1587
1685
|
try:
|
1588
|
-
readonly = [
|
1589
|
-
|
1686
|
+
readonly = [
|
1687
|
+
k for k, v in response._validation.items() if v.get("readonly") # pylint: disable=protected-access
|
1688
|
+
]
|
1689
|
+
const = [
|
1690
|
+
k for k, v in response._validation.items() if v.get("constant") # pylint: disable=protected-access
|
1691
|
+
]
|
1590
1692
|
kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const}
|
1591
1693
|
response_obj = response(**kwargs)
|
1592
1694
|
for attr in readonly:
|
@@ -1596,7 +1698,7 @@ class Deserializer(object):
|
|
1596
1698
|
return response_obj
|
1597
1699
|
except TypeError as err:
|
1598
1700
|
msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore
|
1599
|
-
raise DeserializationError(msg + str(err))
|
1701
|
+
raise DeserializationError(msg + str(err)) from err
|
1600
1702
|
else:
|
1601
1703
|
try:
|
1602
1704
|
for attr, value in attrs.items():
|
@@ -1605,15 +1707,16 @@ class Deserializer(object):
|
|
1605
1707
|
except Exception as exp:
|
1606
1708
|
msg = "Unable to populate response model. "
|
1607
1709
|
msg += "Type: {}, Error: {}".format(type(response), exp)
|
1608
|
-
raise DeserializationError(msg)
|
1710
|
+
raise DeserializationError(msg) from exp
|
1609
1711
|
|
1610
|
-
def deserialize_data(self, data, data_type):
|
1712
|
+
def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements
|
1611
1713
|
"""Process data for deserialization according to data type.
|
1612
1714
|
|
1613
1715
|
:param str data: The response string to be deserialized.
|
1614
1716
|
:param str data_type: The type to deserialize to.
|
1615
1717
|
:raises: DeserializationError if deserialization fails.
|
1616
1718
|
:return: Deserialized object.
|
1719
|
+
:rtype: object
|
1617
1720
|
"""
|
1618
1721
|
if data is None:
|
1619
1722
|
return data
|
@@ -1627,7 +1730,11 @@ class Deserializer(object):
|
|
1627
1730
|
if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())):
|
1628
1731
|
return data
|
1629
1732
|
|
1630
|
-
is_a_text_parsing_type = lambda x: x not in [
|
1733
|
+
is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment
|
1734
|
+
"object",
|
1735
|
+
"[]",
|
1736
|
+
r"{}",
|
1737
|
+
]
|
1631
1738
|
if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text:
|
1632
1739
|
return None
|
1633
1740
|
data_val = self.deserialize_type[data_type](data)
|
@@ -1647,14 +1754,14 @@ class Deserializer(object):
|
|
1647
1754
|
msg = "Unable to deserialize response data."
|
1648
1755
|
msg += " Data: {}, {}".format(data, data_type)
|
1649
1756
|
raise DeserializationError(msg) from err
|
1650
|
-
|
1651
|
-
return self._deserialize(obj_type, data)
|
1757
|
+
return self._deserialize(obj_type, data)
|
1652
1758
|
|
1653
1759
|
def deserialize_iter(self, attr, iter_type):
|
1654
1760
|
"""Deserialize an iterable.
|
1655
1761
|
|
1656
1762
|
:param list attr: Iterable to be deserialized.
|
1657
1763
|
:param str iter_type: The type of object in the iterable.
|
1764
|
+
:return: Deserialized iterable.
|
1658
1765
|
:rtype: list
|
1659
1766
|
"""
|
1660
1767
|
if attr is None:
|
@@ -1671,6 +1778,7 @@ class Deserializer(object):
|
|
1671
1778
|
:param dict/list attr: Dictionary to be deserialized. Also accepts
|
1672
1779
|
a list of key, value pairs.
|
1673
1780
|
:param str dict_type: The object type of the items in the dictionary.
|
1781
|
+
:return: Deserialized dictionary.
|
1674
1782
|
:rtype: dict
|
1675
1783
|
"""
|
1676
1784
|
if isinstance(attr, list):
|
@@ -1681,11 +1789,12 @@ class Deserializer(object):
|
|
1681
1789
|
attr = {el.tag: el.text for el in attr}
|
1682
1790
|
return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()}
|
1683
1791
|
|
1684
|
-
def deserialize_object(self, attr, **kwargs):
|
1792
|
+
def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements
|
1685
1793
|
"""Deserialize a generic object.
|
1686
1794
|
This will be handled as a dictionary.
|
1687
1795
|
|
1688
1796
|
:param dict attr: Dictionary to be deserialized.
|
1797
|
+
:return: Deserialized object.
|
1689
1798
|
:rtype: dict
|
1690
1799
|
:raises: TypeError if non-builtin datatype encountered.
|
1691
1800
|
"""
|
@@ -1720,11 +1829,10 @@ class Deserializer(object):
|
|
1720
1829
|
pass
|
1721
1830
|
return deserialized
|
1722
1831
|
|
1723
|
-
|
1724
|
-
|
1725
|
-
raise TypeError(error + str(obj_type))
|
1832
|
+
error = "Cannot deserialize generic object with type: "
|
1833
|
+
raise TypeError(error + str(obj_type))
|
1726
1834
|
|
1727
|
-
def deserialize_basic(self, attr, data_type):
|
1835
|
+
def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements
|
1728
1836
|
"""Deserialize basic builtin data type from string.
|
1729
1837
|
Will attempt to convert to str, int, float and bool.
|
1730
1838
|
This function will also accept '1', '0', 'true' and 'false' as
|
@@ -1732,6 +1840,7 @@ class Deserializer(object):
|
|
1732
1840
|
|
1733
1841
|
:param str attr: response string to be deserialized.
|
1734
1842
|
:param str data_type: deserialization data type.
|
1843
|
+
:return: Deserialized basic type.
|
1735
1844
|
:rtype: str, int, float or bool
|
1736
1845
|
:raises: TypeError if string format is not valid.
|
1737
1846
|
"""
|
@@ -1743,24 +1852,23 @@ class Deserializer(object):
|
|
1743
1852
|
if data_type == "str":
|
1744
1853
|
# None or '', node <a/> is empty string.
|
1745
1854
|
return ""
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
return None
|
1855
|
+
# None or '', node <a/> with a strong type is None.
|
1856
|
+
# Don't try to model "empty bool" or "empty int"
|
1857
|
+
return None
|
1750
1858
|
|
1751
1859
|
if data_type == "bool":
|
1752
1860
|
if attr in [True, False, 1, 0]:
|
1753
1861
|
return bool(attr)
|
1754
|
-
|
1862
|
+
if isinstance(attr, str):
|
1755
1863
|
if attr.lower() in ["true", "1"]:
|
1756
1864
|
return True
|
1757
|
-
|
1865
|
+
if attr.lower() in ["false", "0"]:
|
1758
1866
|
return False
|
1759
1867
|
raise TypeError("Invalid boolean value: {}".format(attr))
|
1760
1868
|
|
1761
1869
|
if data_type == "str":
|
1762
1870
|
return self.deserialize_unicode(attr)
|
1763
|
-
return eval(data_type)(attr) # nosec
|
1871
|
+
return eval(data_type)(attr) # nosec # pylint: disable=eval-used
|
1764
1872
|
|
1765
1873
|
@staticmethod
|
1766
1874
|
def deserialize_unicode(data):
|
@@ -1768,6 +1876,7 @@ class Deserializer(object):
|
|
1768
1876
|
as a string.
|
1769
1877
|
|
1770
1878
|
:param str data: response string to be deserialized.
|
1879
|
+
:return: Deserialized string.
|
1771
1880
|
:rtype: str or unicode
|
1772
1881
|
"""
|
1773
1882
|
# We might be here because we have an enum modeled as string,
|
@@ -1781,8 +1890,7 @@ class Deserializer(object):
|
|
1781
1890
|
return data
|
1782
1891
|
except NameError:
|
1783
1892
|
return str(data)
|
1784
|
-
|
1785
|
-
return str(data)
|
1893
|
+
return str(data)
|
1786
1894
|
|
1787
1895
|
@staticmethod
|
1788
1896
|
def deserialize_enum(data, enum_obj):
|
@@ -1794,6 +1902,7 @@ class Deserializer(object):
|
|
1794
1902
|
:param str data: Response string to be deserialized. If this value is
|
1795
1903
|
None or invalid it will be returned as-is.
|
1796
1904
|
:param Enum enum_obj: Enum object to deserialize to.
|
1905
|
+
:return: Deserialized enum object.
|
1797
1906
|
:rtype: Enum
|
1798
1907
|
"""
|
1799
1908
|
if isinstance(data, enum_obj) or data is None:
|
@@ -1804,9 +1913,9 @@ class Deserializer(object):
|
|
1804
1913
|
# Workaround. We might consider remove it in the future.
|
1805
1914
|
try:
|
1806
1915
|
return list(enum_obj.__members__.values())[data]
|
1807
|
-
except IndexError:
|
1916
|
+
except IndexError as exc:
|
1808
1917
|
error = "{!r} is not a valid index for enum {!r}"
|
1809
|
-
raise DeserializationError(error.format(data, enum_obj))
|
1918
|
+
raise DeserializationError(error.format(data, enum_obj)) from exc
|
1810
1919
|
try:
|
1811
1920
|
return enum_obj(str(data))
|
1812
1921
|
except ValueError:
|
@@ -1822,6 +1931,7 @@ class Deserializer(object):
|
|
1822
1931
|
"""Deserialize string into bytearray.
|
1823
1932
|
|
1824
1933
|
:param str attr: response string to be deserialized.
|
1934
|
+
:return: Deserialized bytearray
|
1825
1935
|
:rtype: bytearray
|
1826
1936
|
:raises: TypeError if string format invalid.
|
1827
1937
|
"""
|
@@ -1834,6 +1944,7 @@ class Deserializer(object):
|
|
1834
1944
|
"""Deserialize base64 encoded string into string.
|
1835
1945
|
|
1836
1946
|
:param str attr: response string to be deserialized.
|
1947
|
+
:return: Deserialized base64 string
|
1837
1948
|
:rtype: bytearray
|
1838
1949
|
:raises: TypeError if string format invalid.
|
1839
1950
|
"""
|
@@ -1849,8 +1960,9 @@ class Deserializer(object):
|
|
1849
1960
|
"""Deserialize string into Decimal object.
|
1850
1961
|
|
1851
1962
|
:param str attr: response string to be deserialized.
|
1852
|
-
:
|
1963
|
+
:return: Deserialized decimal
|
1853
1964
|
:raises: DeserializationError if string format invalid.
|
1965
|
+
:rtype: decimal
|
1854
1966
|
"""
|
1855
1967
|
if isinstance(attr, ET.Element):
|
1856
1968
|
attr = attr.text
|
@@ -1865,6 +1977,7 @@ class Deserializer(object):
|
|
1865
1977
|
"""Deserialize string into long (Py2) or int (Py3).
|
1866
1978
|
|
1867
1979
|
:param str attr: response string to be deserialized.
|
1980
|
+
:return: Deserialized int
|
1868
1981
|
:rtype: long or int
|
1869
1982
|
:raises: ValueError if string format invalid.
|
1870
1983
|
"""
|
@@ -1877,6 +1990,7 @@ class Deserializer(object):
|
|
1877
1990
|
"""Deserialize ISO-8601 formatted string into TimeDelta object.
|
1878
1991
|
|
1879
1992
|
:param str attr: response string to be deserialized.
|
1993
|
+
:return: Deserialized duration
|
1880
1994
|
:rtype: TimeDelta
|
1881
1995
|
:raises: DeserializationError if string format invalid.
|
1882
1996
|
"""
|
@@ -1887,14 +2001,14 @@ class Deserializer(object):
|
|
1887
2001
|
except (ValueError, OverflowError, AttributeError) as err:
|
1888
2002
|
msg = "Cannot deserialize duration object."
|
1889
2003
|
raise DeserializationError(msg) from err
|
1890
|
-
|
1891
|
-
return duration
|
2004
|
+
return duration
|
1892
2005
|
|
1893
2006
|
@staticmethod
|
1894
2007
|
def deserialize_date(attr):
|
1895
2008
|
"""Deserialize ISO-8601 formatted string into Date object.
|
1896
2009
|
|
1897
2010
|
:param str attr: response string to be deserialized.
|
2011
|
+
:return: Deserialized date
|
1898
2012
|
:rtype: Date
|
1899
2013
|
:raises: DeserializationError if string format invalid.
|
1900
2014
|
"""
|
@@ -1910,6 +2024,7 @@ class Deserializer(object):
|
|
1910
2024
|
"""Deserialize ISO-8601 formatted string into time object.
|
1911
2025
|
|
1912
2026
|
:param str attr: response string to be deserialized.
|
2027
|
+
:return: Deserialized time
|
1913
2028
|
:rtype: datetime.time
|
1914
2029
|
:raises: DeserializationError if string format invalid.
|
1915
2030
|
"""
|
@@ -1924,6 +2039,7 @@ class Deserializer(object):
|
|
1924
2039
|
"""Deserialize RFC-1123 formatted string into Datetime object.
|
1925
2040
|
|
1926
2041
|
:param str attr: response string to be deserialized.
|
2042
|
+
:return: Deserialized RFC datetime
|
1927
2043
|
:rtype: Datetime
|
1928
2044
|
:raises: DeserializationError if string format invalid.
|
1929
2045
|
"""
|
@@ -1939,14 +2055,14 @@ class Deserializer(object):
|
|
1939
2055
|
except ValueError as err:
|
1940
2056
|
msg = "Cannot deserialize to rfc datetime object."
|
1941
2057
|
raise DeserializationError(msg) from err
|
1942
|
-
|
1943
|
-
return date_obj
|
2058
|
+
return date_obj
|
1944
2059
|
|
1945
2060
|
@staticmethod
|
1946
2061
|
def deserialize_iso(attr):
|
1947
2062
|
"""Deserialize ISO-8601 formatted string into Datetime object.
|
1948
2063
|
|
1949
2064
|
:param str attr: response string to be deserialized.
|
2065
|
+
:return: Deserialized ISO datetime
|
1950
2066
|
:rtype: Datetime
|
1951
2067
|
:raises: DeserializationError if string format invalid.
|
1952
2068
|
"""
|
@@ -1976,8 +2092,7 @@ class Deserializer(object):
|
|
1976
2092
|
except (ValueError, OverflowError, AttributeError) as err:
|
1977
2093
|
msg = "Cannot deserialize datetime object."
|
1978
2094
|
raise DeserializationError(msg) from err
|
1979
|
-
|
1980
|
-
return date_obj
|
2095
|
+
return date_obj
|
1981
2096
|
|
1982
2097
|
@staticmethod
|
1983
2098
|
def deserialize_unix(attr):
|
@@ -1985,6 +2100,7 @@ class Deserializer(object):
|
|
1985
2100
|
This is represented as seconds.
|
1986
2101
|
|
1987
2102
|
:param int attr: Object to be serialized.
|
2103
|
+
:return: Deserialized datetime
|
1988
2104
|
:rtype: Datetime
|
1989
2105
|
:raises: DeserializationError if format invalid
|
1990
2106
|
"""
|
@@ -1996,5 +2112,4 @@ class Deserializer(object):
|
|
1996
2112
|
except ValueError as err:
|
1997
2113
|
msg = "Cannot deserialize to unix datetime object."
|
1998
2114
|
raise DeserializationError(msg) from err
|
1999
|
-
|
2000
|
-
return date_obj
|
2115
|
+
return date_obj
|