@autorest/python 6.7.0 → 6.7.2
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.
- package/autorest/black/__init__.py +3 -0
- package/autorest/codegen/models/__init__.py +2 -0
- package/autorest/codegen/models/client.py +2 -0
- package/autorest/codegen/models/code_model.py +6 -2
- package/autorest/codegen/models/dictionary_type.py +4 -0
- package/autorest/codegen/models/list_type.py +4 -0
- package/autorest/codegen/models/operation.py +14 -2
- package/autorest/codegen/models/parameter.py +1 -7
- package/autorest/codegen/models/parameter_list.py +1 -1
- package/autorest/codegen/models/primitive_types.py +37 -9
- package/autorest/codegen/serializers/__init__.py +1 -0
- package/autorest/codegen/serializers/builder_serializer.py +30 -41
- package/autorest/codegen/serializers/client_serializer.py +8 -2
- package/autorest/codegen/serializers/general_serializer.py +7 -0
- package/autorest/codegen/serializers/model_serializer.py +2 -2
- package/autorest/codegen/serializers/parameter_serializer.py +59 -4
- package/autorest/codegen/templates/model_base.py.jinja2 +242 -168
- package/autorest/codegen/templates/packaging_templates/setup.py.jinja2 +1 -1
- package/autorest/codegen/templates/serialization.py.jinja2 +13 -4
- package/autorest/codegen/templates/vendor.py.jinja2 +29 -0
- package/autorest/multiapi/__init__.py +0 -5
- package/autorest/preprocess/__init__.py +63 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
# pylint: disable=protected-access, arguments-differ, signature-differs, broad-except
|
|
8
8
|
# pyright: reportGeneralTypeIssues=false
|
|
9
9
|
|
|
10
|
+
import calendar
|
|
10
11
|
import functools
|
|
11
12
|
import sys
|
|
12
13
|
import logging
|
|
@@ -14,13 +15,14 @@ import base64
|
|
|
14
15
|
import re
|
|
15
16
|
import copy
|
|
16
17
|
import typing
|
|
18
|
+
import email
|
|
17
19
|
from datetime import datetime, date, time, timedelta, timezone
|
|
18
20
|
from json import JSONEncoder
|
|
19
21
|
import isodate
|
|
20
22
|
from azure.core.exceptions import DeserializationError
|
|
21
23
|
from azure.core import CaseInsensitiveEnumMeta
|
|
22
24
|
from azure.core.pipeline import PipelineResponse
|
|
23
|
-
from azure.core.serialization import _Null
|
|
25
|
+
from azure.core.serialization import _Null
|
|
24
26
|
|
|
25
27
|
if sys.version_info >= (3, 9):
|
|
26
28
|
from collections.abc import MutableMapping
|
|
@@ -31,9 +33,9 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
31
33
|
|
|
32
34
|
__all__ = ["AzureJSONEncoder", "Model", "rest_field", "rest_discriminator"]
|
|
33
35
|
|
|
34
|
-
|
|
35
36
|
TZ_UTC = timezone.utc
|
|
36
37
|
|
|
38
|
+
|
|
37
39
|
def _timedelta_as_isostr(td: timedelta) -> str:
|
|
38
40
|
"""Converts a datetime.timedelta object into an ISO 8601 formatted string, e.g. 'P4DT12H30M05S'
|
|
39
41
|
|
|
@@ -91,38 +93,20 @@ def _timedelta_as_isostr(td: timedelta) -> str:
|
|
|
91
93
|
return "P" + date_str + time_str
|
|
92
94
|
|
|
93
95
|
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
:return: ISO8601 version of this datetime
|
|
100
|
-
"""
|
|
101
|
-
# First try datetime.datetime
|
|
102
|
-
if hasattr(dt, "year") and hasattr(dt, "hour"):
|
|
103
|
-
dt = typing.cast(datetime, dt)
|
|
104
|
-
# astimezone() fails for naive times in Python 2.7, so make make sure dt is aware (tzinfo is set)
|
|
105
|
-
if not dt.tzinfo:
|
|
106
|
-
iso_formatted = dt.replace(tzinfo=TZ_UTC).isoformat()
|
|
107
|
-
else:
|
|
108
|
-
iso_formatted = dt.astimezone(TZ_UTC).isoformat()
|
|
109
|
-
# Replace the trailing "+00:00" UTC offset with "Z" (RFC 3339: https://www.ietf.org/rfc/rfc3339.txt)
|
|
110
|
-
return iso_formatted.replace("+00:00", "Z")
|
|
111
|
-
# Next try datetime.date or datetime.time
|
|
112
|
-
try:
|
|
113
|
-
dt = typing.cast(typing.Union[date, time], dt)
|
|
114
|
-
return dt.isoformat()
|
|
115
|
-
# Last, try datetime.timedelta
|
|
116
|
-
except AttributeError:
|
|
117
|
-
dt = typing.cast(timedelta, dt)
|
|
118
|
-
return _timedelta_as_isostr(dt)
|
|
119
|
-
|
|
120
|
-
def _serialize_bytes(o) -> str:
|
|
121
|
-
return base64.b64encode(o).decode()
|
|
96
|
+
def _serialize_bytes(o, format: typing.Optional[str] = None) -> str:
|
|
97
|
+
encoded = base64.b64encode(o).decode()
|
|
98
|
+
if format == "base64url":
|
|
99
|
+
return encoded.strip("=").replace("+", "-").replace("/", "_")
|
|
100
|
+
return encoded
|
|
122
101
|
|
|
123
102
|
|
|
124
|
-
def _serialize_datetime(o):
|
|
103
|
+
def _serialize_datetime(o, format: typing.Optional[str] = None):
|
|
125
104
|
if hasattr(o, "year") and hasattr(o, "hour"):
|
|
105
|
+
if format == "rfc7231":
|
|
106
|
+
return email.utils.format_datetime(o, usegmt=True)
|
|
107
|
+
if format == "unix-timestamp":
|
|
108
|
+
return int(calendar.timegm(o.utctimetuple()))
|
|
109
|
+
|
|
126
110
|
# astimezone() fails for naive times in Python 2.7, so make make sure o is aware (tzinfo is set)
|
|
127
111
|
if not o.tzinfo:
|
|
128
112
|
iso_formatted = o.replace(tzinfo=TZ_UTC).isoformat()
|
|
@@ -146,7 +130,7 @@ class AzureJSONEncoder(JSONEncoder):
|
|
|
146
130
|
|
|
147
131
|
def default(self, o): # pylint: disable=too-many-return-statements
|
|
148
132
|
if _is_model(o):
|
|
149
|
-
readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)]
|
|
133
|
+
readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)]
|
|
150
134
|
return {k: v for k, v in o.items() if k not in readonly_props}
|
|
151
135
|
if isinstance(o, (bytes, bytearray)):
|
|
152
136
|
return base64.b64encode(o).decode()
|
|
@@ -172,6 +156,10 @@ class AzureJSONEncoder(JSONEncoder):
|
|
|
172
156
|
|
|
173
157
|
|
|
174
158
|
_VALID_DATE = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}" + r"\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?")
|
|
159
|
+
_VALID_RFC7231 = re.compile(
|
|
160
|
+
r"(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s\d{2}\s"
|
|
161
|
+
r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT"
|
|
162
|
+
)
|
|
175
163
|
|
|
176
164
|
|
|
177
165
|
def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
|
|
@@ -207,6 +195,36 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
|
|
|
207
195
|
return date_obj
|
|
208
196
|
|
|
209
197
|
|
|
198
|
+
def _deserialize_datetime_rfc7231(attr: typing.Union[str, datetime]) -> datetime:
|
|
199
|
+
"""Deserialize RFC7231 formatted string into Datetime object.
|
|
200
|
+
|
|
201
|
+
:param str attr: response string to be deserialized.
|
|
202
|
+
:rtype: ~datetime.datetime
|
|
203
|
+
:returns: The datetime object from that input
|
|
204
|
+
"""
|
|
205
|
+
if isinstance(attr, datetime):
|
|
206
|
+
# i'm already deserialized
|
|
207
|
+
return attr
|
|
208
|
+
match = _VALID_RFC7231.match(attr)
|
|
209
|
+
if not match:
|
|
210
|
+
raise ValueError("Invalid datetime string: " + attr)
|
|
211
|
+
|
|
212
|
+
return email.utils.parsedate_to_datetime(attr)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _deserialize_datetime_unix_timestamp(attr: typing.Union[float, datetime]) -> datetime:
|
|
216
|
+
"""Deserialize unix timestamp into Datetime object.
|
|
217
|
+
|
|
218
|
+
:param str attr: response string to be deserialized.
|
|
219
|
+
:rtype: ~datetime.datetime
|
|
220
|
+
:returns: The datetime object from that input
|
|
221
|
+
"""
|
|
222
|
+
if isinstance(attr, datetime):
|
|
223
|
+
# i'm already deserialized
|
|
224
|
+
return attr
|
|
225
|
+
return datetime.fromtimestamp(attr, TZ_UTC)
|
|
226
|
+
|
|
227
|
+
|
|
210
228
|
def _deserialize_date(attr: typing.Union[str, date]) -> date:
|
|
211
229
|
"""Deserialize ISO-8601 formatted string into Date object.
|
|
212
230
|
:param str attr: response string to be deserialized.
|
|
@@ -231,13 +249,22 @@ def _deserialize_time(attr: typing.Union[str, time]) -> time:
|
|
|
231
249
|
return isodate.parse_time(attr)
|
|
232
250
|
|
|
233
251
|
|
|
234
|
-
def
|
|
252
|
+
def _deserialize_bytes(attr):
|
|
235
253
|
if isinstance(attr, (bytes, bytearray)):
|
|
236
254
|
return attr
|
|
237
255
|
return bytes(base64.b64decode(attr))
|
|
238
256
|
|
|
239
257
|
|
|
240
|
-
def
|
|
258
|
+
def _deserialize_bytes_base64(attr):
|
|
259
|
+
if isinstance(attr, (bytes, bytearray)):
|
|
260
|
+
return attr
|
|
261
|
+
padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore
|
|
262
|
+
attr = attr + padding # type: ignore
|
|
263
|
+
encoded = attr.replace("-", "+").replace("_", "/")
|
|
264
|
+
return bytes(base64.b64decode(encoded))
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _deserialize_duration(attr):
|
|
241
268
|
if isinstance(attr, timedelta):
|
|
242
269
|
return attr
|
|
243
270
|
return isodate.parse_duration(attr)
|
|
@@ -247,11 +274,26 @@ _DESERIALIZE_MAPPING = {
|
|
|
247
274
|
datetime: _deserialize_datetime,
|
|
248
275
|
date: _deserialize_date,
|
|
249
276
|
time: _deserialize_time,
|
|
250
|
-
bytes:
|
|
251
|
-
|
|
277
|
+
bytes: _deserialize_bytes,
|
|
278
|
+
bytearray: _deserialize_bytes,
|
|
279
|
+
timedelta: _deserialize_duration,
|
|
252
280
|
typing.Any: lambda x: x,
|
|
253
281
|
}
|
|
254
282
|
|
|
283
|
+
_DESERIALIZE_MAPPING_WITHFORMAT = {
|
|
284
|
+
"rfc3339": _deserialize_datetime,
|
|
285
|
+
"rfc7231": _deserialize_datetime_rfc7231,
|
|
286
|
+
"unix-timestamp": _deserialize_datetime_unix_timestamp,
|
|
287
|
+
"base64": _deserialize_bytes,
|
|
288
|
+
"base64url": _deserialize_bytes_base64,
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None):
|
|
293
|
+
if rf and rf._format:
|
|
294
|
+
return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format)
|
|
295
|
+
return _DESERIALIZE_MAPPING.get(annotation)
|
|
296
|
+
|
|
255
297
|
|
|
256
298
|
def _get_model(module_name: str, model_name: str):
|
|
257
299
|
models = {k: v for k, v in sys.modules[module_name].__dict__.items() if isinstance(v, type)}
|
|
@@ -358,12 +400,20 @@ def _is_model(obj: typing.Any) -> bool:
|
|
|
358
400
|
return getattr(obj, "_is_model", False)
|
|
359
401
|
|
|
360
402
|
|
|
361
|
-
def _serialize(o):
|
|
403
|
+
def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements
|
|
404
|
+
if isinstance(o, list):
|
|
405
|
+
return [_serialize(x, format) for x in o]
|
|
406
|
+
if isinstance(o, dict):
|
|
407
|
+
return {k: _serialize(v, format) for k, v in o.items()}
|
|
408
|
+
if isinstance(o, set):
|
|
409
|
+
return {_serialize(x, format) for x in o}
|
|
410
|
+
if isinstance(o, tuple):
|
|
411
|
+
return tuple(_serialize(x, format) for x in o)
|
|
362
412
|
if isinstance(o, (bytes, bytearray)):
|
|
363
|
-
return _serialize_bytes(o)
|
|
413
|
+
return _serialize_bytes(o, format)
|
|
364
414
|
try:
|
|
365
415
|
# First try datetime.datetime
|
|
366
|
-
return _serialize_datetime(o)
|
|
416
|
+
return _serialize_datetime(o, format)
|
|
367
417
|
except AttributeError:
|
|
368
418
|
pass
|
|
369
419
|
# Last, try datetime.timedelta
|
|
@@ -385,7 +435,7 @@ def _get_rest_field(
|
|
|
385
435
|
|
|
386
436
|
|
|
387
437
|
def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any:
|
|
388
|
-
return _deserialize(rf._type, value) if (rf and rf._is_model) else _serialize(value)
|
|
438
|
+
return _deserialize(rf._type, value) if (rf and rf._is_model) else _serialize(value, rf._format if rf else None)
|
|
389
439
|
|
|
390
440
|
|
|
391
441
|
class Model(_MyMutableMapping):
|
|
@@ -409,10 +459,13 @@ class Model(_MyMutableMapping):
|
|
|
409
459
|
if non_attr_kwargs:
|
|
410
460
|
# actual type errors only throw the first wrong keyword arg they see, so following that.
|
|
411
461
|
raise TypeError(f"{class_name}.__init__() got an unexpected keyword argument '{non_attr_kwargs[0]}'")
|
|
412
|
-
dict_to_pass.update(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
462
|
+
dict_to_pass.update(
|
|
463
|
+
{
|
|
464
|
+
self._attr_to_rest_field[k]._rest_name: _serialize(v, self._attr_to_rest_field[k]._format)
|
|
465
|
+
for k, v in kwargs.items()
|
|
466
|
+
if v is not None
|
|
467
|
+
}
|
|
468
|
+
)
|
|
416
469
|
super().__init__(dict_to_pass)
|
|
417
470
|
|
|
418
471
|
def copy(self) -> "Model":
|
|
@@ -464,145 +517,157 @@ class Model(_MyMutableMapping):
|
|
|
464
517
|
|
|
465
518
|
|
|
466
519
|
def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
520
|
+
annotation: typing.Any,
|
|
521
|
+
module: typing.Optional[str],
|
|
522
|
+
rf: typing.Optional["_RestField"] = None,
|
|
523
|
+
) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]:
|
|
524
|
+
if not annotation or annotation in [int, float]:
|
|
525
|
+
return None
|
|
471
526
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
|
|
477
|
-
if _is_model(obj):
|
|
478
|
-
return obj
|
|
479
|
-
return _deserialize(model_deserializer, obj)
|
|
527
|
+
try:
|
|
528
|
+
if module and _is_model(_get_model(module, annotation)):
|
|
529
|
+
if rf:
|
|
530
|
+
rf._is_model = True
|
|
480
531
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
532
|
+
def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
|
|
533
|
+
if _is_model(obj):
|
|
534
|
+
return obj
|
|
535
|
+
return _deserialize(model_deserializer, obj)
|
|
484
536
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports
|
|
489
|
-
else:
|
|
490
|
-
from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports
|
|
537
|
+
return functools.partial(_deserialize_model, _get_model(module, annotation))
|
|
538
|
+
except Exception:
|
|
539
|
+
pass
|
|
491
540
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
541
|
+
# is it a literal?
|
|
542
|
+
try:
|
|
543
|
+
if sys.version_info >= (3, 8):
|
|
544
|
+
from typing import (
|
|
545
|
+
Literal,
|
|
546
|
+
) # pylint: disable=no-name-in-module, ungrouped-imports
|
|
547
|
+
else:
|
|
548
|
+
from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports
|
|
496
549
|
|
|
497
|
-
if
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return _deserialize(t, obj, module)
|
|
502
|
-
except DeserializationError:
|
|
503
|
-
pass
|
|
504
|
-
raise DeserializationError()
|
|
505
|
-
return functools.partial(_deserialize_with_union, annotation)
|
|
506
|
-
|
|
507
|
-
# is it optional?
|
|
508
|
-
try:
|
|
509
|
-
# right now, assuming we don't have unions, since we're getting rid of the only
|
|
510
|
-
# union we used to have in msrest models, which was union of str and enum
|
|
511
|
-
if any(a for a in annotation.__args__ if a == type(None)):
|
|
550
|
+
if annotation.__origin__ == Literal:
|
|
551
|
+
return None
|
|
552
|
+
except AttributeError:
|
|
553
|
+
pass
|
|
512
554
|
|
|
513
|
-
|
|
514
|
-
next(a for a in annotation.__args__ if a != type(None)), module, rf
|
|
515
|
-
)
|
|
555
|
+
if getattr(annotation, "__origin__", None) is typing.Union:
|
|
516
556
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
return
|
|
557
|
+
def _deserialize_with_union(union_annotation, obj):
|
|
558
|
+
for t in union_annotation.__args__:
|
|
559
|
+
try:
|
|
560
|
+
return _deserialize(t, obj, module, rf)
|
|
561
|
+
except DeserializationError:
|
|
562
|
+
pass
|
|
563
|
+
raise DeserializationError()
|
|
521
564
|
|
|
522
|
-
|
|
523
|
-
except AttributeError:
|
|
524
|
-
pass
|
|
565
|
+
return functools.partial(_deserialize_with_union, annotation)
|
|
525
566
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
567
|
+
# is it optional?
|
|
568
|
+
try:
|
|
569
|
+
# right now, assuming we don't have unions, since we're getting rid of the only
|
|
570
|
+
# union we used to have in msrest models, which was union of str and enum
|
|
571
|
+
if any(a for a in annotation.__args__ if a == type(None)):
|
|
572
|
+
if_obj_deserializer = _get_deserialize_callable_from_annotation(
|
|
573
|
+
next(a for a in annotation.__args__ if a != type(None)), module, rf
|
|
574
|
+
)
|
|
534
575
|
|
|
576
|
+
def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj):
|
|
577
|
+
if obj is None:
|
|
578
|
+
return obj
|
|
579
|
+
return _deserialize_with_callable(if_obj_deserializer, obj)
|
|
580
|
+
|
|
581
|
+
return functools.partial(_deserialize_with_optional, if_obj_deserializer)
|
|
582
|
+
except AttributeError:
|
|
583
|
+
pass
|
|
584
|
+
|
|
585
|
+
# is it a forward ref / in quotes?
|
|
586
|
+
if isinstance(annotation, (str, typing.ForwardRef)):
|
|
535
587
|
try:
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
entry_deserializers
|
|
572
|
-
_get_deserialize_callable_from_annotation(dt, module, rf) for dt in annotation.__args__
|
|
573
|
-
]
|
|
574
|
-
return functools.partial(_deserialize_multiple_sequence, entry_deserializers)
|
|
575
|
-
deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module, rf)
|
|
576
|
-
|
|
577
|
-
def _deserialize_sequence(
|
|
578
|
-
deserializer: typing.Optional[typing.Callable],
|
|
588
|
+
model_name = annotation.__forward_arg__ # type: ignore
|
|
589
|
+
except AttributeError:
|
|
590
|
+
model_name = annotation
|
|
591
|
+
if module is not None:
|
|
592
|
+
annotation = _get_model(module, model_name)
|
|
593
|
+
|
|
594
|
+
try:
|
|
595
|
+
if annotation._name == "Dict":
|
|
596
|
+
key_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module, rf)
|
|
597
|
+
value_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[1], module, rf)
|
|
598
|
+
|
|
599
|
+
def _deserialize_dict(
|
|
600
|
+
key_deserializer: typing.Optional[typing.Callable],
|
|
601
|
+
value_deserializer: typing.Optional[typing.Callable],
|
|
602
|
+
obj: typing.Dict[typing.Any, typing.Any],
|
|
603
|
+
):
|
|
604
|
+
if obj is None:
|
|
605
|
+
return obj
|
|
606
|
+
return {
|
|
607
|
+
_deserialize(key_deserializer, k, module): _deserialize(value_deserializer, v, module)
|
|
608
|
+
for k, v in obj.items()
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return functools.partial(
|
|
612
|
+
_deserialize_dict,
|
|
613
|
+
key_deserializer,
|
|
614
|
+
value_deserializer,
|
|
615
|
+
)
|
|
616
|
+
except (AttributeError, IndexError):
|
|
617
|
+
pass
|
|
618
|
+
try:
|
|
619
|
+
if annotation._name in ["List", "Set", "Tuple", "Sequence"]:
|
|
620
|
+
if len(annotation.__args__) > 1:
|
|
621
|
+
|
|
622
|
+
def _deserialize_multiple_sequence(
|
|
623
|
+
entry_deserializers: typing.List[typing.Optional[typing.Callable]],
|
|
579
624
|
obj,
|
|
580
625
|
):
|
|
581
626
|
if obj is None:
|
|
582
627
|
return obj
|
|
583
|
-
return type(obj)(
|
|
628
|
+
return type(obj)(
|
|
629
|
+
_deserialize(deserializer, entry, module)
|
|
630
|
+
for entry, deserializer in zip(obj, entry_deserializers)
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
entry_deserializers = [
|
|
634
|
+
_get_deserialize_callable_from_annotation(dt, module, rf) for dt in annotation.__args__
|
|
635
|
+
]
|
|
636
|
+
return functools.partial(_deserialize_multiple_sequence, entry_deserializers)
|
|
637
|
+
deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module, rf)
|
|
638
|
+
|
|
639
|
+
def _deserialize_sequence(
|
|
640
|
+
deserializer: typing.Optional[typing.Callable],
|
|
641
|
+
obj,
|
|
642
|
+
):
|
|
643
|
+
if obj is None:
|
|
644
|
+
return obj
|
|
645
|
+
return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)
|
|
646
|
+
|
|
647
|
+
return functools.partial(_deserialize_sequence, deserializer)
|
|
648
|
+
except (TypeError, IndexError, AttributeError, SyntaxError):
|
|
649
|
+
pass
|
|
584
650
|
|
|
585
|
-
|
|
586
|
-
|
|
651
|
+
def _deserialize_default(
|
|
652
|
+
annotation,
|
|
653
|
+
deserializer_from_mapping,
|
|
654
|
+
obj,
|
|
655
|
+
):
|
|
656
|
+
if obj is None:
|
|
657
|
+
return obj
|
|
658
|
+
try:
|
|
659
|
+
return _deserialize_with_callable(annotation, obj)
|
|
660
|
+
except Exception:
|
|
587
661
|
pass
|
|
662
|
+
return _deserialize_with_callable(deserializer_from_mapping, obj)
|
|
588
663
|
|
|
589
|
-
|
|
590
|
-
annotation,
|
|
591
|
-
deserializer_from_mapping,
|
|
592
|
-
obj,
|
|
593
|
-
):
|
|
594
|
-
if obj is None:
|
|
595
|
-
return obj
|
|
596
|
-
try:
|
|
597
|
-
return _deserialize_with_callable(annotation, obj)
|
|
598
|
-
except Exception:
|
|
599
|
-
pass
|
|
600
|
-
return _deserialize_with_callable(deserializer_from_mapping, obj)
|
|
601
|
-
|
|
602
|
-
return functools.partial(_deserialize_default, annotation, _DESERIALIZE_MAPPING.get(annotation))
|
|
664
|
+
return functools.partial(_deserialize_default, annotation, get_deserializer(annotation, rf))
|
|
603
665
|
|
|
604
666
|
|
|
605
|
-
def _deserialize_with_callable(
|
|
667
|
+
def _deserialize_with_callable(
|
|
668
|
+
deserializer: typing.Optional[typing.Callable[[typing.Any], typing.Any]],
|
|
669
|
+
value: typing.Any,
|
|
670
|
+
):
|
|
606
671
|
try:
|
|
607
672
|
if value is None:
|
|
608
673
|
return None
|
|
@@ -621,12 +686,18 @@ def _deserialize_with_callable(deserializer: typing.Optional[typing.Callable[[ty
|
|
|
621
686
|
raise DeserializationError() from e
|
|
622
687
|
|
|
623
688
|
|
|
624
|
-
def _deserialize(
|
|
689
|
+
def _deserialize(
|
|
690
|
+
deserializer: typing.Any,
|
|
691
|
+
value: typing.Any,
|
|
692
|
+
module: typing.Optional[str] = None,
|
|
693
|
+
rf: typing.Optional["_RestField"] = None,
|
|
694
|
+
) -> typing.Any:
|
|
625
695
|
if isinstance(value, PipelineResponse):
|
|
626
696
|
value = value.http_response.json()
|
|
627
|
-
deserializer = _get_deserialize_callable_from_annotation(deserializer, module)
|
|
697
|
+
deserializer = _get_deserialize_callable_from_annotation(deserializer, module, rf)
|
|
628
698
|
return _deserialize_with_callable(deserializer, value)
|
|
629
699
|
|
|
700
|
+
|
|
630
701
|
class _RestField:
|
|
631
702
|
def __init__(
|
|
632
703
|
self,
|
|
@@ -636,6 +707,7 @@ class _RestField:
|
|
|
636
707
|
is_discriminator: bool = False,
|
|
637
708
|
visibility: typing.Optional[typing.List[str]] = None,
|
|
638
709
|
default: typing.Any = _UNSET,
|
|
710
|
+
format: typing.Optional[str] = None,
|
|
639
711
|
):
|
|
640
712
|
self._type = type
|
|
641
713
|
self._rest_name_input = name
|
|
@@ -644,6 +716,7 @@ class _RestField:
|
|
|
644
716
|
self._visibility = visibility
|
|
645
717
|
self._is_model = False
|
|
646
718
|
self._default = default
|
|
719
|
+
self._format = format
|
|
647
720
|
|
|
648
721
|
@property
|
|
649
722
|
def _rest_name(self) -> str:
|
|
@@ -657,7 +730,7 @@ class _RestField:
|
|
|
657
730
|
item = obj.get(self._rest_name)
|
|
658
731
|
if item is None:
|
|
659
732
|
return item
|
|
660
|
-
return _deserialize(self._type, _serialize(item))
|
|
733
|
+
return _deserialize(self._type, _serialize(item, self._format), rf=self)
|
|
661
734
|
|
|
662
735
|
def __set__(self, obj: Model, value) -> None:
|
|
663
736
|
if value is None:
|
|
@@ -669,7 +742,7 @@ class _RestField:
|
|
|
669
742
|
return
|
|
670
743
|
if self._is_model and not _is_model(value):
|
|
671
744
|
obj.__setitem__(self._rest_name, _deserialize(self._type, value))
|
|
672
|
-
obj.__setitem__(self._rest_name, _serialize(value))
|
|
745
|
+
obj.__setitem__(self._rest_name, _serialize(value, self._format))
|
|
673
746
|
|
|
674
747
|
def _get_deserialize_callable_from_annotation(
|
|
675
748
|
self, annotation: typing.Any
|
|
@@ -683,8 +756,9 @@ def rest_field(
|
|
|
683
756
|
type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
|
|
684
757
|
visibility: typing.Optional[typing.List[str]] = None,
|
|
685
758
|
default: typing.Any = _UNSET,
|
|
759
|
+
format: typing.Optional[str] = None,
|
|
686
760
|
) -> typing.Any:
|
|
687
|
-
return _RestField(name=name, type=type, visibility=visibility, default=default)
|
|
761
|
+
return _RestField(name=name, type=type, visibility=visibility, default=default, format=format)
|
|
688
762
|
|
|
689
763
|
|
|
690
764
|
def rest_discriminator(
|
|
@@ -744,6 +744,8 @@ class Serializer(object):
|
|
|
744
744
|
|
|
745
745
|
:param data: The data to be serialized.
|
|
746
746
|
:param str data_type: The type to be serialized from.
|
|
747
|
+
:keyword bool skip_quote: Whether to skip quote the serialized result.
|
|
748
|
+
Defaults to False.
|
|
747
749
|
:rtype: str
|
|
748
750
|
:raises: TypeError if serialization fails.
|
|
749
751
|
:raises: ValueError if data is None
|
|
@@ -752,10 +754,8 @@ class Serializer(object):
|
|
|
752
754
|
# Treat the list aside, since we don't want to encode the div separator
|
|
753
755
|
if data_type.startswith("["):
|
|
754
756
|
internal_data_type = data_type[1:-1]
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
data = [quote(str(d), safe="") for d in data]
|
|
758
|
-
return str(self.serialize_iter(data, internal_data_type, **kwargs))
|
|
757
|
+
do_quote = not kwargs.get('skip_quote', False)
|
|
758
|
+
return str(self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs))
|
|
759
759
|
|
|
760
760
|
# Not a list, regular serialization
|
|
761
761
|
output = self.serialize_data(data, data_type, **kwargs)
|
|
@@ -894,6 +894,8 @@ class Serializer(object):
|
|
|
894
894
|
not be None or empty.
|
|
895
895
|
:param str div: If set, this str will be used to combine the elements
|
|
896
896
|
in the iterable into a combined string. Default is 'None'.
|
|
897
|
+
:keyword bool do_quote: Whether to quote the serialized result of each iterable element.
|
|
898
|
+
Defaults to False.
|
|
897
899
|
:rtype: list, str
|
|
898
900
|
"""
|
|
899
901
|
if isinstance(data, str):
|
|
@@ -911,6 +913,13 @@ class Serializer(object):
|
|
|
911
913
|
raise
|
|
912
914
|
serialized.append(None)
|
|
913
915
|
|
|
916
|
+
if kwargs.get('do_quote', False):
|
|
917
|
+
serialized = [
|
|
918
|
+
'' if s is None else quote(str(s), safe='')
|
|
919
|
+
for s
|
|
920
|
+
in serialized
|
|
921
|
+
]
|
|
922
|
+
|
|
914
923
|
if div:
|
|
915
924
|
serialized = ["" if s is None else str(s) for s in serialized]
|
|
916
925
|
serialized = div.join(serialized)
|
|
@@ -32,3 +32,32 @@ def raise_if_not_implemented(cls, abstract_methods):
|
|
|
32
32
|
cls.__name__, '\', \''.join(not_implemented))
|
|
33
33
|
)
|
|
34
34
|
{% endif %}
|
|
35
|
+
|
|
36
|
+
{% if code_model.has_etag %}
|
|
37
|
+
def quote_etag(etag: Optional[str]) -> Optional[str]:
|
|
38
|
+
if not etag or etag == "*":
|
|
39
|
+
return etag
|
|
40
|
+
if etag.startswith('"') and etag.endswith('"'):
|
|
41
|
+
return etag
|
|
42
|
+
if etag.startswith("'") and etag.endswith("'"):
|
|
43
|
+
return etag
|
|
44
|
+
return '"' + etag + '"'
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]:
|
|
48
|
+
if match_condition == MatchConditions.IfNotModified:
|
|
49
|
+
if_match = quote_etag(etag) if etag else None
|
|
50
|
+
return if_match
|
|
51
|
+
if match_condition == MatchConditions.IfPresent:
|
|
52
|
+
return "*"
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]:
|
|
57
|
+
if match_condition == MatchConditions.IfModified:
|
|
58
|
+
if_none_match = quote_etag(etag) if etag else None
|
|
59
|
+
return if_none_match
|
|
60
|
+
if match_condition == MatchConditions.IfMissing:
|
|
61
|
+
return "*"
|
|
62
|
+
return None
|
|
63
|
+
{% endif %}
|