diracx-client 0.0.1a18__py3-none-any.whl → 0.0.1a20__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.
- diracx/client/__init__.py +4 -18
- diracx/client/aio.py +1 -0
- diracx/client/extensions.py +90 -0
- diracx/client/{aio → generated}/__init__.py +2 -2
- diracx/client/{_client.py → generated/_client.py} +7 -6
- diracx/client/{_configuration.py → generated/_configuration.py} +1 -1
- diracx/client/generated/_patch.py +47 -0
- diracx/client/{_serialization.py → generated/_serialization.py} +303 -154
- diracx/client/{_vendor.py → generated/_vendor.py} +1 -1
- diracx/client/generated/aio/__init__.py +21 -0
- diracx/client/{aio → generated/aio}/_client.py +7 -6
- diracx/client/{aio → generated/aio}/_configuration.py +1 -1
- diracx/client/generated/aio/_patch.py +23 -0
- diracx/client/{aio → generated/aio}/_vendor.py +1 -1
- diracx/client/{aio → generated/aio}/operations/__init__.py +2 -2
- diracx/client/{aio → generated/aio}/operations/_operations.py +139 -209
- diracx/client/{models → generated/models}/__init__.py +4 -2
- diracx/client/{models → generated/models}/_enums.py +2 -2
- diracx/client/{models → generated/models}/_models.py +86 -46
- diracx/client/{operations → generated/operations}/__init__.py +2 -2
- diracx/client/{operations → generated/operations}/_operations.py +139 -209
- diracx/client/generated/py.typed +1 -0
- diracx/client/models.py +5 -0
- diracx/client/patches/__init__.py +19 -0
- diracx/client/patches/aio/__init__.py +18 -0
- diracx/client/{aio/_patch.py → patches/aio/utils.py} +25 -19
- diracx/client/{_patch.py → patches/utils.py} +115 -122
- {diracx_client-0.0.1a18.dist-info → diracx_client-0.0.1a20.dist-info}/METADATA +1 -2
- diracx_client-0.0.1a20.dist-info/RECORD +36 -0
- {diracx_client-0.0.1a18.dist-info → diracx_client-0.0.1a20.dist-info}/WHEEL +1 -1
- diracx_client-0.0.1a20.dist-info/entry_points.txt +3 -0
- diracx_client-0.0.1a18.dist-info/RECORD +0 -26
- /diracx/client/{aio → generated/aio}/operations/_patch.py +0 -0
- /diracx/client/{models → generated/models}/_patch.py +0 -0
- /diracx/client/{operations → generated/operations}/_patch.py +0 -0
- {diracx_client-0.0.1a18.dist-info → diracx_client-0.0.1a20.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,6 @@
|
|
24
24
|
#
|
25
25
|
# --------------------------------------------------------------------------
|
26
26
|
|
27
|
-
# pylint: skip-file
|
28
27
|
# pyright: reportUnnecessaryTypeIgnoreComment=false
|
29
28
|
|
30
29
|
from base64 import b64decode, b64encode
|
@@ -52,7 +51,6 @@ from typing import (
|
|
52
51
|
MutableMapping,
|
53
52
|
Type,
|
54
53
|
List,
|
55
|
-
Mapping,
|
56
54
|
)
|
57
55
|
|
58
56
|
try:
|
@@ -93,6 +91,8 @@ class RawDeserializer:
|
|
93
91
|
:param data: Input, could be bytes or stream (will be decoded with UTF8) or text
|
94
92
|
:type data: str or bytes or IO
|
95
93
|
:param str content_type: The content type.
|
94
|
+
:return: The deserialized data.
|
95
|
+
:rtype: object
|
96
96
|
"""
|
97
97
|
if hasattr(data, "read"):
|
98
98
|
# Assume a stream
|
@@ -114,7 +114,9 @@ class RawDeserializer:
|
|
114
114
|
try:
|
115
115
|
return json.loads(data_as_str)
|
116
116
|
except ValueError as err:
|
117
|
-
raise DeserializationError(
|
117
|
+
raise DeserializationError(
|
118
|
+
"JSON is invalid: {}".format(err), err
|
119
|
+
) from err
|
118
120
|
elif "xml" in (content_type or []):
|
119
121
|
try:
|
120
122
|
|
@@ -146,6 +148,8 @@ class RawDeserializer:
|
|
146
148
|
# context otherwise.
|
147
149
|
_LOGGER.critical("Wasn't XML not JSON, failing")
|
148
150
|
raise DeserializationError("XML is invalid") from err
|
151
|
+
elif content_type.startswith("text/"):
|
152
|
+
return data_as_str
|
149
153
|
raise DeserializationError(
|
150
154
|
"Cannot deserialize content-type: {}".format(content_type)
|
151
155
|
)
|
@@ -159,6 +163,11 @@ class RawDeserializer:
|
|
159
163
|
Use bytes and headers to NOT use any requests/aiohttp or whatever
|
160
164
|
specific implementation.
|
161
165
|
Headers will tested for "content-type"
|
166
|
+
|
167
|
+
:param bytes body_bytes: The body of the response.
|
168
|
+
:param dict headers: The headers of the response.
|
169
|
+
:returns: The deserialized data.
|
170
|
+
:rtype: object
|
162
171
|
"""
|
163
172
|
# Try to use content-type from headers if available
|
164
173
|
content_type = None
|
@@ -188,15 +197,30 @@ class UTC(datetime.tzinfo):
|
|
188
197
|
"""Time Zone info for handling UTC"""
|
189
198
|
|
190
199
|
def utcoffset(self, dt):
|
191
|
-
"""UTF offset for UTC is 0.
|
200
|
+
"""UTF offset for UTC is 0.
|
201
|
+
|
202
|
+
:param datetime.datetime dt: The datetime
|
203
|
+
:returns: The offset
|
204
|
+
:rtype: datetime.timedelta
|
205
|
+
"""
|
192
206
|
return datetime.timedelta(0)
|
193
207
|
|
194
208
|
def tzname(self, dt):
|
195
|
-
"""Timestamp representation.
|
209
|
+
"""Timestamp representation.
|
210
|
+
|
211
|
+
:param datetime.datetime dt: The datetime
|
212
|
+
:returns: The timestamp representation
|
213
|
+
:rtype: str
|
214
|
+
"""
|
196
215
|
return "Z"
|
197
216
|
|
198
217
|
def dst(self, dt):
|
199
|
-
"""No daylight saving for UTC.
|
218
|
+
"""No daylight saving for UTC.
|
219
|
+
|
220
|
+
:param datetime.datetime dt: The datetime
|
221
|
+
:returns: The daylight saving time
|
222
|
+
:rtype: datetime.timedelta
|
223
|
+
"""
|
200
224
|
return datetime.timedelta(hours=1)
|
201
225
|
|
202
226
|
|
@@ -210,7 +234,7 @@ except ImportError: # Python 2.7
|
|
210
234
|
:param datetime.timedelta offset: offset in timedelta format
|
211
235
|
"""
|
212
236
|
|
213
|
-
def __init__(self, offset):
|
237
|
+
def __init__(self, offset) -> None:
|
214
238
|
self.__offset = offset
|
215
239
|
|
216
240
|
def utcoffset(self, dt):
|
@@ -239,24 +263,28 @@ except ImportError:
|
|
239
263
|
_FLATTEN = re.compile(r"(?<!\\)\.")
|
240
264
|
|
241
265
|
|
242
|
-
def attribute_transformer(key, attr_desc, value):
|
266
|
+
def attribute_transformer(key, attr_desc, value): # pylint: disable=unused-argument
|
243
267
|
"""A key transformer that returns the Python attribute.
|
244
268
|
|
245
269
|
:param str key: The attribute name
|
246
270
|
:param dict attr_desc: The attribute metadata
|
247
271
|
:param object value: The value
|
248
272
|
:returns: A key using attribute name
|
273
|
+
:rtype: str
|
249
274
|
"""
|
250
275
|
return (key, value)
|
251
276
|
|
252
277
|
|
253
|
-
def full_restapi_key_transformer(
|
278
|
+
def full_restapi_key_transformer(
|
279
|
+
key, attr_desc, value
|
280
|
+
): # pylint: disable=unused-argument
|
254
281
|
"""A key transformer that returns the full RestAPI key path.
|
255
282
|
|
256
|
-
:param str
|
283
|
+
:param str key: The attribute name
|
257
284
|
:param dict attr_desc: The attribute metadata
|
258
285
|
:param object value: The value
|
259
286
|
:returns: A list of keys using RestAPI syntax.
|
287
|
+
:rtype: list
|
260
288
|
"""
|
261
289
|
keys = _FLATTEN.split(attr_desc["key"])
|
262
290
|
return ([_decode_attribute_map_key(k) for k in keys], value)
|
@@ -269,19 +297,26 @@ def last_restapi_key_transformer(key, attr_desc, value):
|
|
269
297
|
:param dict attr_desc: The attribute metadata
|
270
298
|
:param object value: The value
|
271
299
|
:returns: The last RestAPI key.
|
300
|
+
:rtype: str
|
272
301
|
"""
|
273
302
|
key, value = full_restapi_key_transformer(key, attr_desc, value)
|
274
303
|
return (key[-1], value)
|
275
304
|
|
276
305
|
|
277
306
|
def _create_xml_node(tag, prefix=None, ns=None):
|
278
|
-
"""Create a XML node.
|
307
|
+
"""Create a XML node.
|
308
|
+
|
309
|
+
:param str tag: The tag name
|
310
|
+
:param str prefix: The prefix
|
311
|
+
:param str ns: The namespace
|
312
|
+
:return: The XML node
|
313
|
+
:rtype: xml.etree.ElementTree.Element
|
314
|
+
"""
|
279
315
|
if prefix and ns:
|
280
316
|
ET.register_namespace(prefix, ns)
|
281
317
|
if ns:
|
282
318
|
return ET.Element("{" + ns + "}" + tag)
|
283
|
-
|
284
|
-
return ET.Element(tag)
|
319
|
+
return ET.Element(tag)
|
285
320
|
|
286
321
|
|
287
322
|
class Model(object):
|
@@ -295,7 +330,7 @@ class Model(object):
|
|
295
330
|
|
296
331
|
def __init__(self, **kwargs: Any) -> None:
|
297
332
|
self.additional_properties: Optional[Dict[str, Any]] = {}
|
298
|
-
for k in kwargs:
|
333
|
+
for k in kwargs: # pylint: disable=consider-using-dict-items
|
299
334
|
if k not in self._attribute_map:
|
300
335
|
_LOGGER.warning(
|
301
336
|
"%s is not a known attribute of class %s and will be ignored",
|
@@ -312,13 +347,23 @@ class Model(object):
|
|
312
347
|
setattr(self, k, kwargs[k])
|
313
348
|
|
314
349
|
def __eq__(self, other: Any) -> bool:
|
315
|
-
"""Compare objects by comparing all attributes.
|
350
|
+
"""Compare objects by comparing all attributes.
|
351
|
+
|
352
|
+
:param object other: The object to compare
|
353
|
+
:returns: True if objects are equal
|
354
|
+
:rtype: bool
|
355
|
+
"""
|
316
356
|
if isinstance(other, self.__class__):
|
317
357
|
return self.__dict__ == other.__dict__
|
318
358
|
return False
|
319
359
|
|
320
360
|
def __ne__(self, other: Any) -> bool:
|
321
|
-
"""Compare objects by comparing all attributes.
|
361
|
+
"""Compare objects by comparing all attributes.
|
362
|
+
|
363
|
+
:param object other: The object to compare
|
364
|
+
:returns: True if objects are not equal
|
365
|
+
:rtype: bool
|
366
|
+
"""
|
322
367
|
return not self.__eq__(other)
|
323
368
|
|
324
369
|
def __str__(self) -> str:
|
@@ -338,7 +383,11 @@ class Model(object):
|
|
338
383
|
|
339
384
|
@classmethod
|
340
385
|
def _create_xml_node(cls):
|
341
|
-
"""Create XML node.
|
386
|
+
"""Create XML node.
|
387
|
+
|
388
|
+
:returns: The XML node
|
389
|
+
:rtype: xml.etree.ElementTree.Element
|
390
|
+
"""
|
342
391
|
try:
|
343
392
|
xml_map = cls._xml_map # type: ignore
|
344
393
|
except AttributeError:
|
@@ -362,7 +411,9 @@ class Model(object):
|
|
362
411
|
:rtype: dict
|
363
412
|
"""
|
364
413
|
serializer = Serializer(self._infer_class_models())
|
365
|
-
return serializer._serialize(
|
414
|
+
return serializer._serialize( # type: ignore # pylint: disable=protected-access
|
415
|
+
self, keep_readonly=keep_readonly, **kwargs
|
416
|
+
)
|
366
417
|
|
367
418
|
def as_dict(
|
368
419
|
self,
|
@@ -398,12 +449,15 @@ class Model(object):
|
|
398
449
|
|
399
450
|
If you want XML serialization, you can pass the kwargs is_xml=True.
|
400
451
|
|
452
|
+
:param bool keep_readonly: If you want to serialize the readonly attributes
|
401
453
|
:param function key_transformer: A key transformer function.
|
402
454
|
:returns: A dict JSON compatible object
|
403
455
|
:rtype: dict
|
404
456
|
"""
|
405
457
|
serializer = Serializer(self._infer_class_models())
|
406
|
-
return serializer._serialize(
|
458
|
+
return serializer._serialize( # type: ignore # pylint: disable=protected-access
|
459
|
+
self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs
|
460
|
+
)
|
407
461
|
|
408
462
|
@classmethod
|
409
463
|
def _infer_class_models(cls):
|
@@ -415,7 +469,7 @@ class Model(object):
|
|
415
469
|
}
|
416
470
|
if cls.__name__ not in client_models:
|
417
471
|
raise ValueError("Not Autorest generated code")
|
418
|
-
except Exception:
|
472
|
+
except Exception: # pylint: disable=broad-exception-caught
|
419
473
|
# Assume it's not Autorest generated (tests?). Add ourselves as dependencies.
|
420
474
|
client_models = {cls.__name__: cls}
|
421
475
|
return client_models
|
@@ -430,6 +484,7 @@ class Model(object):
|
|
430
484
|
:param str content_type: JSON by default, set application/xml if XML.
|
431
485
|
:returns: An instance of this model
|
432
486
|
:raises: DeserializationError if something went wrong
|
487
|
+
:rtype: ModelType
|
433
488
|
"""
|
434
489
|
deserializer = Deserializer(cls._infer_class_models())
|
435
490
|
return deserializer(cls.__name__, data, content_type=content_type) # type: ignore
|
@@ -448,9 +503,11 @@ class Model(object):
|
|
448
503
|
and last_rest_key_case_insensitive_extractor)
|
449
504
|
|
450
505
|
:param dict data: A dict using RestAPI structure
|
506
|
+
:param function key_extractors: A key extractor function.
|
451
507
|
:param str content_type: JSON by default, set application/xml if XML.
|
452
508
|
:returns: An instance of this model
|
453
509
|
:raises: DeserializationError if something went wrong
|
510
|
+
:rtype: ModelType
|
454
511
|
"""
|
455
512
|
deserializer = Deserializer(cls._infer_class_models())
|
456
513
|
deserializer.key_extractors = ( # type: ignore
|
@@ -470,7 +527,9 @@ class Model(object):
|
|
470
527
|
return {}
|
471
528
|
result = dict(cls._subtype_map[key])
|
472
529
|
for valuetype in cls._subtype_map[key].values():
|
473
|
-
result.update(
|
530
|
+
result.update(
|
531
|
+
objects[valuetype]._flatten_subtype(key, objects)
|
532
|
+
) # pylint: disable=protected-access
|
474
533
|
return result
|
475
534
|
|
476
535
|
@classmethod
|
@@ -478,6 +537,11 @@ class Model(object):
|
|
478
537
|
"""Check the class _subtype_map for any child classes.
|
479
538
|
We want to ignore any inherited _subtype_maps.
|
480
539
|
Remove the polymorphic key from the initial data.
|
540
|
+
|
541
|
+
:param dict response: The initial data
|
542
|
+
:param dict objects: The class objects
|
543
|
+
:returns: The class to be used
|
544
|
+
:rtype: class
|
481
545
|
"""
|
482
546
|
for subtype_key in cls.__dict__.get("_subtype_map", {}).keys():
|
483
547
|
subtype_value = None
|
@@ -531,11 +595,13 @@ def _decode_attribute_map_key(key):
|
|
531
595
|
inside the received data.
|
532
596
|
|
533
597
|
:param str key: A key string from the generated code
|
598
|
+
:returns: The decoded key
|
599
|
+
:rtype: str
|
534
600
|
"""
|
535
601
|
return key.replace("\\.", ".")
|
536
602
|
|
537
603
|
|
538
|
-
class Serializer(object):
|
604
|
+
class Serializer(object): # pylint: disable=too-many-public-methods
|
539
605
|
"""Request object model serializer."""
|
540
606
|
|
541
607
|
basic_types = {str: "str", int: "int", bool: "bool", float: "float"}
|
@@ -570,7 +636,7 @@ class Serializer(object):
|
|
570
636
|
"multiple": lambda x, y: x % y != 0,
|
571
637
|
}
|
572
638
|
|
573
|
-
def __init__(self, classes: Optional[Mapping[str, type]] = None):
|
639
|
+
def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None:
|
574
640
|
self.serialize_type = {
|
575
641
|
"iso-8601": Serializer.serialize_iso,
|
576
642
|
"rfc-1123": Serializer.serialize_rfc,
|
@@ -590,13 +656,16 @@ class Serializer(object):
|
|
590
656
|
self.key_transformer = full_restapi_key_transformer
|
591
657
|
self.client_side_validation = True
|
592
658
|
|
593
|
-
def _serialize(
|
659
|
+
def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals
|
660
|
+
self, target_obj, data_type=None, **kwargs
|
661
|
+
):
|
594
662
|
"""Serialize data into a string according to type.
|
595
663
|
|
596
|
-
:param target_obj: The data to be serialized.
|
664
|
+
:param object target_obj: The data to be serialized.
|
597
665
|
:param str data_type: The type to be serialized from.
|
598
666
|
:rtype: str, dict
|
599
667
|
:raises: SerializationError if serialization fails.
|
668
|
+
:returns: The serialized data.
|
600
669
|
"""
|
601
670
|
key_transformer = kwargs.get("key_transformer", self.key_transformer)
|
602
671
|
keep_readonly = kwargs.get("keep_readonly", False)
|
@@ -624,13 +693,18 @@ class Serializer(object):
|
|
624
693
|
|
625
694
|
serialized = {}
|
626
695
|
if is_xml_model_serialization:
|
627
|
-
serialized =
|
696
|
+
serialized = (
|
697
|
+
target_obj._create_xml_node()
|
698
|
+
) # pylint: disable=protected-access
|
628
699
|
try:
|
629
|
-
attributes = target_obj._attribute_map
|
700
|
+
attributes = target_obj._attribute_map # pylint: disable=protected-access
|
630
701
|
for attr, attr_desc in attributes.items():
|
631
702
|
attr_name = attr
|
632
|
-
if
|
633
|
-
|
703
|
+
if (
|
704
|
+
not keep_readonly
|
705
|
+
and target_obj._validation.get( # pylint: disable=protected-access
|
706
|
+
attr_name, {}
|
707
|
+
).get("readonly", False)
|
634
708
|
):
|
635
709
|
continue
|
636
710
|
|
@@ -671,7 +745,8 @@ class Serializer(object):
|
|
671
745
|
if isinstance(new_attr, list):
|
672
746
|
serialized.extend(new_attr) # type: ignore
|
673
747
|
elif isinstance(new_attr, ET.Element):
|
674
|
-
# If the down XML has no XML/Name,
|
748
|
+
# If the down XML has no XML/Name,
|
749
|
+
# we MUST replace the tag with the local tag. But keeping the namespaces.
|
675
750
|
if "name" not in getattr(orig_attr, "_xml_map", {}):
|
676
751
|
splitted_tag = new_attr.tag.split("}")
|
677
752
|
if len(splitted_tag) == 2: # Namespace
|
@@ -704,17 +779,17 @@ class Serializer(object):
|
|
704
779
|
attr_name, class_name, str(target_obj)
|
705
780
|
)
|
706
781
|
raise SerializationError(msg) from err
|
707
|
-
|
708
|
-
return serialized
|
782
|
+
return serialized
|
709
783
|
|
710
784
|
def body(self, data, data_type, **kwargs):
|
711
785
|
"""Serialize data intended for a request body.
|
712
786
|
|
713
|
-
:param data: The data to be serialized.
|
787
|
+
:param object data: The data to be serialized.
|
714
788
|
:param str data_type: The type to be serialized from.
|
715
789
|
:rtype: dict
|
716
790
|
:raises: SerializationError if serialization fails.
|
717
791
|
:raises: ValueError if data is None
|
792
|
+
:returns: The serialized request body
|
718
793
|
"""
|
719
794
|
|
720
795
|
# Just in case this is a dict
|
@@ -745,7 +820,9 @@ class Serializer(object):
|
|
745
820
|
attribute_key_case_insensitive_extractor,
|
746
821
|
last_rest_key_case_insensitive_extractor,
|
747
822
|
]
|
748
|
-
data = deserializer._deserialize(
|
823
|
+
data = deserializer._deserialize(
|
824
|
+
data_type, data
|
825
|
+
) # pylint: disable=protected-access
|
749
826
|
except DeserializationError as err:
|
750
827
|
raise SerializationError(
|
751
828
|
"Unable to build a model: " + str(err)
|
@@ -756,9 +833,11 @@ class Serializer(object):
|
|
756
833
|
def url(self, name, data, data_type, **kwargs):
|
757
834
|
"""Serialize data intended for a URL path.
|
758
835
|
|
759
|
-
:param
|
836
|
+
:param str name: The name of the URL path parameter.
|
837
|
+
:param object data: The data to be serialized.
|
760
838
|
:param str data_type: The type to be serialized from.
|
761
839
|
:rtype: str
|
840
|
+
:returns: The serialized URL path
|
762
841
|
:raises: TypeError if serialization fails.
|
763
842
|
:raises: ValueError if data is None
|
764
843
|
"""
|
@@ -772,21 +851,20 @@ class Serializer(object):
|
|
772
851
|
output = output.replace("{", quote("{")).replace("}", quote("}"))
|
773
852
|
else:
|
774
853
|
output = quote(str(output), safe="")
|
775
|
-
except SerializationError:
|
776
|
-
raise TypeError("{} must be type {}.".format(name, data_type))
|
777
|
-
|
778
|
-
return output
|
854
|
+
except SerializationError as exc:
|
855
|
+
raise TypeError("{} must be type {}.".format(name, data_type)) from exc
|
856
|
+
return output
|
779
857
|
|
780
858
|
def query(self, name, data, data_type, **kwargs):
|
781
859
|
"""Serialize data intended for a URL query.
|
782
860
|
|
783
|
-
:param
|
861
|
+
:param str name: The name of the query parameter.
|
862
|
+
:param object data: The data to be serialized.
|
784
863
|
:param str data_type: The type to be serialized from.
|
785
|
-
:keyword bool skip_quote: Whether to skip quote the serialized result.
|
786
|
-
Defaults to False.
|
787
864
|
:rtype: str, list
|
788
865
|
:raises: TypeError if serialization fails.
|
789
866
|
:raises: ValueError if data is None
|
867
|
+
:returns: The serialized query parameter
|
790
868
|
"""
|
791
869
|
try:
|
792
870
|
# Treat the list aside, since we don't want to encode the div separator
|
@@ -805,19 +883,20 @@ class Serializer(object):
|
|
805
883
|
output = str(output)
|
806
884
|
else:
|
807
885
|
output = quote(str(output), safe="")
|
808
|
-
except SerializationError:
|
809
|
-
raise TypeError("{} must be type {}.".format(name, data_type))
|
810
|
-
|
811
|
-
return str(output)
|
886
|
+
except SerializationError as exc:
|
887
|
+
raise TypeError("{} must be type {}.".format(name, data_type)) from exc
|
888
|
+
return str(output)
|
812
889
|
|
813
890
|
def header(self, name, data, data_type, **kwargs):
|
814
891
|
"""Serialize data intended for a request header.
|
815
892
|
|
816
|
-
:param
|
893
|
+
:param str name: The name of the header.
|
894
|
+
:param object data: The data to be serialized.
|
817
895
|
:param str data_type: The type to be serialized from.
|
818
896
|
:rtype: str
|
819
897
|
:raises: TypeError if serialization fails.
|
820
898
|
:raises: ValueError if data is None
|
899
|
+
:returns: The serialized header
|
821
900
|
"""
|
822
901
|
try:
|
823
902
|
if data_type in ["[str]"]:
|
@@ -826,21 +905,20 @@ class Serializer(object):
|
|
826
905
|
output = self.serialize_data(data, data_type, **kwargs)
|
827
906
|
if data_type == "bool":
|
828
907
|
output = json.dumps(output)
|
829
|
-
except SerializationError:
|
830
|
-
raise TypeError("{} must be type {}.".format(name, data_type))
|
831
|
-
|
832
|
-
return str(output)
|
908
|
+
except SerializationError as exc:
|
909
|
+
raise TypeError("{} must be type {}.".format(name, data_type)) from exc
|
910
|
+
return str(output)
|
833
911
|
|
834
912
|
def serialize_data(self, data, data_type, **kwargs):
|
835
913
|
"""Serialize generic data according to supplied data type.
|
836
914
|
|
837
|
-
:param data: The data to be serialized.
|
915
|
+
:param object data: The data to be serialized.
|
838
916
|
:param str data_type: The type to be serialized from.
|
839
|
-
:param bool required: Whether it's essential that the data not be
|
840
|
-
empty or None
|
841
917
|
:raises: AttributeError if required data is None.
|
842
918
|
:raises: ValueError if data is None
|
843
919
|
:raises: SerializationError if serialization fails.
|
920
|
+
:returns: The serialized data.
|
921
|
+
:rtype: str, int, float, bool, dict, list
|
844
922
|
"""
|
845
923
|
if data is None:
|
846
924
|
raise ValueError("No value for given attribute")
|
@@ -851,7 +929,7 @@ class Serializer(object):
|
|
851
929
|
if data_type in self.basic_types.values():
|
852
930
|
return self.serialize_basic(data, data_type, **kwargs)
|
853
931
|
|
854
|
-
|
932
|
+
if data_type in self.serialize_type:
|
855
933
|
return self.serialize_type[data_type](data, **kwargs)
|
856
934
|
|
857
935
|
# If dependencies is empty, try with current data class
|
@@ -867,11 +945,12 @@ class Serializer(object):
|
|
867
945
|
except (ValueError, TypeError) as err:
|
868
946
|
msg = "Unable to serialize value: {!r} as type: {!r}."
|
869
947
|
raise SerializationError(msg.format(data, data_type)) from err
|
870
|
-
|
871
|
-
return self._serialize(data, **kwargs)
|
948
|
+
return self._serialize(data, **kwargs)
|
872
949
|
|
873
950
|
@classmethod
|
874
|
-
def _get_custom_serializers(
|
951
|
+
def _get_custom_serializers(
|
952
|
+
cls, data_type, **kwargs
|
953
|
+
): # pylint: disable=inconsistent-return-statements
|
875
954
|
custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type)
|
876
955
|
if custom_serializer:
|
877
956
|
return custom_serializer
|
@@ -887,23 +966,26 @@ class Serializer(object):
|
|
887
966
|
- basic_types_serializers dict[str, callable] : If set, use the callable as serializer
|
888
967
|
- is_xml bool : If set, use xml_basic_types_serializers
|
889
968
|
|
890
|
-
:param data: Object to be serialized.
|
969
|
+
:param obj data: Object to be serialized.
|
891
970
|
:param str data_type: Type of object in the iterable.
|
971
|
+
:rtype: str, int, float, bool
|
972
|
+
:return: serialized object
|
892
973
|
"""
|
893
974
|
custom_serializer = cls._get_custom_serializers(data_type, **kwargs)
|
894
975
|
if custom_serializer:
|
895
976
|
return custom_serializer(data)
|
896
977
|
if data_type == "str":
|
897
978
|
return cls.serialize_unicode(data)
|
898
|
-
return eval(data_type)(data) # nosec
|
979
|
+
return eval(data_type)(data) # nosec # pylint: disable=eval-used
|
899
980
|
|
900
981
|
@classmethod
|
901
982
|
def serialize_unicode(cls, data):
|
902
983
|
"""Special handling for serializing unicode strings in Py2.
|
903
984
|
Encode to UTF-8 if unicode, otherwise handle as a str.
|
904
985
|
|
905
|
-
:param data: Object to be serialized.
|
986
|
+
:param str data: Object to be serialized.
|
906
987
|
:rtype: str
|
988
|
+
:return: serialized object
|
907
989
|
"""
|
908
990
|
try: # If I received an enum, return its value
|
909
991
|
return data.value
|
@@ -917,8 +999,7 @@ class Serializer(object):
|
|
917
999
|
return data
|
918
1000
|
except NameError:
|
919
1001
|
return str(data)
|
920
|
-
|
921
|
-
return str(data)
|
1002
|
+
return str(data)
|
922
1003
|
|
923
1004
|
def serialize_iter(self, data, iter_type, div=None, **kwargs):
|
924
1005
|
"""Serialize iterable.
|
@@ -928,15 +1009,13 @@ class Serializer(object):
|
|
928
1009
|
serialization_ctxt['type'] should be same as data_type.
|
929
1010
|
- is_xml bool : If set, serialize as XML
|
930
1011
|
|
931
|
-
:param list
|
1012
|
+
:param list data: Object to be serialized.
|
932
1013
|
:param str iter_type: Type of object in the iterable.
|
933
|
-
:param bool required: Whether the objects in the iterable must
|
934
|
-
not be None or empty.
|
935
1014
|
:param str div: If set, this str will be used to combine the elements
|
936
1015
|
in the iterable into a combined string. Default is 'None'.
|
937
|
-
:keyword bool do_quote: Whether to quote the serialized result of each iterable element.
|
938
1016
|
Defaults to False.
|
939
1017
|
:rtype: list, str
|
1018
|
+
:return: serialized iterable
|
940
1019
|
"""
|
941
1020
|
if isinstance(data, str):
|
942
1021
|
raise SerializationError("Refuse str type as a valid iter type.")
|
@@ -999,9 +1078,8 @@ class Serializer(object):
|
|
999
1078
|
|
1000
1079
|
:param dict attr: Object to be serialized.
|
1001
1080
|
:param str dict_type: Type of object in the dictionary.
|
1002
|
-
:param bool required: Whether the objects in the dictionary must
|
1003
|
-
not be None or empty.
|
1004
1081
|
:rtype: dict
|
1082
|
+
:return: serialized dictionary
|
1005
1083
|
"""
|
1006
1084
|
serialization_ctxt = kwargs.get("serialization_ctxt", {})
|
1007
1085
|
serialized = {}
|
@@ -1029,7 +1107,9 @@ class Serializer(object):
|
|
1029
1107
|
|
1030
1108
|
return serialized
|
1031
1109
|
|
1032
|
-
def serialize_object(
|
1110
|
+
def serialize_object(
|
1111
|
+
self, attr, **kwargs
|
1112
|
+
): # pylint: disable=too-many-return-statements
|
1033
1113
|
"""Serialize a generic object.
|
1034
1114
|
This will be handled as a dictionary. If object passed in is not
|
1035
1115
|
a basic type (str, int, float, dict, list) it will simply be
|
@@ -1037,6 +1117,7 @@ class Serializer(object):
|
|
1037
1117
|
|
1038
1118
|
:param dict attr: Object to be serialized.
|
1039
1119
|
:rtype: dict or str
|
1120
|
+
:return: serialized object
|
1040
1121
|
"""
|
1041
1122
|
if attr is None:
|
1042
1123
|
return None
|
@@ -1061,7 +1142,7 @@ class Serializer(object):
|
|
1061
1142
|
return self.serialize_decimal(attr)
|
1062
1143
|
|
1063
1144
|
# If it's a model or I know this dependency, serialize as a Model
|
1064
|
-
|
1145
|
+
if obj_type in self.dependencies.values() or isinstance(attr, Model):
|
1065
1146
|
return self._serialize(attr)
|
1066
1147
|
|
1067
1148
|
if obj_type == dict:
|
@@ -1094,56 +1175,61 @@ class Serializer(object):
|
|
1094
1175
|
try:
|
1095
1176
|
enum_obj(result) # type: ignore
|
1096
1177
|
return result
|
1097
|
-
except ValueError:
|
1178
|
+
except ValueError as exc:
|
1098
1179
|
for enum_value in enum_obj: # type: ignore
|
1099
1180
|
if enum_value.value.lower() == str(attr).lower():
|
1100
1181
|
return enum_value.value
|
1101
1182
|
error = "{!r} is not valid value for enum {!r}"
|
1102
|
-
raise SerializationError(error.format(attr, enum_obj))
|
1183
|
+
raise SerializationError(error.format(attr, enum_obj)) from exc
|
1103
1184
|
|
1104
1185
|
@staticmethod
|
1105
|
-
def serialize_bytearray(attr, **kwargs):
|
1186
|
+
def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument
|
1106
1187
|
"""Serialize bytearray into base-64 string.
|
1107
1188
|
|
1108
|
-
:param attr: Object to be serialized.
|
1189
|
+
:param str attr: Object to be serialized.
|
1109
1190
|
:rtype: str
|
1191
|
+
:return: serialized base64
|
1110
1192
|
"""
|
1111
1193
|
return b64encode(attr).decode()
|
1112
1194
|
|
1113
1195
|
@staticmethod
|
1114
|
-
def serialize_base64(attr, **kwargs):
|
1196
|
+
def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument
|
1115
1197
|
"""Serialize str into base-64 string.
|
1116
1198
|
|
1117
|
-
:param attr: Object to be serialized.
|
1199
|
+
:param str attr: Object to be serialized.
|
1118
1200
|
:rtype: str
|
1201
|
+
:return: serialized base64
|
1119
1202
|
"""
|
1120
1203
|
encoded = b64encode(attr).decode("ascii")
|
1121
1204
|
return encoded.strip("=").replace("+", "-").replace("/", "_")
|
1122
1205
|
|
1123
1206
|
@staticmethod
|
1124
|
-
def serialize_decimal(attr, **kwargs):
|
1207
|
+
def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument
|
1125
1208
|
"""Serialize Decimal object to float.
|
1126
1209
|
|
1127
|
-
:param attr: Object to be serialized.
|
1210
|
+
:param decimal attr: Object to be serialized.
|
1128
1211
|
:rtype: float
|
1212
|
+
:return: serialized decimal
|
1129
1213
|
"""
|
1130
1214
|
return float(attr)
|
1131
1215
|
|
1132
1216
|
@staticmethod
|
1133
|
-
def serialize_long(attr, **kwargs):
|
1217
|
+
def serialize_long(attr, **kwargs): # pylint: disable=unused-argument
|
1134
1218
|
"""Serialize long (Py2) or int (Py3).
|
1135
1219
|
|
1136
|
-
:param attr: Object to be serialized.
|
1220
|
+
:param int attr: Object to be serialized.
|
1137
1221
|
:rtype: int/long
|
1222
|
+
:return: serialized long
|
1138
1223
|
"""
|
1139
1224
|
return _long_type(attr)
|
1140
1225
|
|
1141
1226
|
@staticmethod
|
1142
|
-
def serialize_date(attr, **kwargs):
|
1227
|
+
def serialize_date(attr, **kwargs): # pylint: disable=unused-argument
|
1143
1228
|
"""Serialize Date object into ISO-8601 formatted string.
|
1144
1229
|
|
1145
1230
|
:param Date attr: Object to be serialized.
|
1146
1231
|
:rtype: str
|
1232
|
+
:return: serialized date
|
1147
1233
|
"""
|
1148
1234
|
if isinstance(attr, str):
|
1149
1235
|
attr = isodate.parse_date(attr)
|
@@ -1151,11 +1237,12 @@ class Serializer(object):
|
|
1151
1237
|
return t
|
1152
1238
|
|
1153
1239
|
@staticmethod
|
1154
|
-
def serialize_time(attr, **kwargs):
|
1240
|
+
def serialize_time(attr, **kwargs): # pylint: disable=unused-argument
|
1155
1241
|
"""Serialize Time object into ISO-8601 formatted string.
|
1156
1242
|
|
1157
1243
|
:param datetime.time attr: Object to be serialized.
|
1158
1244
|
:rtype: str
|
1245
|
+
:return: serialized time
|
1159
1246
|
"""
|
1160
1247
|
if isinstance(attr, str):
|
1161
1248
|
attr = isodate.parse_time(attr)
|
@@ -1165,30 +1252,32 @@ class Serializer(object):
|
|
1165
1252
|
return t
|
1166
1253
|
|
1167
1254
|
@staticmethod
|
1168
|
-
def serialize_duration(attr, **kwargs):
|
1255
|
+
def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument
|
1169
1256
|
"""Serialize TimeDelta object into ISO-8601 formatted string.
|
1170
1257
|
|
1171
1258
|
:param TimeDelta attr: Object to be serialized.
|
1172
1259
|
:rtype: str
|
1260
|
+
:return: serialized duration
|
1173
1261
|
"""
|
1174
1262
|
if isinstance(attr, str):
|
1175
1263
|
attr = isodate.parse_duration(attr)
|
1176
1264
|
return isodate.duration_isoformat(attr)
|
1177
1265
|
|
1178
1266
|
@staticmethod
|
1179
|
-
def serialize_rfc(attr, **kwargs):
|
1267
|
+
def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument
|
1180
1268
|
"""Serialize Datetime object into RFC-1123 formatted string.
|
1181
1269
|
|
1182
1270
|
:param Datetime attr: Object to be serialized.
|
1183
1271
|
:rtype: str
|
1184
1272
|
:raises: TypeError if format invalid.
|
1273
|
+
:return: serialized rfc
|
1185
1274
|
"""
|
1186
1275
|
try:
|
1187
1276
|
if not attr.tzinfo:
|
1188
1277
|
_LOGGER.warning("Datetime with no tzinfo will be considered UTC.")
|
1189
1278
|
utc = attr.utctimetuple()
|
1190
|
-
except AttributeError:
|
1191
|
-
raise TypeError("RFC1123 object must be valid Datetime object.")
|
1279
|
+
except AttributeError as exc:
|
1280
|
+
raise TypeError("RFC1123 object must be valid Datetime object.") from exc
|
1192
1281
|
|
1193
1282
|
return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format(
|
1194
1283
|
Serializer.days[utc.tm_wday],
|
@@ -1201,12 +1290,13 @@ class Serializer(object):
|
|
1201
1290
|
)
|
1202
1291
|
|
1203
1292
|
@staticmethod
|
1204
|
-
def serialize_iso(attr, **kwargs):
|
1293
|
+
def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument
|
1205
1294
|
"""Serialize Datetime object into ISO-8601 formatted string.
|
1206
1295
|
|
1207
1296
|
:param Datetime attr: Object to be serialized.
|
1208
1297
|
:rtype: str
|
1209
1298
|
:raises: SerializationError if format invalid.
|
1299
|
+
:return: serialized iso
|
1210
1300
|
"""
|
1211
1301
|
if isinstance(attr, str):
|
1212
1302
|
attr = isodate.parse_datetime(attr)
|
@@ -1237,13 +1327,14 @@ class Serializer(object):
|
|
1237
1327
|
raise TypeError(msg) from err
|
1238
1328
|
|
1239
1329
|
@staticmethod
|
1240
|
-
def serialize_unix(attr, **kwargs):
|
1330
|
+
def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument
|
1241
1331
|
"""Serialize Datetime object into IntTime format.
|
1242
1332
|
This is represented as seconds.
|
1243
1333
|
|
1244
1334
|
:param Datetime attr: Object to be serialized.
|
1245
1335
|
:rtype: int
|
1246
1336
|
:raises: SerializationError if format invalid
|
1337
|
+
:return: serialied unix
|
1247
1338
|
"""
|
1248
1339
|
if isinstance(attr, int):
|
1249
1340
|
return attr
|
@@ -1251,11 +1342,11 @@ class Serializer(object):
|
|
1251
1342
|
if not attr.tzinfo:
|
1252
1343
|
_LOGGER.warning("Datetime with no tzinfo will be considered UTC.")
|
1253
1344
|
return int(calendar.timegm(attr.utctimetuple()))
|
1254
|
-
except AttributeError:
|
1255
|
-
raise TypeError("Unix time object must be valid Datetime object.")
|
1345
|
+
except AttributeError as exc:
|
1346
|
+
raise TypeError("Unix time object must be valid Datetime object.") from exc
|
1256
1347
|
|
1257
1348
|
|
1258
|
-
def rest_key_extractor(attr, attr_desc, data):
|
1349
|
+
def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument
|
1259
1350
|
key = attr_desc["key"]
|
1260
1351
|
working_data = data
|
1261
1352
|
|
@@ -1276,7 +1367,9 @@ def rest_key_extractor(attr, attr_desc, data):
|
|
1276
1367
|
return working_data.get(key)
|
1277
1368
|
|
1278
1369
|
|
1279
|
-
def rest_key_case_insensitive_extractor(
|
1370
|
+
def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements
|
1371
|
+
attr, attr_desc, data
|
1372
|
+
):
|
1280
1373
|
key = attr_desc["key"]
|
1281
1374
|
working_data = data
|
1282
1375
|
|
@@ -1299,17 +1392,31 @@ def rest_key_case_insensitive_extractor(attr, attr_desc, data):
|
|
1299
1392
|
return attribute_key_case_insensitive_extractor(key, None, working_data)
|
1300
1393
|
|
1301
1394
|
|
1302
|
-
def last_rest_key_extractor(attr, attr_desc, data):
|
1303
|
-
"""Extract the attribute in "data" based on the last part of the JSON path key.
|
1395
|
+
def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument
|
1396
|
+
"""Extract the attribute in "data" based on the last part of the JSON path key.
|
1397
|
+
|
1398
|
+
:param str attr: The attribute to extract
|
1399
|
+
:param dict attr_desc: The attribute description
|
1400
|
+
:param dict data: The data to extract from
|
1401
|
+
:rtype: object
|
1402
|
+
:returns: The extracted attribute
|
1403
|
+
"""
|
1304
1404
|
key = attr_desc["key"]
|
1305
1405
|
dict_keys = _FLATTEN.split(key)
|
1306
1406
|
return attribute_key_extractor(dict_keys[-1], None, data)
|
1307
1407
|
|
1308
1408
|
|
1309
|
-
def last_rest_key_case_insensitive_extractor(
|
1409
|
+
def last_rest_key_case_insensitive_extractor(
|
1410
|
+
attr, attr_desc, data
|
1411
|
+
): # pylint: disable=unused-argument
|
1310
1412
|
"""Extract the attribute in "data" based on the last part of the JSON path key.
|
1311
1413
|
|
1312
1414
|
This is the case insensitive version of "last_rest_key_extractor"
|
1415
|
+
:param str attr: The attribute to extract
|
1416
|
+
:param dict attr_desc: The attribute description
|
1417
|
+
:param dict data: The data to extract from
|
1418
|
+
:rtype: object
|
1419
|
+
:returns: The extracted attribute
|
1313
1420
|
"""
|
1314
1421
|
key = attr_desc["key"]
|
1315
1422
|
dict_keys = _FLATTEN.split(key)
|
@@ -1346,7 +1453,9 @@ def _extract_name_from_internal_type(internal_type):
|
|
1346
1453
|
return xml_name
|
1347
1454
|
|
1348
1455
|
|
1349
|
-
def xml_key_extractor(
|
1456
|
+
def xml_key_extractor(
|
1457
|
+
attr, attr_desc, data
|
1458
|
+
): # pylint: disable=unused-argument,too-many-return-statements
|
1350
1459
|
if isinstance(data, dict):
|
1351
1460
|
return None
|
1352
1461
|
|
@@ -1403,22 +1512,21 @@ def xml_key_extractor(attr, attr_desc, data):
|
|
1403
1512
|
if is_iter_type:
|
1404
1513
|
if is_wrapped:
|
1405
1514
|
return None # is_wrapped no node, we want None
|
1406
|
-
|
1407
|
-
return [] # not wrapped, assume empty list
|
1515
|
+
return [] # not wrapped, assume empty list
|
1408
1516
|
return None # Assume it's not there, maybe an optional node.
|
1409
1517
|
|
1410
1518
|
# If is_iter_type and not wrapped, return all found children
|
1411
1519
|
if is_iter_type:
|
1412
1520
|
if not is_wrapped:
|
1413
1521
|
return children
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
)
|
1522
|
+
# Iter and wrapped, should have found one node only (the wrap one)
|
1523
|
+
if len(children) != 1:
|
1524
|
+
raise DeserializationError(
|
1525
|
+
"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
|
1526
|
+
xml_name
|
1420
1527
|
)
|
1421
|
-
|
1528
|
+
)
|
1529
|
+
return list(children[0]) # Might be empty list and that's ok.
|
1422
1530
|
|
1423
1531
|
# Here it's not a itertype, we should have found one element only or empty
|
1424
1532
|
if len(children) > 1:
|
@@ -1438,10 +1546,10 @@ class Deserializer(object):
|
|
1438
1546
|
basic_types = {str: "str", int: "int", bool: "bool", float: "float"}
|
1439
1547
|
|
1440
1548
|
valid_date = re.compile(
|
1441
|
-
r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}
|
1549
|
+
r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?"
|
1442
1550
|
)
|
1443
1551
|
|
1444
|
-
def __init__(self, classes: Optional[Mapping[str, type]] = None):
|
1552
|
+
def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None:
|
1445
1553
|
self.deserialize_type = {
|
1446
1554
|
"iso-8601": Deserializer.deserialize_iso,
|
1447
1555
|
"rfc-1123": Deserializer.deserialize_rfc,
|
@@ -1479,11 +1587,14 @@ class Deserializer(object):
|
|
1479
1587
|
:param str content_type: Swagger "produces" if available.
|
1480
1588
|
:raises: DeserializationError if deserialization fails.
|
1481
1589
|
:return: Deserialized object.
|
1590
|
+
:rtype: object
|
1482
1591
|
"""
|
1483
1592
|
data = self._unpack_content(response_data, content_type)
|
1484
1593
|
return self._deserialize(target_obj, data)
|
1485
1594
|
|
1486
|
-
def _deserialize(
|
1595
|
+
def _deserialize(
|
1596
|
+
self, target_obj, data
|
1597
|
+
): # pylint: disable=inconsistent-return-statements
|
1487
1598
|
"""Call the deserializer on a model.
|
1488
1599
|
|
1489
1600
|
Data needs to be already deserialized as JSON or XML ElementTree
|
@@ -1492,6 +1603,7 @@ class Deserializer(object):
|
|
1492
1603
|
:param object data: Object to deserialize.
|
1493
1604
|
:raises: DeserializationError if deserialization fails.
|
1494
1605
|
:return: Deserialized object.
|
1606
|
+
:rtype: object
|
1495
1607
|
"""
|
1496
1608
|
# This is already a model, go recursive just in case
|
1497
1609
|
if hasattr(data, "_attribute_map"):
|
@@ -1501,7 +1613,10 @@ class Deserializer(object):
|
|
1501
1613
|
if config.get("constant")
|
1502
1614
|
]
|
1503
1615
|
try:
|
1504
|
-
for
|
1616
|
+
for (
|
1617
|
+
attr,
|
1618
|
+
mapconfig,
|
1619
|
+
) in data._attribute_map.items(): # pylint: disable=protected-access
|
1505
1620
|
if attr in constants:
|
1506
1621
|
continue
|
1507
1622
|
value = getattr(data, attr)
|
@@ -1522,13 +1637,13 @@ class Deserializer(object):
|
|
1522
1637
|
|
1523
1638
|
if isinstance(response, str):
|
1524
1639
|
return self.deserialize_data(data, response)
|
1525
|
-
|
1640
|
+
if isinstance(response, type) and issubclass(response, Enum):
|
1526
1641
|
return self.deserialize_enum(data, response)
|
1527
1642
|
|
1528
1643
|
if data is None or data is CoreNull:
|
1529
1644
|
return data
|
1530
1645
|
try:
|
1531
|
-
attributes = response._attribute_map # type: ignore
|
1646
|
+
attributes = response._attribute_map # type: ignore # pylint: disable=protected-access
|
1532
1647
|
d_attrs = {}
|
1533
1648
|
for attr, attr_desc in attributes.items():
|
1534
1649
|
# Check empty string. If it's not empty, someone has a real "additionalProperties"...
|
@@ -1558,9 +1673,8 @@ class Deserializer(object):
|
|
1558
1673
|
except (AttributeError, TypeError, KeyError) as err:
|
1559
1674
|
msg = "Unable to deserialize to object: " + class_name # type: ignore
|
1560
1675
|
raise DeserializationError(msg) from err
|
1561
|
-
|
1562
|
-
|
1563
|
-
return self._instantiate_model(response, d_attrs, additional_properties)
|
1676
|
+
additional_properties = self._build_additional_properties(attributes, data)
|
1677
|
+
return self._instantiate_model(response, d_attrs, additional_properties)
|
1564
1678
|
|
1565
1679
|
def _build_additional_properties(self, attribute_map, data):
|
1566
1680
|
if not self.additional_properties_detection:
|
@@ -1590,6 +1704,8 @@ class Deserializer(object):
|
|
1590
1704
|
|
1591
1705
|
:param str target: The target object type to deserialize to.
|
1592
1706
|
:param str/dict data: The response data to deserialize.
|
1707
|
+
:return: The classified target object and its class name.
|
1708
|
+
:rtype: tuple
|
1593
1709
|
"""
|
1594
1710
|
if target is None:
|
1595
1711
|
return None, None
|
@@ -1601,7 +1717,7 @@ class Deserializer(object):
|
|
1601
1717
|
return target, target
|
1602
1718
|
|
1603
1719
|
try:
|
1604
|
-
target = target._classify(data, self.dependencies) # type: ignore
|
1720
|
+
target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access
|
1605
1721
|
except AttributeError:
|
1606
1722
|
pass # Target is not a Model, no classify
|
1607
1723
|
return target, target.__class__.__name__ # type: ignore
|
@@ -1616,10 +1732,12 @@ class Deserializer(object):
|
|
1616
1732
|
:param str target_obj: The target object type to deserialize to.
|
1617
1733
|
:param str/dict data: The response data to deserialize.
|
1618
1734
|
:param str content_type: Swagger "produces" if available.
|
1735
|
+
:return: Deserialized object.
|
1736
|
+
:rtype: object
|
1619
1737
|
"""
|
1620
1738
|
try:
|
1621
1739
|
return self(target_obj, data, content_type=content_type)
|
1622
|
-
except:
|
1740
|
+
except: # pylint: disable=bare-except
|
1623
1741
|
_LOGGER.debug(
|
1624
1742
|
"Ran into a deserialization error. Ignoring since this is failsafe deserialization",
|
1625
1743
|
exc_info=True,
|
@@ -1638,10 +1756,12 @@ class Deserializer(object):
|
|
1638
1756
|
|
1639
1757
|
If raw_data is something else, bypass all logic and return it directly.
|
1640
1758
|
|
1641
|
-
:param raw_data: Data to be processed.
|
1642
|
-
:param content_type: How to parse if raw_data is a string/bytes.
|
1759
|
+
:param obj raw_data: Data to be processed.
|
1760
|
+
:param str content_type: How to parse if raw_data is a string/bytes.
|
1643
1761
|
:raises JSONDecodeError: If JSON is requested and parsing is impossible.
|
1644
1762
|
:raises UnicodeDecodeError: If bytes is not UTF8
|
1763
|
+
:rtype: object
|
1764
|
+
:return: Unpacked content.
|
1645
1765
|
"""
|
1646
1766
|
# Assume this is enough to detect a Pipeline Response without importing it
|
1647
1767
|
context = getattr(raw_data, "context", {})
|
@@ -1671,17 +1791,24 @@ class Deserializer(object):
|
|
1671
1791
|
def _instantiate_model(self, response, attrs, additional_properties=None):
|
1672
1792
|
"""Instantiate a response model passing in deserialized args.
|
1673
1793
|
|
1674
|
-
:param response: The response model class.
|
1675
|
-
:param
|
1794
|
+
:param Response response: The response model class.
|
1795
|
+
:param dict attrs: The deserialized response attributes.
|
1796
|
+
:param dict additional_properties: Additional properties to be set.
|
1797
|
+
:rtype: Response
|
1798
|
+
:return: The instantiated response model.
|
1676
1799
|
"""
|
1677
1800
|
if callable(response):
|
1678
1801
|
subtype = getattr(response, "_subtype_map", {})
|
1679
1802
|
try:
|
1680
1803
|
readonly = [
|
1681
|
-
k
|
1804
|
+
k
|
1805
|
+
for k, v in response._validation.items()
|
1806
|
+
if v.get("readonly") # pylint: disable=protected-access
|
1682
1807
|
]
|
1683
1808
|
const = [
|
1684
|
-
k
|
1809
|
+
k
|
1810
|
+
for k, v in response._validation.items()
|
1811
|
+
if v.get("constant") # pylint: disable=protected-access
|
1685
1812
|
]
|
1686
1813
|
kwargs = {
|
1687
1814
|
k: v
|
@@ -1696,7 +1823,7 @@ class Deserializer(object):
|
|
1696
1823
|
return response_obj
|
1697
1824
|
except TypeError as err:
|
1698
1825
|
msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore
|
1699
|
-
raise DeserializationError(msg + str(err))
|
1826
|
+
raise DeserializationError(msg + str(err)) from err
|
1700
1827
|
else:
|
1701
1828
|
try:
|
1702
1829
|
for attr, value in attrs.items():
|
@@ -1705,15 +1832,18 @@ class Deserializer(object):
|
|
1705
1832
|
except Exception as exp:
|
1706
1833
|
msg = "Unable to populate response model. "
|
1707
1834
|
msg += "Type: {}, Error: {}".format(type(response), exp)
|
1708
|
-
raise DeserializationError(msg)
|
1835
|
+
raise DeserializationError(msg) from exp
|
1709
1836
|
|
1710
|
-
def deserialize_data(
|
1837
|
+
def deserialize_data(
|
1838
|
+
self, data, data_type
|
1839
|
+
): # pylint: disable=too-many-return-statements
|
1711
1840
|
"""Process data for deserialization according to data type.
|
1712
1841
|
|
1713
1842
|
:param str data: The response string to be deserialized.
|
1714
1843
|
:param str data_type: The type to deserialize to.
|
1715
1844
|
:raises: DeserializationError if deserialization fails.
|
1716
1845
|
:return: Deserialized object.
|
1846
|
+
:rtype: object
|
1717
1847
|
"""
|
1718
1848
|
if data is None:
|
1719
1849
|
return data
|
@@ -1729,7 +1859,14 @@ class Deserializer(object):
|
|
1729
1859
|
):
|
1730
1860
|
return data
|
1731
1861
|
|
1732
|
-
is_a_text_parsing_type =
|
1862
|
+
is_a_text_parsing_type = (
|
1863
|
+
lambda x: x
|
1864
|
+
not in [ # pylint: disable=unnecessary-lambda-assignment
|
1865
|
+
"object",
|
1866
|
+
"[]",
|
1867
|
+
r"{}",
|
1868
|
+
]
|
1869
|
+
)
|
1733
1870
|
if (
|
1734
1871
|
isinstance(data, ET.Element)
|
1735
1872
|
and is_a_text_parsing_type(data_type)
|
@@ -1753,14 +1890,14 @@ class Deserializer(object):
|
|
1753
1890
|
msg = "Unable to deserialize response data."
|
1754
1891
|
msg += " Data: {}, {}".format(data, data_type)
|
1755
1892
|
raise DeserializationError(msg) from err
|
1756
|
-
|
1757
|
-
return self._deserialize(obj_type, data)
|
1893
|
+
return self._deserialize(obj_type, data)
|
1758
1894
|
|
1759
1895
|
def deserialize_iter(self, attr, iter_type):
|
1760
1896
|
"""Deserialize an iterable.
|
1761
1897
|
|
1762
1898
|
:param list attr: Iterable to be deserialized.
|
1763
1899
|
:param str iter_type: The type of object in the iterable.
|
1900
|
+
:return: Deserialized iterable.
|
1764
1901
|
:rtype: list
|
1765
1902
|
"""
|
1766
1903
|
if attr is None:
|
@@ -1783,6 +1920,7 @@ class Deserializer(object):
|
|
1783
1920
|
:param dict/list attr: Dictionary to be deserialized. Also accepts
|
1784
1921
|
a list of key, value pairs.
|
1785
1922
|
:param str dict_type: The object type of the items in the dictionary.
|
1923
|
+
:return: Deserialized dictionary.
|
1786
1924
|
:rtype: dict
|
1787
1925
|
"""
|
1788
1926
|
if isinstance(attr, list):
|
@@ -1795,11 +1933,14 @@ class Deserializer(object):
|
|
1795
1933
|
attr = {el.tag: el.text for el in attr}
|
1796
1934
|
return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()}
|
1797
1935
|
|
1798
|
-
def deserialize_object(
|
1936
|
+
def deserialize_object(
|
1937
|
+
self, attr, **kwargs
|
1938
|
+
): # pylint: disable=too-many-return-statements
|
1799
1939
|
"""Deserialize a generic object.
|
1800
1940
|
This will be handled as a dictionary.
|
1801
1941
|
|
1802
1942
|
:param dict attr: Dictionary to be deserialized.
|
1943
|
+
:return: Deserialized object.
|
1803
1944
|
:rtype: dict
|
1804
1945
|
:raises: TypeError if non-builtin datatype encountered.
|
1805
1946
|
"""
|
@@ -1834,11 +1975,12 @@ class Deserializer(object):
|
|
1834
1975
|
pass
|
1835
1976
|
return deserialized
|
1836
1977
|
|
1837
|
-
|
1838
|
-
|
1839
|
-
raise TypeError(error + str(obj_type))
|
1978
|
+
error = "Cannot deserialize generic object with type: "
|
1979
|
+
raise TypeError(error + str(obj_type))
|
1840
1980
|
|
1841
|
-
def deserialize_basic(
|
1981
|
+
def deserialize_basic(
|
1982
|
+
self, attr, data_type
|
1983
|
+
): # pylint: disable=too-many-return-statements
|
1842
1984
|
"""Deserialize basic builtin data type from string.
|
1843
1985
|
Will attempt to convert to str, int, float and bool.
|
1844
1986
|
This function will also accept '1', '0', 'true' and 'false' as
|
@@ -1846,6 +1988,7 @@ class Deserializer(object):
|
|
1846
1988
|
|
1847
1989
|
:param str attr: response string to be deserialized.
|
1848
1990
|
:param str data_type: deserialization data type.
|
1991
|
+
:return: Deserialized basic type.
|
1849
1992
|
:rtype: str, int, float or bool
|
1850
1993
|
:raises: TypeError if string format is not valid.
|
1851
1994
|
"""
|
@@ -1857,24 +2000,23 @@ class Deserializer(object):
|
|
1857
2000
|
if data_type == "str":
|
1858
2001
|
# None or '', node <a/> is empty string.
|
1859
2002
|
return ""
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
return None
|
2003
|
+
# None or '', node <a/> with a strong type is None.
|
2004
|
+
# Don't try to model "empty bool" or "empty int"
|
2005
|
+
return None
|
1864
2006
|
|
1865
2007
|
if data_type == "bool":
|
1866
2008
|
if attr in [True, False, 1, 0]:
|
1867
2009
|
return bool(attr)
|
1868
|
-
|
2010
|
+
if isinstance(attr, str):
|
1869
2011
|
if attr.lower() in ["true", "1"]:
|
1870
2012
|
return True
|
1871
|
-
|
2013
|
+
if attr.lower() in ["false", "0"]:
|
1872
2014
|
return False
|
1873
2015
|
raise TypeError("Invalid boolean value: {}".format(attr))
|
1874
2016
|
|
1875
2017
|
if data_type == "str":
|
1876
2018
|
return self.deserialize_unicode(attr)
|
1877
|
-
return eval(data_type)(attr) # nosec
|
2019
|
+
return eval(data_type)(attr) # nosec # pylint: disable=eval-used
|
1878
2020
|
|
1879
2021
|
@staticmethod
|
1880
2022
|
def deserialize_unicode(data):
|
@@ -1882,6 +2024,7 @@ class Deserializer(object):
|
|
1882
2024
|
as a string.
|
1883
2025
|
|
1884
2026
|
:param str data: response string to be deserialized.
|
2027
|
+
:return: Deserialized string.
|
1885
2028
|
:rtype: str or unicode
|
1886
2029
|
"""
|
1887
2030
|
# We might be here because we have an enum modeled as string,
|
@@ -1895,8 +2038,7 @@ class Deserializer(object):
|
|
1895
2038
|
return data
|
1896
2039
|
except NameError:
|
1897
2040
|
return str(data)
|
1898
|
-
|
1899
|
-
return str(data)
|
2041
|
+
return str(data)
|
1900
2042
|
|
1901
2043
|
@staticmethod
|
1902
2044
|
def deserialize_enum(data, enum_obj):
|
@@ -1908,6 +2050,7 @@ class Deserializer(object):
|
|
1908
2050
|
:param str data: Response string to be deserialized. If this value is
|
1909
2051
|
None or invalid it will be returned as-is.
|
1910
2052
|
:param Enum enum_obj: Enum object to deserialize to.
|
2053
|
+
:return: Deserialized enum object.
|
1911
2054
|
:rtype: Enum
|
1912
2055
|
"""
|
1913
2056
|
if isinstance(data, enum_obj) or data is None:
|
@@ -1918,9 +2061,9 @@ class Deserializer(object):
|
|
1918
2061
|
# Workaround. We might consider remove it in the future.
|
1919
2062
|
try:
|
1920
2063
|
return list(enum_obj.__members__.values())[data]
|
1921
|
-
except IndexError:
|
2064
|
+
except IndexError as exc:
|
1922
2065
|
error = "{!r} is not a valid index for enum {!r}"
|
1923
|
-
raise DeserializationError(error.format(data, enum_obj))
|
2066
|
+
raise DeserializationError(error.format(data, enum_obj)) from exc
|
1924
2067
|
try:
|
1925
2068
|
return enum_obj(str(data))
|
1926
2069
|
except ValueError:
|
@@ -1940,6 +2083,7 @@ class Deserializer(object):
|
|
1940
2083
|
"""Deserialize string into bytearray.
|
1941
2084
|
|
1942
2085
|
:param str attr: response string to be deserialized.
|
2086
|
+
:return: Deserialized bytearray
|
1943
2087
|
:rtype: bytearray
|
1944
2088
|
:raises: TypeError if string format invalid.
|
1945
2089
|
"""
|
@@ -1952,6 +2096,7 @@ class Deserializer(object):
|
|
1952
2096
|
"""Deserialize base64 encoded string into string.
|
1953
2097
|
|
1954
2098
|
:param str attr: response string to be deserialized.
|
2099
|
+
:return: Deserialized base64 string
|
1955
2100
|
:rtype: bytearray
|
1956
2101
|
:raises: TypeError if string format invalid.
|
1957
2102
|
"""
|
@@ -1967,8 +2112,9 @@ class Deserializer(object):
|
|
1967
2112
|
"""Deserialize string into Decimal object.
|
1968
2113
|
|
1969
2114
|
:param str attr: response string to be deserialized.
|
1970
|
-
:
|
2115
|
+
:return: Deserialized decimal
|
1971
2116
|
:raises: DeserializationError if string format invalid.
|
2117
|
+
:rtype: decimal
|
1972
2118
|
"""
|
1973
2119
|
if isinstance(attr, ET.Element):
|
1974
2120
|
attr = attr.text
|
@@ -1983,6 +2129,7 @@ class Deserializer(object):
|
|
1983
2129
|
"""Deserialize string into long (Py2) or int (Py3).
|
1984
2130
|
|
1985
2131
|
:param str attr: response string to be deserialized.
|
2132
|
+
:return: Deserialized int
|
1986
2133
|
:rtype: long or int
|
1987
2134
|
:raises: ValueError if string format invalid.
|
1988
2135
|
"""
|
@@ -1995,6 +2142,7 @@ class Deserializer(object):
|
|
1995
2142
|
"""Deserialize ISO-8601 formatted string into TimeDelta object.
|
1996
2143
|
|
1997
2144
|
:param str attr: response string to be deserialized.
|
2145
|
+
:return: Deserialized duration
|
1998
2146
|
:rtype: TimeDelta
|
1999
2147
|
:raises: DeserializationError if string format invalid.
|
2000
2148
|
"""
|
@@ -2005,14 +2153,14 @@ class Deserializer(object):
|
|
2005
2153
|
except (ValueError, OverflowError, AttributeError) as err:
|
2006
2154
|
msg = "Cannot deserialize duration object."
|
2007
2155
|
raise DeserializationError(msg) from err
|
2008
|
-
|
2009
|
-
return duration
|
2156
|
+
return duration
|
2010
2157
|
|
2011
2158
|
@staticmethod
|
2012
2159
|
def deserialize_date(attr):
|
2013
2160
|
"""Deserialize ISO-8601 formatted string into Date object.
|
2014
2161
|
|
2015
2162
|
:param str attr: response string to be deserialized.
|
2163
|
+
:return: Deserialized date
|
2016
2164
|
:rtype: Date
|
2017
2165
|
:raises: DeserializationError if string format invalid.
|
2018
2166
|
"""
|
@@ -2030,6 +2178,7 @@ class Deserializer(object):
|
|
2030
2178
|
"""Deserialize ISO-8601 formatted string into time object.
|
2031
2179
|
|
2032
2180
|
:param str attr: response string to be deserialized.
|
2181
|
+
:return: Deserialized time
|
2033
2182
|
:rtype: datetime.time
|
2034
2183
|
:raises: DeserializationError if string format invalid.
|
2035
2184
|
"""
|
@@ -2046,6 +2195,7 @@ class Deserializer(object):
|
|
2046
2195
|
"""Deserialize RFC-1123 formatted string into Datetime object.
|
2047
2196
|
|
2048
2197
|
:param str attr: response string to be deserialized.
|
2198
|
+
:return: Deserialized RFC datetime
|
2049
2199
|
:rtype: Datetime
|
2050
2200
|
:raises: DeserializationError if string format invalid.
|
2051
2201
|
"""
|
@@ -2064,14 +2214,14 @@ class Deserializer(object):
|
|
2064
2214
|
except ValueError as err:
|
2065
2215
|
msg = "Cannot deserialize to rfc datetime object."
|
2066
2216
|
raise DeserializationError(msg) from err
|
2067
|
-
|
2068
|
-
return date_obj
|
2217
|
+
return date_obj
|
2069
2218
|
|
2070
2219
|
@staticmethod
|
2071
2220
|
def deserialize_iso(attr):
|
2072
2221
|
"""Deserialize ISO-8601 formatted string into Datetime object.
|
2073
2222
|
|
2074
2223
|
:param str attr: response string to be deserialized.
|
2224
|
+
:return: Deserialized ISO datetime
|
2075
2225
|
:rtype: Datetime
|
2076
2226
|
:raises: DeserializationError if string format invalid.
|
2077
2227
|
"""
|
@@ -2101,8 +2251,7 @@ class Deserializer(object):
|
|
2101
2251
|
except (ValueError, OverflowError, AttributeError) as err:
|
2102
2252
|
msg = "Cannot deserialize datetime object."
|
2103
2253
|
raise DeserializationError(msg) from err
|
2104
|
-
|
2105
|
-
return date_obj
|
2254
|
+
return date_obj
|
2106
2255
|
|
2107
2256
|
@staticmethod
|
2108
2257
|
def deserialize_unix(attr):
|
@@ -2110,6 +2259,7 @@ class Deserializer(object):
|
|
2110
2259
|
This is represented as seconds.
|
2111
2260
|
|
2112
2261
|
:param int attr: Object to be serialized.
|
2262
|
+
:return: Deserialized datetime
|
2113
2263
|
:rtype: Datetime
|
2114
2264
|
:raises: DeserializationError if format invalid
|
2115
2265
|
"""
|
@@ -2121,5 +2271,4 @@ class Deserializer(object):
|
|
2121
2271
|
except ValueError as err:
|
2122
2272
|
msg = "Cannot deserialize to unix datetime object."
|
2123
2273
|
raise DeserializationError(msg) from err
|
2124
|
-
|
2125
|
-
return date_obj
|
2274
|
+
return date_obj
|