@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.
Files changed (52) hide show
  1. package/autorest/__init__.py +7 -5
  2. package/autorest/_utils.py +7 -1
  3. package/autorest/black/__init__.py +6 -1
  4. package/autorest/codegen/__init__.py +1 -1
  5. package/autorest/codegen/models/base.py +4 -13
  6. package/autorest/codegen/models/client.py +9 -11
  7. package/autorest/codegen/models/code_model.py +2 -2
  8. package/autorest/codegen/models/credential_types.py +7 -14
  9. package/autorest/codegen/models/dictionary_type.py +1 -1
  10. package/autorest/codegen/models/imports.py +3 -3
  11. package/autorest/codegen/models/lro_operation.py +5 -5
  12. package/autorest/codegen/models/model_type.py +11 -8
  13. package/autorest/codegen/models/operation.py +8 -8
  14. package/autorest/codegen/models/operation_group.py +3 -1
  15. package/autorest/codegen/models/paging_operation.py +2 -2
  16. package/autorest/codegen/models/parameter.py +27 -6
  17. package/autorest/codegen/models/parameter_list.py +1 -9
  18. package/autorest/codegen/models/primitive_types.py +1 -1
  19. package/autorest/codegen/models/property.py +15 -3
  20. package/autorest/codegen/models/response.py +2 -2
  21. package/autorest/codegen/serializers/__init__.py +2 -2
  22. package/autorest/codegen/serializers/builder_serializer.py +55 -25
  23. package/autorest/codegen/serializers/client_serializer.py +6 -4
  24. package/autorest/codegen/serializers/general_serializer.py +7 -2
  25. package/autorest/codegen/serializers/model_serializer.py +14 -4
  26. package/autorest/codegen/serializers/sample_serializer.py +2 -6
  27. package/autorest/codegen/templates/config.py.jinja2 +25 -6
  28. package/autorest/codegen/templates/enum.py.jinja2 +2 -2
  29. package/autorest/codegen/templates/metadata.json.jinja2 +18 -9
  30. package/autorest/codegen/templates/model_base.py.jinja2 +87 -70
  31. package/autorest/codegen/templates/model_dpg.py.jinja2 +6 -4
  32. package/autorest/codegen/templates/serialization.py.jinja2 +20 -15
  33. package/autorest/codegen/templates/vendor.py.jinja2 +3 -2
  34. package/autorest/jsonrpc/localapi.py +3 -3
  35. package/autorest/jsonrpc/server.py +3 -3
  36. package/autorest/m2r/__init__.py +1 -1
  37. package/autorest/m4reformatter/__init__.py +12 -2
  38. package/autorest/multiapi/models/__init__.py +2 -0
  39. package/autorest/multiapi/models/code_model.py +13 -0
  40. package/autorest/multiapi/models/global_parameter.py +1 -0
  41. package/autorest/multiapi/models/imports.py +3 -3
  42. package/autorest/multiapi/serializers/__init__.py +30 -3
  43. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +8 -12
  44. package/autorest/postprocess/get_all.py +3 -1
  45. package/autorest/postprocess/venvtools.py +5 -4
  46. package/autorest/preprocess/__init__.py +16 -4
  47. package/autorest/preprocess/python_mappings.py +1 -0
  48. package/index.js +0 -0
  49. package/package.json +2 -1
  50. package/requirements.txt +6 -6
  51. package/setup.py +0 -1
  52. 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 isodate
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 copy
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: Date
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 = model_name.split(".")[-1]
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: str) -> bool:
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: typing.Any, default: typing.Any = _UNSET) -> typing.Any:
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: typing.Any, default: typing.Any = _UNSET) -> typing.Any:
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(rest_field: typing.Optional["_RestField"], value: typing.Any) -> typing.Any:
387
- return _deserialize(rest_field._type, value) if (rest_field and rest_field._is_model) else _serialize(value)
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, rest_field in attr_to_rest_field.items():
430
- rest_field._module = cls.__module__
431
- if not rest_field._type:
432
- rest_field._type = rest_field._get_deserialize_callable_from_annotation(annotations.get(attr, None))
433
- if not rest_field._rest_name_input:
434
- rest_field._rest_name_input = attr
435
- cls._attr_to_rest_field: typing.Dict[str, _RestField] = {k: v for k, v in attr_to_rest_field.items()}
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 annotation.__origin__ == typing.Literal:
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 isinstance(annotation, typing._GenericAlias): # pylint: disable=protected-access
487
- if annotation.__origin__ is typing.Union:
488
- def _deserialize_with_union(union_annotation: typing._GenericAlias, obj):
489
- for t in union_annotation.__args__:
490
- try:
491
- return _deserialize(t, obj, module)
492
- except DeserializationError:
493
- pass
494
- raise DeserializationError()
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 (AttributeError):
528
+ except AttributeError:
514
529
  pass
515
530
 
516
531
  # is it a forward ref / in quotes?
517
- if isinstance(annotation, str) or type(annotation) == typing.ForwardRef:
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) if deserializer else 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.Optional[typing.Callable[[typing.Any], typing.Any]], value: typing.Any, module: str = ""):
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
- def __init__(self, *args, **kwargs):
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 serializer.initialize_properties(model) %}
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 JSONify using json.dump.
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
- unflattened = {k: new_attr}
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
- internal_data_type = data_type.strip("[]{}")
686
- internal_data_type = self.dependencies.get(internal_data_type, None)
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
- dict_keys = _FLATTEN.split(key)
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 deseralize.
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 deseralize.
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
- formatted_components = template.split("/")
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 code_model.clients | selectattr("has_mixin") %}
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]] = dict()
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
 
@@ -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: # pylint: disable=no-self-use
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 = "base_url" if self.legacy else "endpoint"
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.version_tolerant or self.low_level_client:
1096
+ if self.only_path_and_body_parameters_positional:
1087
1097
  parameters.append(credential)
1088
1098
  else:
1089
1099
  parameters.insert(0, credential)