@autorest/python 6.2.12 → 6.2.16
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/__init__.py +7 -5
- package/autorest/_utils.py +7 -1
- package/autorest/black/__init__.py +6 -1
- package/autorest/codegen/__init__.py +1 -1
- package/autorest/codegen/models/base.py +4 -13
- package/autorest/codegen/models/client.py +9 -11
- package/autorest/codegen/models/code_model.py +2 -2
- package/autorest/codegen/models/credential_types.py +7 -14
- package/autorest/codegen/models/dictionary_type.py +1 -1
- package/autorest/codegen/models/imports.py +3 -3
- package/autorest/codegen/models/lro_operation.py +5 -5
- package/autorest/codegen/models/model_type.py +11 -8
- package/autorest/codegen/models/operation.py +8 -8
- package/autorest/codegen/models/operation_group.py +3 -1
- package/autorest/codegen/models/paging_operation.py +2 -2
- package/autorest/codegen/models/parameter.py +27 -6
- package/autorest/codegen/models/parameter_list.py +1 -9
- package/autorest/codegen/models/primitive_types.py +1 -1
- package/autorest/codegen/models/property.py +15 -3
- package/autorest/codegen/models/response.py +2 -2
- package/autorest/codegen/serializers/__init__.py +2 -2
- package/autorest/codegen/serializers/builder_serializer.py +55 -25
- package/autorest/codegen/serializers/client_serializer.py +6 -4
- package/autorest/codegen/serializers/general_serializer.py +7 -2
- package/autorest/codegen/serializers/model_serializer.py +14 -4
- package/autorest/codegen/serializers/sample_serializer.py +2 -6
- package/autorest/codegen/templates/config.py.jinja2 +25 -6
- package/autorest/codegen/templates/enum.py.jinja2 +2 -2
- package/autorest/codegen/templates/metadata.json.jinja2 +18 -9
- package/autorest/codegen/templates/model_base.py.jinja2 +87 -70
- package/autorest/codegen/templates/model_dpg.py.jinja2 +6 -4
- package/autorest/codegen/templates/serialization.py.jinja2 +20 -15
- package/autorest/codegen/templates/vendor.py.jinja2 +3 -2
- package/autorest/jsonrpc/localapi.py +3 -3
- package/autorest/jsonrpc/server.py +3 -3
- package/autorest/m2r/__init__.py +1 -1
- package/autorest/m4reformatter/__init__.py +12 -2
- package/autorest/multiapi/models/__init__.py +2 -0
- package/autorest/multiapi/models/code_model.py +13 -0
- package/autorest/multiapi/models/global_parameter.py +1 -0
- package/autorest/multiapi/models/imports.py +3 -3
- package/autorest/multiapi/serializers/__init__.py +30 -3
- package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +8 -12
- package/autorest/postprocess/get_all.py +3 -1
- package/autorest/postprocess/venvtools.py +5 -4
- package/autorest/preprocess/__init__.py +16 -4
- package/autorest/preprocess/python_mappings.py +1 -0
- package/index.js +0 -0
- package/package.json +2 -1
- package/requirements.txt +6 -6
- package/setup.py +0 -1
- package/venvtools.py +2 -3
|
@@ -4,22 +4,24 @@
|
|
|
4
4
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
5
5
|
# license information.
|
|
6
6
|
# --------------------------------------------------------------------------
|
|
7
|
+
# pylint: disable=protected-access, arguments-differ, signature-differs, broad-except
|
|
8
|
+
# pyright: reportGeneralTypeIssues=false
|
|
7
9
|
|
|
8
10
|
import functools
|
|
9
11
|
import sys
|
|
10
12
|
import logging
|
|
11
13
|
import base64
|
|
12
14
|
import re
|
|
13
|
-
import
|
|
14
|
-
from json import JSONEncoder
|
|
15
|
+
import copy
|
|
15
16
|
import typing
|
|
16
|
-
from datetime import datetime, date, time, timedelta
|
|
17
|
-
from azure.core.utils._utils import _FixedOffset
|
|
18
17
|
from collections.abc import MutableMapping
|
|
18
|
+
from datetime import datetime, date, time, timedelta, timezone
|
|
19
|
+
from json import JSONEncoder
|
|
20
|
+
import isodate
|
|
19
21
|
from azure.core.exceptions import DeserializationError
|
|
20
22
|
from azure.core import CaseInsensitiveEnumMeta
|
|
21
23
|
from azure.core.pipeline import PipelineResponse
|
|
22
|
-
import
|
|
24
|
+
from azure.core.serialization import NULL as AzureCoreNull
|
|
23
25
|
|
|
24
26
|
_LOGGER = logging.getLogger(__name__)
|
|
25
27
|
|
|
@@ -41,11 +43,16 @@ A falsy sentinel object which is supposed to be used to specify attributes
|
|
|
41
43
|
with no data. This gets serialized to `null` on the wire.
|
|
42
44
|
"""
|
|
43
45
|
|
|
46
|
+
TZ_UTC = timezone.utc
|
|
44
47
|
|
|
45
48
|
def _timedelta_as_isostr(td: timedelta) -> str:
|
|
46
49
|
"""Converts a datetime.timedelta object into an ISO 8601 formatted string, e.g. 'P4DT12H30M05S'
|
|
47
50
|
|
|
48
51
|
Function adapted from the Tin Can Python project: https://github.com/RusticiSoftware/TinCanPython
|
|
52
|
+
|
|
53
|
+
:param timedelta td: The timedelta to convert
|
|
54
|
+
:rtype: str
|
|
55
|
+
:return: ISO8601 version of this timedelta
|
|
49
56
|
"""
|
|
50
57
|
|
|
51
58
|
# Split seconds to larger units
|
|
@@ -93,7 +100,12 @@ def _timedelta_as_isostr(td: timedelta) -> str:
|
|
|
93
100
|
|
|
94
101
|
|
|
95
102
|
def _datetime_as_isostr(dt: typing.Union[datetime, date, time, timedelta]) -> str:
|
|
96
|
-
"""Converts a datetime.(datetime|date|time|timedelta) object into an ISO 8601 formatted string
|
|
103
|
+
"""Converts a datetime.(datetime|date|time|timedelta) object into an ISO 8601 formatted string
|
|
104
|
+
|
|
105
|
+
:param timedelta dt: The date object to convert
|
|
106
|
+
:rtype: str
|
|
107
|
+
:return: ISO8601 version of this datetime
|
|
108
|
+
"""
|
|
97
109
|
# First try datetime.datetime
|
|
98
110
|
if hasattr(dt, "year") and hasattr(dt, "hour"):
|
|
99
111
|
dt = typing.cast(datetime, dt)
|
|
@@ -113,15 +125,6 @@ def _datetime_as_isostr(dt: typing.Union[datetime, date, time, timedelta]) -> st
|
|
|
113
125
|
dt = typing.cast(timedelta, dt)
|
|
114
126
|
return _timedelta_as_isostr(dt)
|
|
115
127
|
|
|
116
|
-
|
|
117
|
-
try:
|
|
118
|
-
from datetime import timezone
|
|
119
|
-
|
|
120
|
-
TZ_UTC = timezone.utc # type: ignore
|
|
121
|
-
except ImportError:
|
|
122
|
-
TZ_UTC = _FixedOffset(0) # type: ignore
|
|
123
|
-
|
|
124
|
-
|
|
125
128
|
def _serialize_bytes(o) -> str:
|
|
126
129
|
return base64.b64encode(o).decode()
|
|
127
130
|
|
|
@@ -141,7 +144,7 @@ def _serialize_datetime(o):
|
|
|
141
144
|
|
|
142
145
|
def _is_readonly(p):
|
|
143
146
|
try:
|
|
144
|
-
return p._readonly
|
|
147
|
+
return p._readonly # pylint: disable=protected-access
|
|
145
148
|
except AttributeError:
|
|
146
149
|
return False
|
|
147
150
|
|
|
@@ -151,10 +154,12 @@ class AzureJSONEncoder(JSONEncoder):
|
|
|
151
154
|
|
|
152
155
|
def default(self, o): # pylint: disable=too-many-return-statements
|
|
153
156
|
if _is_model(o):
|
|
154
|
-
readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)]
|
|
157
|
+
readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] # pylint: disable=protected-access
|
|
155
158
|
return {k: v for k, v in o.items() if k not in readonly_props}
|
|
156
159
|
if isinstance(o, (bytes, bytearray)):
|
|
157
160
|
return base64.b64encode(o).decode()
|
|
161
|
+
if o is AzureCoreNull:
|
|
162
|
+
return None
|
|
158
163
|
try:
|
|
159
164
|
return super(AzureJSONEncoder, self).default(o)
|
|
160
165
|
except TypeError:
|
|
@@ -174,7 +179,7 @@ class AzureJSONEncoder(JSONEncoder):
|
|
|
174
179
|
return super(AzureJSONEncoder, self).default(o)
|
|
175
180
|
|
|
176
181
|
|
|
177
|
-
_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}]?")
|
|
182
|
+
_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}]?")
|
|
178
183
|
|
|
179
184
|
|
|
180
185
|
def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
|
|
@@ -182,6 +187,7 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
|
|
|
182
187
|
|
|
183
188
|
:param str attr: response string to be deserialized.
|
|
184
189
|
:rtype: ~datetime.datetime
|
|
190
|
+
:returns: The datetime object from that input
|
|
185
191
|
"""
|
|
186
192
|
if isinstance(attr, datetime):
|
|
187
193
|
# i'm already deserialized
|
|
@@ -212,7 +218,8 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
|
|
|
212
218
|
def _deserialize_date(attr: typing.Union[str, date]) -> date:
|
|
213
219
|
"""Deserialize ISO-8601 formatted string into Date object.
|
|
214
220
|
:param str attr: response string to be deserialized.
|
|
215
|
-
:rtype:
|
|
221
|
+
:rtype: date
|
|
222
|
+
:returns: The date object from that input
|
|
216
223
|
"""
|
|
217
224
|
# This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception.
|
|
218
225
|
if isinstance(attr, date):
|
|
@@ -225,6 +232,7 @@ def _deserialize_time(attr: typing.Union[str, time]) -> time:
|
|
|
225
232
|
|
|
226
233
|
:param str attr: response string to be deserialized.
|
|
227
234
|
:rtype: datetime.time
|
|
235
|
+
:returns: The time object from that input
|
|
228
236
|
"""
|
|
229
237
|
if isinstance(attr, time):
|
|
230
238
|
return attr
|
|
@@ -258,7 +266,8 @@ def _get_model(module_name: str, model_name: str):
|
|
|
258
266
|
module_end = module_name.rsplit(".", 1)[0]
|
|
259
267
|
module = sys.modules[module_end]
|
|
260
268
|
models.update({k: v for k, v in module.__dict__.items() if isinstance(v, type)})
|
|
261
|
-
model_name
|
|
269
|
+
if isinstance(model_name, str):
|
|
270
|
+
model_name = model_name.split(".")[-1]
|
|
262
271
|
if model_name not in models:
|
|
263
272
|
return model_name
|
|
264
273
|
return models[model_name]
|
|
@@ -271,7 +280,7 @@ class _MyMutableMapping(MutableMapping):
|
|
|
271
280
|
def __init__(self, data: typing.Dict[str, typing.Any]) -> None:
|
|
272
281
|
self._data = copy.deepcopy(data)
|
|
273
282
|
|
|
274
|
-
def __contains__(self, key:
|
|
283
|
+
def __contains__(self, key: typing.Any) -> bool:
|
|
275
284
|
return key in self._data
|
|
276
285
|
|
|
277
286
|
def __getitem__(self, key: str) -> typing.Any:
|
|
@@ -307,15 +316,15 @@ class _MyMutableMapping(MutableMapping):
|
|
|
307
316
|
except KeyError:
|
|
308
317
|
return default
|
|
309
318
|
|
|
310
|
-
@typing.overload
|
|
311
|
-
def pop(self, key: str) -> typing.Any:
|
|
319
|
+
@typing.overload # type: ignore
|
|
320
|
+
def pop(self, key: str) -> typing.Any: # pylint: disable=no-member
|
|
312
321
|
...
|
|
313
322
|
|
|
314
323
|
@typing.overload
|
|
315
324
|
def pop(self, key: str, default: typing.Any) -> typing.Any:
|
|
316
325
|
...
|
|
317
326
|
|
|
318
|
-
def pop(self, key:
|
|
327
|
+
def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
|
|
319
328
|
if default is _UNSET:
|
|
320
329
|
return self._data.pop(key)
|
|
321
330
|
return self._data.pop(key, default)
|
|
@@ -329,7 +338,7 @@ class _MyMutableMapping(MutableMapping):
|
|
|
329
338
|
def update(self, *args: typing.Any, **kwargs: typing.Any) -> None:
|
|
330
339
|
self._data.update(*args, **kwargs)
|
|
331
340
|
|
|
332
|
-
@typing.overload
|
|
341
|
+
@typing.overload # type: ignore
|
|
333
342
|
def setdefault(self, key: str) -> typing.Any:
|
|
334
343
|
...
|
|
335
344
|
|
|
@@ -337,7 +346,7 @@ class _MyMutableMapping(MutableMapping):
|
|
|
337
346
|
def setdefault(self, key: str, default: typing.Any) -> typing.Any:
|
|
338
347
|
...
|
|
339
348
|
|
|
340
|
-
def setdefault(self, key:
|
|
349
|
+
def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
|
|
341
350
|
if default is _UNSET:
|
|
342
351
|
return self._data.setdefault(key)
|
|
343
352
|
return self._data.setdefault(key, default)
|
|
@@ -383,8 +392,8 @@ def _get_rest_field(
|
|
|
383
392
|
return None
|
|
384
393
|
|
|
385
394
|
|
|
386
|
-
def _create_value(
|
|
387
|
-
return _deserialize(
|
|
395
|
+
def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any:
|
|
396
|
+
return _deserialize(rf._type, value) if (rf and rf._is_model) else _serialize(value)
|
|
388
397
|
|
|
389
398
|
|
|
390
399
|
class Model(_MyMutableMapping):
|
|
@@ -414,7 +423,7 @@ class Model(_MyMutableMapping):
|
|
|
414
423
|
def copy(self):
|
|
415
424
|
return Model(self.__dict__)
|
|
416
425
|
|
|
417
|
-
def __new__(cls, *args: typing.Any, **kwargs: typing.Any):
|
|
426
|
+
def __new__(cls, *args: typing.Any, **kwargs: typing.Any): # pylint: disable=unused-argument
|
|
418
427
|
# we know the last three classes in mro are going to be 'Model', 'dict', and 'object'
|
|
419
428
|
mros = cls.__mro__[:-3][::-1] # ignore model, dict, and object parents, and reverse the mro order
|
|
420
429
|
attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
|
|
@@ -423,50 +432,52 @@ class Model(_MyMutableMapping):
|
|
|
423
432
|
annotations = {
|
|
424
433
|
k: v
|
|
425
434
|
for mro_class in mros
|
|
426
|
-
if hasattr(mro_class, "__annotations__")
|
|
427
|
-
for k, v in mro_class.__annotations__.items()
|
|
435
|
+
if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
|
|
436
|
+
for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
|
|
428
437
|
}
|
|
429
|
-
for attr,
|
|
430
|
-
|
|
431
|
-
if not
|
|
432
|
-
|
|
433
|
-
if not
|
|
434
|
-
|
|
435
|
-
cls._attr_to_rest_field: typing.Dict[str, _RestField] =
|
|
438
|
+
for attr, rf in attr_to_rest_field.items():
|
|
439
|
+
rf._module = cls.__module__
|
|
440
|
+
if not rf._type:
|
|
441
|
+
rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
|
|
442
|
+
if not rf._rest_name_input:
|
|
443
|
+
rf._rest_name_input = attr
|
|
444
|
+
cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
|
|
436
445
|
|
|
437
446
|
return super().__new__(cls)
|
|
438
447
|
|
|
439
448
|
def __init_subclass__(cls, discriminator=None):
|
|
440
449
|
for base in cls.__bases__:
|
|
441
|
-
if hasattr(base, "__mapping__"):
|
|
442
|
-
base.__mapping__[discriminator or cls.__name__] = cls
|
|
450
|
+
if hasattr(base, "__mapping__"): # pylint: disable=no-member
|
|
451
|
+
base.__mapping__[discriminator or cls.__name__] = cls # pylint: disable=no-member
|
|
443
452
|
|
|
444
453
|
@classmethod
|
|
445
454
|
def _get_discriminator(cls) -> typing.Optional[str]:
|
|
446
455
|
for v in cls.__dict__.values():
|
|
447
|
-
if isinstance(v, _RestField) and v._is_discriminator:
|
|
448
|
-
return v._rest_name
|
|
456
|
+
if isinstance(v, _RestField) and v._is_discriminator: # pylint: disable=protected-access
|
|
457
|
+
return v._rest_name # pylint: disable=protected-access
|
|
449
458
|
return None
|
|
450
459
|
|
|
451
460
|
@classmethod
|
|
452
461
|
def _deserialize(cls, data):
|
|
453
|
-
if not hasattr(cls, "__mapping__"):
|
|
462
|
+
if not hasattr(cls, "__mapping__"): # pylint: disable=no-member
|
|
454
463
|
return cls(data)
|
|
455
464
|
discriminator = cls._get_discriminator()
|
|
456
|
-
mapped_cls = cls.__mapping__.get(data.get(discriminator), cls)
|
|
465
|
+
mapped_cls = cls.__mapping__.get(data.get(discriminator), cls) # pylint: disable=no-member
|
|
457
466
|
if mapped_cls == cls:
|
|
458
467
|
return cls(data)
|
|
459
|
-
return mapped_cls._deserialize(data)
|
|
468
|
+
return mapped_cls._deserialize(data) # pylint: disable=protected-access
|
|
460
469
|
|
|
461
470
|
|
|
462
|
-
def _get_deserialize_callable_from_annotation(
|
|
463
|
-
annotation: typing.Any, module: str,
|
|
471
|
+
def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements
|
|
472
|
+
annotation: typing.Any, module: typing.Optional[str], rf: "_RestField" = None
|
|
464
473
|
) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]:
|
|
465
474
|
if not annotation or annotation in [int, float]:
|
|
466
475
|
return None
|
|
467
476
|
|
|
468
477
|
try:
|
|
469
|
-
if _is_model(_get_model(module, annotation)):
|
|
478
|
+
if module and _is_model(_get_model(module, annotation)):
|
|
479
|
+
if rf:
|
|
480
|
+
rf._is_model = True
|
|
470
481
|
def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
|
|
471
482
|
if _is_model(obj):
|
|
472
483
|
return obj
|
|
@@ -478,21 +489,25 @@ def _get_deserialize_callable_from_annotation(
|
|
|
478
489
|
|
|
479
490
|
# is it a literal?
|
|
480
491
|
try:
|
|
481
|
-
if
|
|
492
|
+
if sys.version_info >= (3, 8):
|
|
493
|
+
from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports
|
|
494
|
+
else:
|
|
495
|
+
from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports
|
|
496
|
+
|
|
497
|
+
if annotation.__origin__ == Literal:
|
|
482
498
|
return None
|
|
483
499
|
except AttributeError:
|
|
484
500
|
pass
|
|
485
501
|
|
|
486
|
-
if
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
return functools.partial(_deserialize_with_union, annotation)
|
|
502
|
+
if getattr(annotation, "__origin__", None) is typing.Union:
|
|
503
|
+
def _deserialize_with_union(union_annotation, obj):
|
|
504
|
+
for t in union_annotation.__args__:
|
|
505
|
+
try:
|
|
506
|
+
return _deserialize(t, obj, module)
|
|
507
|
+
except DeserializationError:
|
|
508
|
+
pass
|
|
509
|
+
raise DeserializationError()
|
|
510
|
+
return functools.partial(_deserialize_with_union, annotation)
|
|
496
511
|
|
|
497
512
|
# is it optional?
|
|
498
513
|
try:
|
|
@@ -501,7 +516,7 @@ def _get_deserialize_callable_from_annotation(
|
|
|
501
516
|
if any(a for a in annotation.__args__ if a == type(None)):
|
|
502
517
|
|
|
503
518
|
if_obj_deserializer = _get_deserialize_callable_from_annotation(
|
|
504
|
-
next(a for a in annotation.__args__ if a != type(None)), module
|
|
519
|
+
next(a for a in annotation.__args__ if a != type(None)), module, rf
|
|
505
520
|
)
|
|
506
521
|
|
|
507
522
|
def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj):
|
|
@@ -510,11 +525,11 @@ def _get_deserialize_callable_from_annotation(
|
|
|
510
525
|
return _deserialize_with_callable(if_obj_deserializer, obj)
|
|
511
526
|
|
|
512
527
|
return functools.partial(_deserialize_with_optional, if_obj_deserializer)
|
|
513
|
-
except
|
|
528
|
+
except AttributeError:
|
|
514
529
|
pass
|
|
515
530
|
|
|
516
531
|
# is it a forward ref / in quotes?
|
|
517
|
-
if isinstance(annotation, str
|
|
532
|
+
if isinstance(annotation, (str, typing.ForwardRef)):
|
|
518
533
|
try:
|
|
519
534
|
model_name = annotation.__forward_arg__ # type: ignore
|
|
520
535
|
except AttributeError:
|
|
@@ -524,8 +539,8 @@ def _get_deserialize_callable_from_annotation(
|
|
|
524
539
|
|
|
525
540
|
try:
|
|
526
541
|
if annotation._name == "Dict":
|
|
527
|
-
key_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module)
|
|
528
|
-
value_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[1], module)
|
|
542
|
+
key_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module, rf)
|
|
543
|
+
value_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[1], module, rf)
|
|
529
544
|
|
|
530
545
|
def _deserialize_dict(
|
|
531
546
|
key_deserializer: typing.Optional[typing.Callable],
|
|
@@ -559,10 +574,10 @@ def _get_deserialize_callable_from_annotation(
|
|
|
559
574
|
)
|
|
560
575
|
|
|
561
576
|
entry_deserializers = [
|
|
562
|
-
_get_deserialize_callable_from_annotation(dt, module) for dt in annotation.__args__
|
|
577
|
+
_get_deserialize_callable_from_annotation(dt, module, rf) for dt in annotation.__args__
|
|
563
578
|
]
|
|
564
579
|
return functools.partial(_deserialize_multiple_sequence, entry_deserializers)
|
|
565
|
-
deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module)
|
|
580
|
+
deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module, rf)
|
|
566
581
|
|
|
567
582
|
def _deserialize_sequence(
|
|
568
583
|
deserializer: typing.Optional[typing.Callable],
|
|
@@ -596,6 +611,8 @@ def _deserialize_with_callable(deserializer: typing.Optional[typing.Callable[[ty
|
|
|
596
611
|
try:
|
|
597
612
|
if value is None:
|
|
598
613
|
return None
|
|
614
|
+
if deserializer is None:
|
|
615
|
+
return value
|
|
599
616
|
if isinstance(deserializer, CaseInsensitiveEnumMeta):
|
|
600
617
|
try:
|
|
601
618
|
return deserializer(value)
|
|
@@ -603,13 +620,13 @@ def _deserialize_with_callable(deserializer: typing.Optional[typing.Callable[[ty
|
|
|
603
620
|
# for unknown value, return raw value
|
|
604
621
|
return value
|
|
605
622
|
if isinstance(deserializer, type) and issubclass(deserializer, Model):
|
|
606
|
-
return deserializer._deserialize(value)
|
|
607
|
-
return deserializer(value)
|
|
623
|
+
return deserializer._deserialize(value) # type: ignore
|
|
624
|
+
return deserializer(value)
|
|
608
625
|
except Exception as e:
|
|
609
626
|
raise DeserializationError() from e
|
|
610
627
|
|
|
611
628
|
|
|
612
|
-
def _deserialize(deserializer: typing.
|
|
629
|
+
def _deserialize(deserializer: typing.Any, value: typing.Any, module: typing.Optional[str] = None) -> typing.Any:
|
|
613
630
|
if isinstance(value, PipelineResponse):
|
|
614
631
|
value = value.http_response.json()
|
|
615
632
|
deserializer = _get_deserialize_callable_from_annotation(deserializer, module)
|
|
@@ -662,7 +679,7 @@ class _RestField:
|
|
|
662
679
|
def _get_deserialize_callable_from_annotation(
|
|
663
680
|
self, annotation: typing.Any
|
|
664
681
|
) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]:
|
|
665
|
-
return _get_deserialize_callable_from_annotation(annotation, self._module)
|
|
682
|
+
return _get_deserialize_callable_from_annotation(annotation, self._module, self)
|
|
666
683
|
|
|
667
684
|
|
|
668
685
|
def rest_field(
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
30
|
{% if model.is_polymorphic %}
|
|
31
|
-
__mapping__ = {}
|
|
31
|
+
__mapping__: Dict[str, _model_base.Model] = {}
|
|
32
32
|
{% endif %}
|
|
33
33
|
{% for p in serializer.get_properties_to_declare(model)%}
|
|
34
34
|
{% for line in serializer.declare_property(p) %}
|
|
@@ -52,11 +52,13 @@
|
|
|
52
52
|
:param mapping: raw JSON to initialize the model.
|
|
53
53
|
:type mapping: Mapping[str, Any]
|
|
54
54
|
"""
|
|
55
|
-
...
|
|
56
55
|
|
|
57
56
|
{% endif %}
|
|
58
|
-
|
|
57
|
+
{% set initialize_properties = serializer.initialize_properties(model) %}
|
|
58
|
+
{% if model.is_public and serializer.init_line(model) or initialize_properties %}
|
|
59
|
+
def __init__(self, *args, **kwargs):{{ '# pylint: disable=useless-super-delegation' if not initialize_properties else '' }}
|
|
59
60
|
super().__init__(*args, **kwargs)
|
|
60
|
-
{% for initialize_property in
|
|
61
|
+
{% for initialize_property in initialize_properties %}
|
|
61
62
|
{{ initialize_property }}
|
|
62
63
|
{% endfor %}
|
|
64
|
+
{% endif %}
|
|
@@ -50,7 +50,9 @@ from typing import (
|
|
|
50
50
|
Callable,
|
|
51
51
|
TypeVar,
|
|
52
52
|
MutableMapping,
|
|
53
|
-
Type
|
|
53
|
+
Type,
|
|
54
|
+
List,
|
|
55
|
+
Mapping,
|
|
54
56
|
)
|
|
55
57
|
|
|
56
58
|
try:
|
|
@@ -62,6 +64,7 @@ import xml.etree.ElementTree as ET
|
|
|
62
64
|
import isodate # type: ignore
|
|
63
65
|
|
|
64
66
|
from azure.core.exceptions import DeserializationError, SerializationError, raise_with_traceback
|
|
67
|
+
from azure.core.serialization import NULL as AzureCoreNull
|
|
65
68
|
|
|
66
69
|
_BOM = codecs.BOM_UTF8.decode(encoding="utf-8")
|
|
67
70
|
|
|
@@ -358,7 +361,7 @@ class Model(object):
|
|
|
358
361
|
] = attribute_transformer,
|
|
359
362
|
**kwargs: Any
|
|
360
363
|
) -> JSON:
|
|
361
|
-
"""Return a dict that can be
|
|
364
|
+
"""Return a dict that can be serialized using json.dump.
|
|
362
365
|
|
|
363
366
|
Advanced usage might optionally use a callback as parameter:
|
|
364
367
|
|
|
@@ -436,7 +439,7 @@ class Model(object):
|
|
|
436
439
|
"""
|
|
437
440
|
deserializer = Deserializer(cls._infer_class_models())
|
|
438
441
|
deserializer.key_extractors = ( # type: ignore
|
|
439
|
-
[
|
|
442
|
+
[ # type: ignore
|
|
440
443
|
attribute_key_case_insensitive_extractor,
|
|
441
444
|
rest_key_case_insensitive_extractor,
|
|
442
445
|
last_rest_key_case_insensitive_extractor,
|
|
@@ -544,7 +547,7 @@ class Serializer(object):
|
|
|
544
547
|
"multiple": lambda x, y: x % y != 0,
|
|
545
548
|
}
|
|
546
549
|
|
|
547
|
-
def __init__(self, classes=None):
|
|
550
|
+
def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]]=None):
|
|
548
551
|
self.serialize_type = {
|
|
549
552
|
"iso-8601": Serializer.serialize_iso,
|
|
550
553
|
"rfc-1123": Serializer.serialize_rfc,
|
|
@@ -560,7 +563,7 @@ class Serializer(object):
|
|
|
560
563
|
"[]": self.serialize_iter,
|
|
561
564
|
"{}": self.serialize_dict,
|
|
562
565
|
}
|
|
563
|
-
self.dependencies = dict(classes) if classes else {}
|
|
566
|
+
self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {}
|
|
564
567
|
self.key_transformer = full_restapi_key_transformer
|
|
565
568
|
self.client_side_validation = True
|
|
566
569
|
|
|
@@ -652,8 +655,7 @@ class Serializer(object):
|
|
|
652
655
|
serialized.append(local_node) # type: ignore
|
|
653
656
|
else: # JSON
|
|
654
657
|
for k in reversed(keys): # type: ignore
|
|
655
|
-
|
|
656
|
-
new_attr = unflattened
|
|
658
|
+
new_attr = {k: new_attr}
|
|
657
659
|
|
|
658
660
|
_new_attr = new_attr
|
|
659
661
|
_serialized = serialized
|
|
@@ -682,8 +684,8 @@ class Serializer(object):
|
|
|
682
684
|
"""
|
|
683
685
|
|
|
684
686
|
# Just in case this is a dict
|
|
685
|
-
|
|
686
|
-
internal_data_type = self.dependencies.get(
|
|
687
|
+
internal_data_type_str = data_type.strip("[]{}")
|
|
688
|
+
internal_data_type = self.dependencies.get(internal_data_type_str, None)
|
|
687
689
|
try:
|
|
688
690
|
is_xml_model_serialization = kwargs["is_xml"]
|
|
689
691
|
except KeyError:
|
|
@@ -803,6 +805,8 @@ class Serializer(object):
|
|
|
803
805
|
raise ValueError("No value for given attribute")
|
|
804
806
|
|
|
805
807
|
try:
|
|
808
|
+
if data is AzureCoreNull:
|
|
809
|
+
return None
|
|
806
810
|
if data_type in self.basic_types.values():
|
|
807
811
|
return self.serialize_basic(data, data_type, **kwargs)
|
|
808
812
|
|
|
@@ -1187,7 +1191,8 @@ def rest_key_extractor(attr, attr_desc, data):
|
|
|
1187
1191
|
working_data = data
|
|
1188
1192
|
|
|
1189
1193
|
while "." in key:
|
|
1190
|
-
|
|
1194
|
+
# Need the cast, as for some reasons "split" is typed as list[str | Any]
|
|
1195
|
+
dict_keys = cast(List[str], _FLATTEN.split(key))
|
|
1191
1196
|
if len(dict_keys) == 1:
|
|
1192
1197
|
key = _decode_attribute_map_key(dict_keys[0])
|
|
1193
1198
|
break
|
|
@@ -1358,7 +1363,7 @@ class Deserializer(object):
|
|
|
1358
1363
|
|
|
1359
1364
|
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}]?")
|
|
1360
1365
|
|
|
1361
|
-
def __init__(self, classes=None):
|
|
1366
|
+
def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]]=None):
|
|
1362
1367
|
self.deserialize_type = {
|
|
1363
1368
|
"iso-8601": Deserializer.deserialize_iso,
|
|
1364
1369
|
"rfc-1123": Deserializer.deserialize_rfc,
|
|
@@ -1378,7 +1383,7 @@ class Deserializer(object):
|
|
|
1378
1383
|
"duration": (isodate.Duration, datetime.timedelta),
|
|
1379
1384
|
"iso-8601": (datetime.datetime),
|
|
1380
1385
|
}
|
|
1381
|
-
self.dependencies = dict(classes) if classes else {}
|
|
1386
|
+
self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {}
|
|
1382
1387
|
self.key_extractors = [rest_key_extractor, xml_key_extractor]
|
|
1383
1388
|
# Additional properties only works if the "rest_key_extractor" is used to
|
|
1384
1389
|
# extract the keys. Making it to work whatever the key extractor is too much
|
|
@@ -1497,7 +1502,7 @@ class Deserializer(object):
|
|
|
1497
1502
|
Once classification has been determined, initialize object.
|
|
1498
1503
|
|
|
1499
1504
|
:param str target: The target object type to deserialize to.
|
|
1500
|
-
:param str/dict data: The response data to
|
|
1505
|
+
:param str/dict data: The response data to deserialize.
|
|
1501
1506
|
"""
|
|
1502
1507
|
if target is None:
|
|
1503
1508
|
return None, None
|
|
@@ -1512,7 +1517,7 @@ class Deserializer(object):
|
|
|
1512
1517
|
target = target._classify(data, self.dependencies)
|
|
1513
1518
|
except AttributeError:
|
|
1514
1519
|
pass # Target is not a Model, no classify
|
|
1515
|
-
return target, target.__class__.__name__
|
|
1520
|
+
return target, target.__class__.__name__ # type: ignore
|
|
1516
1521
|
|
|
1517
1522
|
def failsafe_deserialize(self, target_obj, data, content_type=None):
|
|
1518
1523
|
"""Ignores any errors encountered in deserialization,
|
|
@@ -1522,7 +1527,7 @@ class Deserializer(object):
|
|
|
1522
1527
|
a deserialization error.
|
|
1523
1528
|
|
|
1524
1529
|
:param str target_obj: The target object type to deserialize to.
|
|
1525
|
-
:param str/dict data: The response data to
|
|
1530
|
+
:param str/dict data: The response data to deserialize.
|
|
1526
1531
|
:param str content_type: Swagger "produces" if available.
|
|
1527
1532
|
"""
|
|
1528
1533
|
try:
|
|
@@ -19,14 +19,15 @@ def _format_url_section(template, **kwargs):
|
|
|
19
19
|
try:
|
|
20
20
|
return template.format(**kwargs)
|
|
21
21
|
except KeyError as key:
|
|
22
|
-
|
|
22
|
+
# Need the cast, as for some reasons "split" is typed as list[str | Any]
|
|
23
|
+
formatted_components = cast(List[str], template.split("/"))
|
|
23
24
|
components = [
|
|
24
25
|
c for c in formatted_components if "{{{}}}".format(key.args[0]) not in c
|
|
25
26
|
]
|
|
26
27
|
template = "/".join(components)
|
|
27
28
|
{% endif %}
|
|
28
29
|
{% if code_model.need_mixin_abc %}
|
|
29
|
-
{% for client in
|
|
30
|
+
{% for client in clients | selectattr("has_mixin") %}
|
|
30
31
|
|
|
31
32
|
class {{ client.name }}MixinABC(ABC):
|
|
32
33
|
"""DO NOT use this class. It is for internal typing use only."""
|
|
@@ -26,17 +26,17 @@ class LocalAutorestAPI(AutorestAPI):
|
|
|
26
26
|
reachable_files = []
|
|
27
27
|
self._reachable_files = reachable_files
|
|
28
28
|
self._output_folder = Path(output_folder)
|
|
29
|
-
self.values: Dict[str, Optional[str]] =
|
|
29
|
+
self.values: Dict[str, Optional[str]] = {}
|
|
30
30
|
|
|
31
31
|
def write_file(self, filename: Union[str, Path], file_content: str) -> None:
|
|
32
32
|
_LOGGER.debug("Writing file: %s", filename)
|
|
33
|
-
with (self._output_folder / Path(filename)).open("w") as fd:
|
|
33
|
+
with (self._output_folder / Path(filename)).open("w", encoding="utf-8") as fd:
|
|
34
34
|
fd.write(file_content)
|
|
35
35
|
_LOGGER.debug("Written file: %s", filename)
|
|
36
36
|
|
|
37
37
|
def read_file(self, filename: Union[str, Path]) -> str:
|
|
38
38
|
_LOGGER.debug("Reading file: %s", filename)
|
|
39
|
-
with (self._output_folder / Path(filename)).open("r") as fd:
|
|
39
|
+
with (self._output_folder / Path(filename)).open("r", encoding="utf-8") as fd:
|
|
40
40
|
return fd.read()
|
|
41
41
|
|
|
42
42
|
def list_inputs(self) -> List[str]:
|
|
@@ -84,15 +84,15 @@ def main() -> None:
|
|
|
84
84
|
):
|
|
85
85
|
try:
|
|
86
86
|
import ptvsd # pylint: disable=import-outside-toplevel
|
|
87
|
-
except ImportError:
|
|
87
|
+
except ImportError as exc:
|
|
88
88
|
raise SystemExit(
|
|
89
89
|
"Please pip install ptvsd in order to use VSCode debugging"
|
|
90
|
-
)
|
|
90
|
+
) from exc
|
|
91
91
|
|
|
92
92
|
# 5678 is the default attach port in the VS Code debug configurations
|
|
93
93
|
ptvsd.enable_attach(address=("localhost", 5678), redirect_output=True)
|
|
94
94
|
ptvsd.wait_for_attach()
|
|
95
|
-
breakpoint() # pylint: disable=undefined-variable
|
|
95
|
+
breakpoint() # pylint: disable=undefined-variable,forgotten-debug-statement
|
|
96
96
|
|
|
97
97
|
_LOGGER.debug("Starting JSON RPC server")
|
|
98
98
|
|
package/autorest/m2r/__init__.py
CHANGED
|
@@ -22,7 +22,7 @@ class AutorestRender(m2r2.RestRenderer):
|
|
|
22
22
|
in the description/summary.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
|
-
def inline_html(self, html: str) -> str:
|
|
25
|
+
def inline_html(self, html: str) -> str:
|
|
26
26
|
"""Do not render inline HTML with a role definition."""
|
|
27
27
|
return f":code:`{html}`"
|
|
28
28
|
|
|
@@ -423,6 +423,12 @@ class M4Reformatter(
|
|
|
423
423
|
def legacy(self) -> bool:
|
|
424
424
|
return not (self.version_tolerant or self.low_level_client)
|
|
425
425
|
|
|
426
|
+
@property
|
|
427
|
+
def only_path_and_body_parameters_positional(self) -> bool:
|
|
428
|
+
return self.version_tolerant or bool(
|
|
429
|
+
self._autorestapi.get_boolean_value("only-path-and-body-params-positional")
|
|
430
|
+
)
|
|
431
|
+
|
|
426
432
|
@property
|
|
427
433
|
def default_optional_constants_to_none(self) -> bool:
|
|
428
434
|
return bool(
|
|
@@ -952,7 +958,11 @@ class M4Reformatter(
|
|
|
952
958
|
if name == "$host":
|
|
953
959
|
# I am the non-parameterized endpoint. Modify name based off of flag
|
|
954
960
|
|
|
955
|
-
client_name =
|
|
961
|
+
client_name = (
|
|
962
|
+
"endpoint"
|
|
963
|
+
if self.only_path_and_body_parameters_positional
|
|
964
|
+
else "base_url"
|
|
965
|
+
)
|
|
956
966
|
global_parameter["language"]["default"]["description"] = "Service URL."
|
|
957
967
|
elif (
|
|
958
968
|
global_parameter.get("origin") == "modelerfour:synthesized/api-version"
|
|
@@ -1083,7 +1093,7 @@ class M4Reformatter(
|
|
|
1083
1093
|
"skipUrlEncoding": True,
|
|
1084
1094
|
"inOverload": False,
|
|
1085
1095
|
}
|
|
1086
|
-
if self.
|
|
1096
|
+
if self.only_path_and_body_parameters_positional:
|
|
1087
1097
|
parameters.append(credential)
|
|
1088
1098
|
else:
|
|
1089
1099
|
parameters.insert(0, credential)
|