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