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