@autorest/python 6.2.12 → 6.2.15

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 +74 -63
  31. package/autorest/codegen/templates/model_dpg.py.jinja2 +6 -4
  32. package/autorest/codegen/templates/serialization.py.jinja2 +17 -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,23 @@
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
23
24
 
24
25
  _LOGGER = logging.getLogger(__name__)
25
26
 
@@ -41,11 +42,16 @@ A falsy sentinel object which is supposed to be used to specify attributes
41
42
  with no data. This gets serialized to `null` on the wire.
42
43
  """
43
44
 
45
+ TZ_UTC = timezone.utc
44
46
 
45
47
  def _timedelta_as_isostr(td: timedelta) -> str:
46
48
  """Converts a datetime.timedelta object into an ISO 8601 formatted string, e.g. 'P4DT12H30M05S'
47
49
 
48
50
  Function adapted from the Tin Can Python project: https://github.com/RusticiSoftware/TinCanPython
51
+
52
+ :param timedelta td: The timedelta to convert
53
+ :rtype: str
54
+ :return: ISO8601 version of this timedelta
49
55
  """
50
56
 
51
57
  # Split seconds to larger units
@@ -93,7 +99,12 @@ def _timedelta_as_isostr(td: timedelta) -> str:
93
99
 
94
100
 
95
101
  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"""
102
+ """Converts a datetime.(datetime|date|time|timedelta) object into an ISO 8601 formatted string
103
+
104
+ :param timedelta dt: The date object to convert
105
+ :rtype: str
106
+ :return: ISO8601 version of this datetime
107
+ """
97
108
  # First try datetime.datetime
98
109
  if hasattr(dt, "year") and hasattr(dt, "hour"):
99
110
  dt = typing.cast(datetime, dt)
@@ -113,15 +124,6 @@ def _datetime_as_isostr(dt: typing.Union[datetime, date, time, timedelta]) -> st
113
124
  dt = typing.cast(timedelta, dt)
114
125
  return _timedelta_as_isostr(dt)
115
126
 
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
127
  def _serialize_bytes(o) -> str:
126
128
  return base64.b64encode(o).decode()
127
129
 
@@ -141,7 +143,7 @@ def _serialize_datetime(o):
141
143
 
142
144
  def _is_readonly(p):
143
145
  try:
144
- return p._readonly
146
+ return p._readonly # pylint: disable=protected-access
145
147
  except AttributeError:
146
148
  return False
147
149
 
@@ -151,7 +153,7 @@ class AzureJSONEncoder(JSONEncoder):
151
153
 
152
154
  def default(self, o): # pylint: disable=too-many-return-statements
153
155
  if _is_model(o):
154
- readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)]
156
+ readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] # pylint: disable=protected-access
155
157
  return {k: v for k, v in o.items() if k not in readonly_props}
156
158
  if isinstance(o, (bytes, bytearray)):
157
159
  return base64.b64encode(o).decode()
@@ -174,7 +176,7 @@ class AzureJSONEncoder(JSONEncoder):
174
176
  return super(AzureJSONEncoder, self).default(o)
175
177
 
176
178
 
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}]?")
179
+ _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
180
 
179
181
 
180
182
  def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
@@ -182,6 +184,7 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
182
184
 
183
185
  :param str attr: response string to be deserialized.
184
186
  :rtype: ~datetime.datetime
187
+ :returns: The datetime object from that input
185
188
  """
186
189
  if isinstance(attr, datetime):
187
190
  # i'm already deserialized
@@ -212,7 +215,8 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
212
215
  def _deserialize_date(attr: typing.Union[str, date]) -> date:
213
216
  """Deserialize ISO-8601 formatted string into Date object.
214
217
  :param str attr: response string to be deserialized.
215
- :rtype: Date
218
+ :rtype: date
219
+ :returns: The date object from that input
216
220
  """
217
221
  # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception.
218
222
  if isinstance(attr, date):
@@ -225,6 +229,7 @@ def _deserialize_time(attr: typing.Union[str, time]) -> time:
225
229
 
226
230
  :param str attr: response string to be deserialized.
227
231
  :rtype: datetime.time
232
+ :returns: The time object from that input
228
233
  """
229
234
  if isinstance(attr, time):
230
235
  return attr
@@ -271,7 +276,7 @@ class _MyMutableMapping(MutableMapping):
271
276
  def __init__(self, data: typing.Dict[str, typing.Any]) -> None:
272
277
  self._data = copy.deepcopy(data)
273
278
 
274
- def __contains__(self, key: str) -> bool:
279
+ def __contains__(self, key: typing.Any) -> bool:
275
280
  return key in self._data
276
281
 
277
282
  def __getitem__(self, key: str) -> typing.Any:
@@ -307,15 +312,15 @@ class _MyMutableMapping(MutableMapping):
307
312
  except KeyError:
308
313
  return default
309
314
 
310
- @typing.overload
311
- def pop(self, key: str) -> typing.Any:
315
+ @typing.overload # type: ignore
316
+ def pop(self, key: str) -> typing.Any: # pylint: disable=no-member
312
317
  ...
313
318
 
314
319
  @typing.overload
315
320
  def pop(self, key: str, default: typing.Any) -> typing.Any:
316
321
  ...
317
322
 
318
- def pop(self, key: typing.Any, default: typing.Any = _UNSET) -> typing.Any:
323
+ def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
319
324
  if default is _UNSET:
320
325
  return self._data.pop(key)
321
326
  return self._data.pop(key, default)
@@ -329,7 +334,7 @@ class _MyMutableMapping(MutableMapping):
329
334
  def update(self, *args: typing.Any, **kwargs: typing.Any) -> None:
330
335
  self._data.update(*args, **kwargs)
331
336
 
332
- @typing.overload
337
+ @typing.overload # type: ignore
333
338
  def setdefault(self, key: str) -> typing.Any:
334
339
  ...
335
340
 
@@ -337,7 +342,7 @@ class _MyMutableMapping(MutableMapping):
337
342
  def setdefault(self, key: str, default: typing.Any) -> typing.Any:
338
343
  ...
339
344
 
340
- def setdefault(self, key: typing.Any, default: typing.Any = _UNSET) -> typing.Any:
345
+ def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
341
346
  if default is _UNSET:
342
347
  return self._data.setdefault(key)
343
348
  return self._data.setdefault(key, default)
@@ -383,8 +388,8 @@ def _get_rest_field(
383
388
  return None
384
389
 
385
390
 
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)
391
+ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any:
392
+ return _deserialize(rf._type, value) if (rf and rf._is_model) else _serialize(value)
388
393
 
389
394
 
390
395
  class Model(_MyMutableMapping):
@@ -414,7 +419,7 @@ class Model(_MyMutableMapping):
414
419
  def copy(self):
415
420
  return Model(self.__dict__)
416
421
 
417
- def __new__(cls, *args: typing.Any, **kwargs: typing.Any):
422
+ def __new__(cls, *args: typing.Any, **kwargs: typing.Any): # pylint: disable=unused-argument
418
423
  # we know the last three classes in mro are going to be 'Model', 'dict', and 'object'
419
424
  mros = cls.__mro__[:-3][::-1] # ignore model, dict, and object parents, and reverse the mro order
420
425
  attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
@@ -423,50 +428,50 @@ class Model(_MyMutableMapping):
423
428
  annotations = {
424
429
  k: v
425
430
  for mro_class in mros
426
- if hasattr(mro_class, "__annotations__")
427
- for k, v in mro_class.__annotations__.items()
431
+ if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
432
+ for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
428
433
  }
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()}
434
+ for attr, rf in attr_to_rest_field.items():
435
+ rf._module = cls.__module__
436
+ if not rf._type:
437
+ rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
438
+ if not rf._rest_name_input:
439
+ rf._rest_name_input = attr
440
+ cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
436
441
 
437
442
  return super().__new__(cls)
438
443
 
439
444
  def __init_subclass__(cls, discriminator=None):
440
445
  for base in cls.__bases__:
441
- if hasattr(base, "__mapping__"):
442
- base.__mapping__[discriminator or cls.__name__] = cls
446
+ if hasattr(base, "__mapping__"): # pylint: disable=no-member
447
+ base.__mapping__[discriminator or cls.__name__] = cls # pylint: disable=no-member
443
448
 
444
449
  @classmethod
445
450
  def _get_discriminator(cls) -> typing.Optional[str]:
446
451
  for v in cls.__dict__.values():
447
- if isinstance(v, _RestField) and v._is_discriminator:
448
- return v._rest_name
452
+ if isinstance(v, _RestField) and v._is_discriminator: # pylint: disable=protected-access
453
+ return v._rest_name # pylint: disable=protected-access
449
454
  return None
450
455
 
451
456
  @classmethod
452
457
  def _deserialize(cls, data):
453
- if not hasattr(cls, "__mapping__"):
458
+ if not hasattr(cls, "__mapping__"): # pylint: disable=no-member
454
459
  return cls(data)
455
460
  discriminator = cls._get_discriminator()
456
- mapped_cls = cls.__mapping__.get(data.get(discriminator), cls)
461
+ mapped_cls = cls.__mapping__.get(data.get(discriminator), cls) # pylint: disable=no-member
457
462
  if mapped_cls == cls:
458
463
  return cls(data)
459
- return mapped_cls._deserialize(data)
464
+ return mapped_cls._deserialize(data) # pylint: disable=protected-access
460
465
 
461
466
 
462
- def _get_deserialize_callable_from_annotation(
463
- annotation: typing.Any, module: str,
467
+ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements
468
+ annotation: typing.Any, module: typing.Optional[str],
464
469
  ) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]:
465
470
  if not annotation or annotation in [int, float]:
466
471
  return None
467
472
 
468
473
  try:
469
- if _is_model(_get_model(module, annotation)):
474
+ if module and _is_model(_get_model(module, annotation)):
470
475
  def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
471
476
  if _is_model(obj):
472
477
  return obj
@@ -478,21 +483,25 @@ def _get_deserialize_callable_from_annotation(
478
483
 
479
484
  # is it a literal?
480
485
  try:
481
- if annotation.__origin__ == typing.Literal:
486
+ if sys.version_info >= (3, 8):
487
+ from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports
488
+ else:
489
+ from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports
490
+
491
+ if annotation.__origin__ == Literal:
482
492
  return None
483
493
  except AttributeError:
484
494
  pass
485
495
 
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)
496
+ if getattr(annotation, "__origin__", None) is typing.Union:
497
+ def _deserialize_with_union(union_annotation, obj):
498
+ for t in union_annotation.__args__:
499
+ try:
500
+ return _deserialize(t, obj, module)
501
+ except DeserializationError:
502
+ pass
503
+ raise DeserializationError()
504
+ return functools.partial(_deserialize_with_union, annotation)
496
505
 
497
506
  # is it optional?
498
507
  try:
@@ -510,11 +519,11 @@ def _get_deserialize_callable_from_annotation(
510
519
  return _deserialize_with_callable(if_obj_deserializer, obj)
511
520
 
512
521
  return functools.partial(_deserialize_with_optional, if_obj_deserializer)
513
- except (AttributeError):
522
+ except AttributeError:
514
523
  pass
515
524
 
516
525
  # is it a forward ref / in quotes?
517
- if isinstance(annotation, str) or type(annotation) == typing.ForwardRef:
526
+ if isinstance(annotation, (str, typing.ForwardRef)):
518
527
  try:
519
528
  model_name = annotation.__forward_arg__ # type: ignore
520
529
  except AttributeError:
@@ -596,6 +605,8 @@ def _deserialize_with_callable(deserializer: typing.Optional[typing.Callable[[ty
596
605
  try:
597
606
  if value is None:
598
607
  return None
608
+ if deserializer is None:
609
+ return value
599
610
  if isinstance(deserializer, CaseInsensitiveEnumMeta):
600
611
  try:
601
612
  return deserializer(value)
@@ -603,13 +614,13 @@ def _deserialize_with_callable(deserializer: typing.Optional[typing.Callable[[ty
603
614
  # for unknown value, return raw value
604
615
  return value
605
616
  if isinstance(deserializer, type) and issubclass(deserializer, Model):
606
- return deserializer._deserialize(value)
607
- return deserializer(value) if deserializer else value
617
+ return deserializer._deserialize(value) # type: ignore
618
+ return deserializer(value)
608
619
  except Exception as e:
609
620
  raise DeserializationError() from e
610
621
 
611
622
 
612
- def _deserialize(deserializer: typing.Optional[typing.Callable[[typing.Any], typing.Any]], value: typing.Any, module: str = ""):
623
+ def _deserialize(deserializer: typing.Any, value: typing.Any, module: typing.Optional[str] = None) -> typing.Any:
613
624
  if isinstance(value, PipelineResponse):
614
625
  value = value.http_response.json()
615
626
  deserializer = _get_deserialize_callable_from_annotation(deserializer, module)
@@ -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:
@@ -358,7 +360,7 @@ class Model(object):
358
360
  ] = attribute_transformer,
359
361
  **kwargs: Any
360
362
  ) -> JSON:
361
- """Return a dict that can be JSONify using json.dump.
363
+ """Return a dict that can be serialized using json.dump.
362
364
 
363
365
  Advanced usage might optionally use a callback as parameter:
364
366
 
@@ -436,7 +438,7 @@ class Model(object):
436
438
  """
437
439
  deserializer = Deserializer(cls._infer_class_models())
438
440
  deserializer.key_extractors = ( # type: ignore
439
- [
441
+ [ # type: ignore
440
442
  attribute_key_case_insensitive_extractor,
441
443
  rest_key_case_insensitive_extractor,
442
444
  last_rest_key_case_insensitive_extractor,
@@ -544,7 +546,7 @@ class Serializer(object):
544
546
  "multiple": lambda x, y: x % y != 0,
545
547
  }
546
548
 
547
- def __init__(self, classes=None):
549
+ def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]]=None):
548
550
  self.serialize_type = {
549
551
  "iso-8601": Serializer.serialize_iso,
550
552
  "rfc-1123": Serializer.serialize_rfc,
@@ -560,7 +562,7 @@ class Serializer(object):
560
562
  "[]": self.serialize_iter,
561
563
  "{}": self.serialize_dict,
562
564
  }
563
- self.dependencies = dict(classes) if classes else {}
565
+ self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {}
564
566
  self.key_transformer = full_restapi_key_transformer
565
567
  self.client_side_validation = True
566
568
 
@@ -652,8 +654,7 @@ class Serializer(object):
652
654
  serialized.append(local_node) # type: ignore
653
655
  else: # JSON
654
656
  for k in reversed(keys): # type: ignore
655
- unflattened = {k: new_attr}
656
- new_attr = unflattened
657
+ new_attr = {k: new_attr}
657
658
 
658
659
  _new_attr = new_attr
659
660
  _serialized = serialized
@@ -682,8 +683,8 @@ class Serializer(object):
682
683
  """
683
684
 
684
685
  # 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)
686
+ internal_data_type_str = data_type.strip("[]{}")
687
+ internal_data_type = self.dependencies.get(internal_data_type_str, None)
687
688
  try:
688
689
  is_xml_model_serialization = kwargs["is_xml"]
689
690
  except KeyError:
@@ -1187,7 +1188,8 @@ def rest_key_extractor(attr, attr_desc, data):
1187
1188
  working_data = data
1188
1189
 
1189
1190
  while "." in key:
1190
- dict_keys = _FLATTEN.split(key)
1191
+ # Need the cast, as for some reasons "split" is typed as list[str | Any]
1192
+ dict_keys = cast(List[str], _FLATTEN.split(key))
1191
1193
  if len(dict_keys) == 1:
1192
1194
  key = _decode_attribute_map_key(dict_keys[0])
1193
1195
  break
@@ -1358,7 +1360,7 @@ class Deserializer(object):
1358
1360
 
1359
1361
  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
1362
 
1361
- def __init__(self, classes=None):
1363
+ def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]]=None):
1362
1364
  self.deserialize_type = {
1363
1365
  "iso-8601": Deserializer.deserialize_iso,
1364
1366
  "rfc-1123": Deserializer.deserialize_rfc,
@@ -1378,7 +1380,7 @@ class Deserializer(object):
1378
1380
  "duration": (isodate.Duration, datetime.timedelta),
1379
1381
  "iso-8601": (datetime.datetime),
1380
1382
  }
1381
- self.dependencies = dict(classes) if classes else {}
1383
+ self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {}
1382
1384
  self.key_extractors = [rest_key_extractor, xml_key_extractor]
1383
1385
  # Additional properties only works if the "rest_key_extractor" is used to
1384
1386
  # extract the keys. Making it to work whatever the key extractor is too much
@@ -1497,7 +1499,7 @@ class Deserializer(object):
1497
1499
  Once classification has been determined, initialize object.
1498
1500
 
1499
1501
  :param str target: The target object type to deserialize to.
1500
- :param str/dict data: The response data to deseralize.
1502
+ :param str/dict data: The response data to deserialize.
1501
1503
  """
1502
1504
  if target is None:
1503
1505
  return None, None
@@ -1512,7 +1514,7 @@ class Deserializer(object):
1512
1514
  target = target._classify(data, self.dependencies)
1513
1515
  except AttributeError:
1514
1516
  pass # Target is not a Model, no classify
1515
- return target, target.__class__.__name__
1517
+ return target, target.__class__.__name__ # type: ignore
1516
1518
 
1517
1519
  def failsafe_deserialize(self, target_obj, data, content_type=None):
1518
1520
  """Ignores any errors encountered in deserialization,
@@ -1522,7 +1524,7 @@ class Deserializer(object):
1522
1524
  a deserialization error.
1523
1525
 
1524
1526
  :param str target_obj: The target object type to deserialize to.
1525
- :param str/dict data: The response data to deseralize.
1527
+ :param str/dict data: The response data to deserialize.
1526
1528
  :param str content_type: Swagger "produces" if available.
1527
1529
  """
1528
1530
  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)
@@ -5,10 +5,12 @@
5
5
  # --------------------------------------------------------------------------
6
6
  from .code_model import CodeModel
7
7
  from .imports import ImportType, FileImport, TypingSection
8
+ from .global_parameter import GlobalParameter
8
9
 
9
10
  __all__ = [
10
11
  "CodeModel",
11
12
  "FileImport",
12
13
  "ImportType",
13
14
  "TypingSection",
15
+ "GlobalParameter",
14
16
  ]
@@ -71,6 +71,19 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
71
71
  operation_groups.sort(key=lambda x: x.name)
72
72
  return operation_groups
73
73
 
74
+ @property
75
+ def host_variable_name(self) -> str:
76
+ if self.client.parameterized_host_template_to_api_version:
77
+ return "base_url"
78
+ params = (
79
+ self.global_parameters.parameters
80
+ + self.global_parameters.service_client_specific_global_parameters
81
+ )
82
+ try:
83
+ return next(p for p in params if p.name in ["endpoint", "base_url"]).name
84
+ except StopIteration:
85
+ return "_endpoint"
86
+
74
87
  @property
75
88
  def last_rt_list(self) -> Dict[str, str]:
76
89
  """Build the a mapping RT => API version if RT doesn't exist in latest detected API version.
@@ -17,6 +17,7 @@ class GlobalParameter:
17
17
  self.global_parameter_metadata_sync = global_parameter_metadata_sync
18
18
  self.global_parameter_metadata_async = global_parameter_metadata_async
19
19
  self.required = global_parameter_metadata_sync["required"]
20
+ self.method_location = global_parameter_metadata_sync["method_location"]
20
21
 
21
22
  def _global_parameter_metadata(self, async_mode: bool) -> Dict[str, Any]:
22
23
  if async_mode:
@@ -85,7 +85,7 @@ class FileImport:
85
85
  ],
86
86
  ],
87
87
  ] = (
88
- imports or dict()
88
+ imports or {}
89
89
  )
90
90
 
91
91
  def _add_import(
@@ -123,8 +123,8 @@ class FileImport:
123
123
  ]
124
124
  ] = None
125
125
  name_input = convert_list_to_tuple(name_import)
126
- self._imports.setdefault(typing_section, dict()).setdefault(
127
- import_type, dict()
126
+ self._imports.setdefault(typing_section, {}).setdefault(
127
+ import_type, {}
128
128
  ).setdefault(from_section, set()).add(name_input)
129
129
 
130
130
  def add_submodule_import(