@autorest/python 6.28.0 → 6.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/autorest/codegen.py +2 -2
  2. package/autorest/jsonrpc/__init__.py +2 -2
  3. package/autorest/m4reformatter/__init__.py +13 -13
  4. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +1 -1
  5. package/generator/build/lib/pygen/codegen/models/code_model.py +5 -1
  6. package/generator/build/lib/pygen/codegen/models/combined_type.py +4 -3
  7. package/generator/build/lib/pygen/codegen/models/credential_types.py +4 -0
  8. package/generator/build/lib/pygen/codegen/models/operation.py +9 -3
  9. package/generator/build/lib/pygen/codegen/models/operation_group.py +26 -1
  10. package/generator/build/lib/pygen/codegen/models/paging_operation.py +1 -1
  11. package/generator/build/lib/pygen/codegen/models/property.py +2 -2
  12. package/generator/build/lib/pygen/codegen/serializers/__init__.py +22 -7
  13. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +14 -3
  14. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +2 -1
  15. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +1 -0
  16. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +61 -0
  17. package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +4 -4
  18. package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +2 -0
  19. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +39 -107
  20. package/generator/build/lib/pygen/preprocess/__init__.py +1 -1
  21. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  22. package/generator/pygen/codegen/models/code_model.py +5 -1
  23. package/generator/pygen/codegen/models/combined_type.py +4 -3
  24. package/generator/pygen/codegen/models/credential_types.py +4 -0
  25. package/generator/pygen/codegen/models/operation.py +9 -3
  26. package/generator/pygen/codegen/models/operation_group.py +26 -1
  27. package/generator/pygen/codegen/models/paging_operation.py +1 -1
  28. package/generator/pygen/codegen/models/property.py +2 -2
  29. package/generator/pygen/codegen/serializers/__init__.py +22 -7
  30. package/generator/pygen/codegen/serializers/builder_serializer.py +14 -3
  31. package/generator/pygen/codegen/serializers/model_serializer.py +2 -1
  32. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +1 -0
  33. package/generator/pygen/codegen/templates/model_base.py.jinja2 +61 -0
  34. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +4 -4
  35. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +2 -0
  36. package/generator/pygen/codegen/templates/serialization.py.jinja2 +39 -107
  37. package/generator/pygen/preprocess/__init__.py +1 -1
  38. package/package.json +2 -2
  39. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
  40. package/scripts/eng/mypy.ini +1 -1
  41. package/scripts/mypy.ini +1 -1
  42. package/scripts/prepare.py +2 -2
  43. package/scripts/start.py +2 -2
  44. package/scripts/venvtools.py +2 -2
@@ -47,9 +47,7 @@ from typing import (
47
47
  IO,
48
48
  Mapping,
49
49
  Callable,
50
- TypeVar,
51
50
  MutableMapping,
52
- Type,
53
51
  List,
54
52
  )
55
53
 
@@ -60,13 +58,13 @@ except ImportError:
60
58
  import xml.etree.ElementTree as ET
61
59
 
62
60
  import isodate # type: ignore
61
+ from typing_extensions import Self
63
62
 
64
63
  from {{ code_model.core_library }}.exceptions import DeserializationError, SerializationError
65
64
  from {{ code_model.core_library }}.serialization import NULL as CoreNull
66
65
 
67
66
  _BOM = codecs.BOM_UTF8.decode(encoding="utf-8")
68
67
 
69
- ModelType = TypeVar("ModelType", bound="Model")
70
68
  JSON = MutableMapping[str, Any]
71
69
 
72
70
 
@@ -184,73 +182,7 @@ try:
184
182
  except NameError:
185
183
  _long_type = int
186
184
 
187
-
188
- class UTC(datetime.tzinfo):
189
- """Time Zone info for handling UTC"""
190
-
191
- def utcoffset(self, dt):
192
- """UTF offset for UTC is 0.
193
-
194
- :param datetime.datetime dt: The datetime
195
- :returns: The offset
196
- :rtype: datetime.timedelta
197
- """
198
- return datetime.timedelta(0)
199
-
200
- def tzname(self, dt):
201
- """Timestamp representation.
202
-
203
- :param datetime.datetime dt: The datetime
204
- :returns: The timestamp representation
205
- :rtype: str
206
- """
207
- return "Z"
208
-
209
- def dst(self, dt):
210
- """No daylight saving for UTC.
211
-
212
- :param datetime.datetime dt: The datetime
213
- :returns: The daylight saving time
214
- :rtype: datetime.timedelta
215
- """
216
- return datetime.timedelta(hours=1)
217
-
218
-
219
- try:
220
- from datetime import timezone as _FixedOffset # type: ignore
221
- except ImportError: # Python 2.7
222
-
223
- class _FixedOffset(datetime.tzinfo): # type: ignore
224
- """Fixed offset in minutes east from UTC.
225
- Copy/pasted from Python doc
226
- :param datetime.timedelta offset: offset in timedelta format
227
- """
228
-
229
- def __init__(self, offset) -> None:
230
- self.__offset = offset
231
-
232
- def utcoffset(self, dt):
233
- return self.__offset
234
-
235
- def tzname(self, dt):
236
- return str(self.__offset.total_seconds() / 3600)
237
-
238
- def __repr__(self):
239
- return "<FixedOffset {}>".format(self.tzname(None))
240
-
241
- def dst(self, dt):
242
- return datetime.timedelta(0)
243
-
244
- def __getinitargs__(self):
245
- return (self.__offset,)
246
-
247
-
248
- try:
249
- from datetime import timezone
250
-
251
- TZ_UTC = timezone.utc
252
- except ImportError:
253
- TZ_UTC = UTC() # type: ignore
185
+ TZ_UTC = datetime.timezone.utc
254
186
 
255
187
  _FLATTEN = re.compile(r"(?<!\\)\.")
256
188
 
@@ -449,25 +381,25 @@ class Model:
449
381
  return client_models
450
382
 
451
383
  @classmethod
452
- def deserialize(cls: Type[ModelType], data: Any, content_type: Optional[str] = None) -> ModelType:
384
+ def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self:
453
385
  """Parse a str using the RestAPI syntax and return a model.
454
386
 
455
387
  :param str data: A str using RestAPI structure. JSON by default.
456
388
  :param str content_type: JSON by default, set application/xml if XML.
457
389
  :returns: An instance of this model
458
- :raises: DeserializationError if something went wrong
459
- :rtype: ModelType
390
+ :raises DeserializationError: if something went wrong
391
+ :rtype: Self
460
392
  """
461
393
  deserializer = Deserializer(cls._infer_class_models())
462
394
  return deserializer(cls.__name__, data, content_type=content_type) # type: ignore
463
395
 
464
396
  @classmethod
465
397
  def from_dict(
466
- cls: Type[ModelType],
398
+ cls,
467
399
  data: Any,
468
400
  key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None,
469
401
  content_type: Optional[str] = None,
470
- ) -> ModelType:
402
+ ) -> Self:
471
403
  """Parse a dict using given key extractor return a model.
472
404
 
473
405
  By default consider key
@@ -479,7 +411,7 @@ class Model:
479
411
  :param str content_type: JSON by default, set application/xml if XML.
480
412
  :returns: An instance of this model
481
413
  :raises: DeserializationError if something went wrong
482
- :rtype: ModelType
414
+ :rtype: Self
483
415
  """
484
416
  deserializer = Deserializer(cls._infer_class_models())
485
417
  deserializer.key_extractors = ( # type: ignore
@@ -625,7 +557,7 @@ class Serializer: # pylint: disable=too-many-public-methods
625
557
  :param object target_obj: The data to be serialized.
626
558
  :param str data_type: The type to be serialized from.
627
559
  :rtype: str, dict
628
- :raises: SerializationError if serialization fails.
560
+ :raises SerializationError: if serialization fails.
629
561
  :returns: The serialized data.
630
562
  """
631
563
  key_transformer = kwargs.get("key_transformer", self.key_transformer)
@@ -735,8 +667,8 @@ class Serializer: # pylint: disable=too-many-public-methods
735
667
  :param object data: The data to be serialized.
736
668
  :param str data_type: The type to be serialized from.
737
669
  :rtype: dict
738
- :raises: SerializationError if serialization fails.
739
- :raises: ValueError if data is None
670
+ :raises SerializationError: if serialization fails.
671
+ :raises ValueError: if data is None
740
672
  :returns: The serialized request body
741
673
  """
742
674
 
@@ -780,8 +712,8 @@ class Serializer: # pylint: disable=too-many-public-methods
780
712
  :param str data_type: The type to be serialized from.
781
713
  :rtype: str
782
714
  :returns: The serialized URL path
783
- :raises: TypeError if serialization fails.
784
- :raises: ValueError if data is None
715
+ :raises TypeError: if serialization fails.
716
+ :raises ValueError: if data is None
785
717
  """
786
718
  try:
787
719
  output = self.serialize_data(data, data_type, **kwargs)
@@ -804,8 +736,8 @@ class Serializer: # pylint: disable=too-many-public-methods
804
736
  :param object data: The data to be serialized.
805
737
  :param str data_type: The type to be serialized from.
806
738
  :rtype: str, list
807
- :raises: TypeError if serialization fails.
808
- :raises: ValueError if data is None
739
+ :raises TypeError: if serialization fails.
740
+ :raises ValueError: if data is None
809
741
  :returns: The serialized query parameter
810
742
  """
811
743
  try:
@@ -834,8 +766,8 @@ class Serializer: # pylint: disable=too-many-public-methods
834
766
  :param object data: The data to be serialized.
835
767
  :param str data_type: The type to be serialized from.
836
768
  :rtype: str
837
- :raises: TypeError if serialization fails.
838
- :raises: ValueError if data is None
769
+ :raises TypeError: if serialization fails.
770
+ :raises ValueError: if data is None
839
771
  :returns: The serialized header
840
772
  """
841
773
  try:
@@ -854,9 +786,9 @@ class Serializer: # pylint: disable=too-many-public-methods
854
786
 
855
787
  :param object data: The data to be serialized.
856
788
  :param str data_type: The type to be serialized from.
857
- :raises: AttributeError if required data is None.
858
- :raises: ValueError if data is None
859
- :raises: SerializationError if serialization fails.
789
+ :raises AttributeError: if required data is None.
790
+ :raises ValueError: if data is None
791
+ :raises SerializationError: if serialization fails.
860
792
  :returns: The serialized data.
861
793
  :rtype: str, int, float, bool, dict, list
862
794
  """
@@ -1191,7 +1123,7 @@ class Serializer: # pylint: disable=too-many-public-methods
1191
1123
 
1192
1124
  :param Datetime attr: Object to be serialized.
1193
1125
  :rtype: str
1194
- :raises: TypeError if format invalid.
1126
+ :raises TypeError: if format invalid.
1195
1127
  :return: serialized rfc
1196
1128
  """
1197
1129
  try:
@@ -1217,7 +1149,7 @@ class Serializer: # pylint: disable=too-many-public-methods
1217
1149
 
1218
1150
  :param Datetime attr: Object to be serialized.
1219
1151
  :rtype: str
1220
- :raises: SerializationError if format invalid.
1152
+ :raises SerializationError: if format invalid.
1221
1153
  :return: serialized iso
1222
1154
  """
1223
1155
  if isinstance(attr, str):
@@ -1250,7 +1182,7 @@ class Serializer: # pylint: disable=too-many-public-methods
1250
1182
 
1251
1183
  :param Datetime attr: Object to be serialized.
1252
1184
  :rtype: int
1253
- :raises: SerializationError if format invalid
1185
+ :raises SerializationError: if format invalid
1254
1186
  :return: serialied unix
1255
1187
  """
1256
1188
  if isinstance(attr, int):
@@ -1487,7 +1419,7 @@ class Deserializer:
1487
1419
  :param str target_obj: Target data type to deserialize to.
1488
1420
  :param requests.Response response_data: REST response object.
1489
1421
  :param str content_type: Swagger "produces" if available.
1490
- :raises: DeserializationError if deserialization fails.
1422
+ :raises DeserializationError: if deserialization fails.
1491
1423
  :return: Deserialized object.
1492
1424
  :rtype: object
1493
1425
  """
@@ -1501,7 +1433,7 @@ class Deserializer:
1501
1433
 
1502
1434
  :param str target_obj: Target data type to deserialize to.
1503
1435
  :param object data: Object to deserialize.
1504
- :raises: DeserializationError if deserialization fails.
1436
+ :raises DeserializationError: if deserialization fails.
1505
1437
  :return: Deserialized object.
1506
1438
  :rtype: object
1507
1439
  """
@@ -1716,7 +1648,7 @@ class Deserializer:
1716
1648
 
1717
1649
  :param str data: The response string to be deserialized.
1718
1650
  :param str data_type: The type to deserialize to.
1719
- :raises: DeserializationError if deserialization fails.
1651
+ :raises DeserializationError: if deserialization fails.
1720
1652
  :return: Deserialized object.
1721
1653
  :rtype: object
1722
1654
  """
@@ -1798,7 +1730,7 @@ class Deserializer:
1798
1730
  :param dict attr: Dictionary to be deserialized.
1799
1731
  :return: Deserialized object.
1800
1732
  :rtype: dict
1801
- :raises: TypeError if non-builtin datatype encountered.
1733
+ :raises TypeError: if non-builtin datatype encountered.
1802
1734
  """
1803
1735
  if attr is None:
1804
1736
  return None
@@ -1844,7 +1776,7 @@ class Deserializer:
1844
1776
  :param str data_type: deserialization data type.
1845
1777
  :return: Deserialized basic type.
1846
1778
  :rtype: str, int, float or bool
1847
- :raises: TypeError if string format is not valid.
1779
+ :raises TypeError: if string format is not valid.
1848
1780
  """
1849
1781
  # If we're here, data is supposed to be a basic type.
1850
1782
  # If it's still an XML node, take the text
@@ -1935,7 +1867,7 @@ class Deserializer:
1935
1867
  :param str attr: response string to be deserialized.
1936
1868
  :return: Deserialized bytearray
1937
1869
  :rtype: bytearray
1938
- :raises: TypeError if string format invalid.
1870
+ :raises TypeError: if string format invalid.
1939
1871
  """
1940
1872
  if isinstance(attr, ET.Element):
1941
1873
  attr = attr.text
@@ -1948,7 +1880,7 @@ class Deserializer:
1948
1880
  :param str attr: response string to be deserialized.
1949
1881
  :return: Deserialized base64 string
1950
1882
  :rtype: bytearray
1951
- :raises: TypeError if string format invalid.
1883
+ :raises TypeError: if string format invalid.
1952
1884
  """
1953
1885
  if isinstance(attr, ET.Element):
1954
1886
  attr = attr.text
@@ -1963,7 +1895,7 @@ class Deserializer:
1963
1895
 
1964
1896
  :param str attr: response string to be deserialized.
1965
1897
  :return: Deserialized decimal
1966
- :raises: DeserializationError if string format invalid.
1898
+ :raises DeserializationError: if string format invalid.
1967
1899
  :rtype: decimal
1968
1900
  """
1969
1901
  if isinstance(attr, ET.Element):
@@ -1981,7 +1913,7 @@ class Deserializer:
1981
1913
  :param str attr: response string to be deserialized.
1982
1914
  :return: Deserialized int
1983
1915
  :rtype: long or int
1984
- :raises: ValueError if string format invalid.
1916
+ :raises ValueError: if string format invalid.
1985
1917
  """
1986
1918
  if isinstance(attr, ET.Element):
1987
1919
  attr = attr.text
@@ -1994,7 +1926,7 @@ class Deserializer:
1994
1926
  :param str attr: response string to be deserialized.
1995
1927
  :return: Deserialized duration
1996
1928
  :rtype: TimeDelta
1997
- :raises: DeserializationError if string format invalid.
1929
+ :raises DeserializationError: if string format invalid.
1998
1930
  """
1999
1931
  if isinstance(attr, ET.Element):
2000
1932
  attr = attr.text
@@ -2012,7 +1944,7 @@ class Deserializer:
2012
1944
  :param str attr: response string to be deserialized.
2013
1945
  :return: Deserialized date
2014
1946
  :rtype: Date
2015
- :raises: DeserializationError if string format invalid.
1947
+ :raises DeserializationError: if string format invalid.
2016
1948
  """
2017
1949
  if isinstance(attr, ET.Element):
2018
1950
  attr = attr.text
@@ -2028,7 +1960,7 @@ class Deserializer:
2028
1960
  :param str attr: response string to be deserialized.
2029
1961
  :return: Deserialized time
2030
1962
  :rtype: datetime.time
2031
- :raises: DeserializationError if string format invalid.
1963
+ :raises DeserializationError: if string format invalid.
2032
1964
  """
2033
1965
  if isinstance(attr, ET.Element):
2034
1966
  attr = attr.text
@@ -2043,14 +1975,14 @@ class Deserializer:
2043
1975
  :param str attr: response string to be deserialized.
2044
1976
  :return: Deserialized RFC datetime
2045
1977
  :rtype: Datetime
2046
- :raises: DeserializationError if string format invalid.
1978
+ :raises DeserializationError: if string format invalid.
2047
1979
  """
2048
1980
  if isinstance(attr, ET.Element):
2049
1981
  attr = attr.text
2050
1982
  try:
2051
1983
  parsed_date = email.utils.parsedate_tz(attr) # type: ignore
2052
1984
  date_obj = datetime.datetime(
2053
- *parsed_date[:6], tzinfo=_FixedOffset(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60))
1985
+ *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60))
2054
1986
  )
2055
1987
  if not date_obj.tzinfo:
2056
1988
  date_obj = date_obj.astimezone(tz=TZ_UTC)
@@ -2066,7 +1998,7 @@ class Deserializer:
2066
1998
  :param str attr: response string to be deserialized.
2067
1999
  :return: Deserialized ISO datetime
2068
2000
  :rtype: Datetime
2069
- :raises: DeserializationError if string format invalid.
2001
+ :raises DeserializationError: if string format invalid.
2070
2002
  """
2071
2003
  if isinstance(attr, ET.Element):
2072
2004
  attr = attr.text
@@ -2104,7 +2036,7 @@ class Deserializer:
2104
2036
  :param int attr: Object to be serialized.
2105
2037
  :return: Deserialized datetime
2106
2038
  :rtype: Datetime
2107
- :raises: DeserializationError if format invalid
2039
+ :raises DeserializationError: if format invalid
2108
2040
  """
2109
2041
  if isinstance(attr, ET.Element):
2110
2042
  attr = int(attr.text) # type: ignore
@@ -92,9 +92,9 @@ def add_overloads_for_body_param(yaml_data: Dict[str, Any]) -> None:
92
92
  for body_type in body_parameter["type"]["types"]:
93
93
  if any(o for o in yaml_data["overloads"] if id(o["bodyParameter"]["type"]) == id(body_type)):
94
94
  continue
95
- yaml_data["overloads"].append(add_overload(yaml_data, body_type))
96
95
  if body_type.get("type") == "model" and body_type.get("base") == "json":
97
96
  yaml_data["overloads"].append(add_overload(yaml_data, body_type, for_flatten_params=True))
97
+ yaml_data["overloads"].append(add_overload(yaml_data, body_type))
98
98
  content_type_param = next(p for p in yaml_data["parameters"] if p["wireName"].lower() == "content-type")
99
99
  content_type_param["inOverload"] = False
100
100
  content_type_param["inOverridden"] = True
@@ -313,7 +313,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
313
313
  :param int schema_id: The yaml id of the schema
314
314
  :return: If created, we return the created schema, otherwise, we throw.
315
315
  :rtype: ~autorest.models.BaseType
316
- :raises: KeyError if schema is not found
316
+ :raises KeyError: if schema is not found
317
317
  """
318
318
  try:
319
319
  return next(type for id, type in self.types_map.items() if id == schema_id)
@@ -402,3 +402,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
402
402
  @property
403
403
  def is_legacy(self) -> bool:
404
404
  return _is_legacy(self.options)
405
+
406
+ @staticmethod
407
+ def has_non_json_models(models: List[ModelType]) -> bool:
408
+ return any(m for m in models if m.base != "json")
@@ -53,9 +53,10 @@ class CombinedType(BaseType):
53
53
  return self.yaml_data.get("clientDefaultValue")
54
54
 
55
55
  def description(self, *, is_operation_file: bool) -> str:
56
- if len(self.types) == 2:
57
- return f"Is either a {self.types[0].type_description} type or a {self.types[1].type_description} type."
58
- return f"Is one of the following types: {', '.join([t.type_description for t in self.types])}"
56
+ type_descriptions = list({t.type_description: None for t in self.types}.keys())
57
+ if len(type_descriptions) == 2:
58
+ return f"Is either a {type_descriptions[0]} type or a {type_descriptions[1]} type."
59
+ return f"Is one of the following types: {', '.join(t for t in type_descriptions)}"
59
60
 
60
61
  def docstring_text(self, **kwargs: Any) -> str:
61
62
  return " or ".join(t.docstring_text(**kwargs) for t in self.types)
@@ -198,6 +198,10 @@ class KeyCredentialType(CredentialType[KeyCredentialPolicyType]):
198
198
  def type_annotation(self, **kwargs: Any) -> str:
199
199
  return self.policy.credential_name
200
200
 
201
+ @property
202
+ def type_description(self) -> str:
203
+ return "key credential"
204
+
201
205
  @property
202
206
  def instance_check_template(self) -> str:
203
207
  return "isinstance({}, " + f"{self.policy.credential_name})"
@@ -35,6 +35,7 @@ from .parameter import (
35
35
  )
36
36
  from .parameter_list import ParameterList
37
37
  from .model_type import ModelType
38
+ from .primitive_types import BinaryIteratorType, BinaryType
38
39
  from .base import BaseType
39
40
  from .combined_type import CombinedType
40
41
  from .request_builder import OverloadedRequestBuilder, RequestBuilder
@@ -313,6 +314,10 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
313
314
  )
314
315
  return file_import
315
316
 
317
+ @property
318
+ def need_deserialize(self) -> bool:
319
+ return any(r.type and not isinstance(r.type, BinaryIteratorType) for r in self.responses)
320
+
316
321
  def imports( # pylint: disable=too-many-branches, disable=too-many-statements
317
322
  self, async_mode: bool, **kwargs: Any
318
323
  ) -> FileImport:
@@ -432,7 +437,8 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
432
437
  file_import.add_submodule_import("typing", "overload", ImportType.STDLIB)
433
438
  if self.code_model.options["models_mode"] == "dpg":
434
439
  relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base")
435
- if self.parameters.has_body:
440
+ body_param = self.parameters.body_parameter if self.parameters.has_body else None
441
+ if body_param and not isinstance(body_param.type, BinaryType):
436
442
  if self.has_form_data_body:
437
443
  file_import.add_submodule_import(
438
444
  self.code_model.get_relative_import_path(serialize_namespace), "_model_base", ImportType.LOCAL
@@ -450,9 +456,9 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
450
456
  ImportType.LOCAL,
451
457
  )
452
458
  file_import.add_import("json", ImportType.STDLIB)
453
- if any(xml_serializable(str(r.default_content_type)) for r in self.responses):
459
+ if any(xml_serializable(str(r.default_content_type)) for r in self.responses + self.exceptions):
454
460
  file_import.add_submodule_import(relative_path, "_deserialize_xml", ImportType.LOCAL)
455
- elif any(r.type for r in self.responses):
461
+ elif self.need_deserialize:
456
462
  file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
457
463
  if self.default_error_deserialization or self.non_default_errors:
458
464
  file_import.add_submodule_import(relative_path, "_failsafe_deserialize", ImportType.LOCAL)
@@ -9,7 +9,7 @@ from .utils import OrderedSet
9
9
 
10
10
  from .base import BaseModel
11
11
  from .operation import get_operation
12
- from .imports import FileImport, ImportType, TypingSection
12
+ from .imports import FileImport, ImportType, TypingSection, MsrestImportType
13
13
  from .utils import add_to_pylint_disable, NamespaceType
14
14
  from .lro_operation import LROOperation
15
15
  from .lro_paging_operation import LROPagingOperation
@@ -152,6 +152,31 @@ class OperationGroup(BaseModel):
152
152
  f"{self.client.name}MixinABC",
153
153
  ImportType.LOCAL,
154
154
  )
155
+ else:
156
+ file_import.add_submodule_import(
157
+ "" if self.code_model.is_azure_flavor else "runtime",
158
+ f"{'Async' if async_mode else ''}PipelineClient",
159
+ ImportType.SDKCORE,
160
+ )
161
+ file_import.add_submodule_import(
162
+ self.code_model.get_relative_import_path(
163
+ serialize_namespace,
164
+ self.code_model.get_imported_namespace_for_client(self.client.client_namespace, async_mode),
165
+ module_name="_configuration",
166
+ ),
167
+ f"{self.client.name}Configuration",
168
+ ImportType.LOCAL,
169
+ )
170
+ file_import.add_msrest_import(
171
+ serialize_namespace=kwargs.get("serialize_namespace", self.code_model.namespace),
172
+ msrest_import_type=MsrestImportType.Serializer,
173
+ typing_section=TypingSection.REGULAR,
174
+ )
175
+ file_import.add_msrest_import(
176
+ serialize_namespace=kwargs.get("serialize_namespace", self.code_model.namespace),
177
+ msrest_import_type=MsrestImportType.SerializerDeserializer,
178
+ typing_section=TypingSection.REGULAR,
179
+ )
155
180
  if self.has_abstract_operations:
156
181
  file_import.add_submodule_import(
157
182
  # raise_if_not_implemented is always defined in _vendor of top namespace
@@ -150,7 +150,7 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
150
150
  if self.code_model.options["models_mode"] == "dpg":
151
151
  relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base")
152
152
  file_import.merge(self.item_type.imports(**kwargs))
153
- if self.default_error_deserialization or any(r.type for r in self.responses):
153
+ if self.default_error_deserialization or self.need_deserialize:
154
154
  file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
155
155
  return file_import
156
156
 
@@ -102,7 +102,7 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
102
102
  if self.is_base_discriminator:
103
103
  return "str"
104
104
  types_type_annotation = self.type.type_annotation(is_operation_file=is_operation_file, **kwargs)
105
- if self.optional and self.client_default_value is None:
105
+ if (self.optional and self.client_default_value is None) or self.readonly:
106
106
  return f"Optional[{types_type_annotation}]"
107
107
  return types_type_annotation
108
108
 
@@ -144,7 +144,7 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
144
144
  if self.is_discriminator and isinstance(self.type, EnumType):
145
145
  return file_import
146
146
  file_import.merge(self.type.imports(**kwargs))
147
- if self.optional and self.client_default_value is None:
147
+ if (self.optional and self.client_default_value is None) or self.readonly:
148
148
  file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
149
149
  if self.code_model.options["models_mode"] == "dpg":
150
150
  serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
@@ -130,10 +130,10 @@ class JinjaSerializer(ReaderAndWriter):
130
130
  if self.code_model.options["package_mode"]:
131
131
  self._serialize_and_write_package_files(client_namespace)
132
132
 
133
- # write apiview_mapping_python.json
133
+ # write apiview-properties.json
134
134
  if self.code_model.options.get("emit_cross_language_definition_file"):
135
135
  self.write_file(
136
- exec_path / Path("apiview_mapping_python.json"),
136
+ exec_path / Path("apiview-properties.json"),
137
137
  general_serializer.serialize_cross_language_definition_file(),
138
138
  )
139
139
 
@@ -159,7 +159,9 @@ class JinjaSerializer(ReaderAndWriter):
159
159
  self._serialize_and_write_top_level_folder(env=env, namespace=client_namespace)
160
160
 
161
161
  # add models folder if there are models in this namespace
162
- if (client_namespace_type.models or client_namespace_type.enums) and self.code_model.options["models_mode"]:
162
+ if (
163
+ self.code_model.has_non_json_models(client_namespace_type.models) or client_namespace_type.enums
164
+ ) and self.code_model.options["models_mode"]:
163
165
  self._serialize_and_write_models_folder(
164
166
  env=env,
165
167
  namespace=client_namespace,
@@ -181,6 +183,14 @@ class JinjaSerializer(ReaderAndWriter):
181
183
  if self.code_model.options["multiapi"]:
182
184
  self._serialize_and_write_metadata(env=env, namespace=client_namespace)
183
185
 
186
+ # if there are only operations under this namespace, we need to add general __init__.py into `aio` folder
187
+ # to make sure all generated files could be packed into .zip/.whl/.tgz package
188
+ if not client_namespace_type.clients and client_namespace_type.operation_groups and self.has_aio_folder:
189
+ self.write_file(
190
+ exec_path / Path("aio/__init__.py"),
191
+ general_serializer.serialize_pkgutil_init_file(),
192
+ )
193
+
184
194
  def _serialize_and_write_package_files(self, client_namespace: str) -> None:
185
195
  root_of_sdk = self.exec_path(client_namespace)
186
196
  if self.code_model.options["package_mode"] in VALID_PACKAGE_MODE:
@@ -228,9 +238,9 @@ class JinjaSerializer(ReaderAndWriter):
228
238
  self, env: Environment, namespace: str, models: List[ModelType], enums: List[EnumType]
229
239
  ) -> None:
230
240
  # Write the models folder
231
- models_path = self.exec_path(namespace + ".models")
241
+ models_path = self.exec_path(namespace) / "models"
232
242
  serializer = DpgModelSerializer if self.code_model.options["models_mode"] == "dpg" else MsrestModelSerializer
233
- if models:
243
+ if self.code_model.has_non_json_models(models):
234
244
  self.write_file(
235
245
  models_path / Path(f"{self.code_model.models_filename}.py"),
236
246
  serializer(code_model=self.code_model, env=env, client_namespace=namespace, models=models).serialize(),
@@ -469,7 +479,12 @@ class JinjaSerializer(ReaderAndWriter):
469
479
  else Path(".")
470
480
  )
471
481
 
482
+ def exec_path_for_test_sample(self, namespace: str) -> Path:
483
+ return self.exec_path_compensation / Path(*namespace.split("."))
484
+
472
485
  def exec_path(self, namespace: str) -> Path:
486
+ if self.code_model.options["no_namespace_folders"] and not self.code_model.options["multiapi"]:
487
+ return Path(".")
473
488
  return self.exec_path_compensation / Path(*namespace.split("."))
474
489
 
475
490
  @property
@@ -482,7 +497,7 @@ class JinjaSerializer(ReaderAndWriter):
482
497
  return Path("")
483
498
 
484
499
  def _serialize_and_write_sample(self, env: Environment, namespace: str):
485
- out_path = self.exec_path(namespace) / Path("generated_samples")
500
+ out_path = self.exec_path_for_test_sample(namespace) / Path("generated_samples")
486
501
  for client in self.code_model.clients:
487
502
  for op_group in client.operation_groups:
488
503
  for operation in op_group.operations:
@@ -516,7 +531,7 @@ class JinjaSerializer(ReaderAndWriter):
516
531
 
517
532
  def _serialize_and_write_test(self, env: Environment, namespace: str):
518
533
  self.code_model.for_test = True
519
- out_path = self.exec_path(namespace) / Path("generated_tests")
534
+ out_path = self.exec_path_for_test_sample(namespace) / Path("generated_tests")
520
535
  general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
521
536
  self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
522
537
  if not self.code_model.options["azure_arm"]:
@@ -498,7 +498,11 @@ class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]):
498
498
  url_value = _escape_str(builder.url)
499
499
  else:
500
500
  url_value = f'kwargs.pop("template_url", {_escape_str(builder.url)})'
501
- return f"_url = {url_value}{' # pylint: disable=line-too-long' if len(url_value) > 114 else ''}"
501
+ result = "_url = " + url_value
502
+ # there will be always 4 spaces before the url
503
+ if len(result) + 4 > 120:
504
+ return result + " # pylint: disable=line-too-long"
505
+ return result
502
506
 
503
507
 
504
508
  ############################## NORMAL OPERATIONS ##############################
@@ -1001,7 +1005,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
1001
1005
  retval.extend(deserialize_code)
1002
1006
  return retval
1003
1007
 
1004
- def handle_error_response(self, builder: OperationType) -> List[str]:
1008
+ def handle_error_response(self, builder: OperationType) -> List[str]: # pylint: disable=too-many-statements, too-many-branches
1005
1009
  async_await = "await " if self.async_mode else ""
1006
1010
  retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
1007
1011
  response_read = [
@@ -1075,7 +1079,14 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
1075
1079
  is_operation_file=True, skip_quote=True, serialize_namespace=self.serialize_namespace
1076
1080
  )
1077
1081
  if self.code_model.options["models_mode"] == "dpg":
1078
- retval.append(f" error = _failsafe_deserialize({type_annotation}, response.json())")
1082
+ if xml_serializable(str(e.default_content_type)):
1083
+ retval.append(
1084
+ f" error = _failsafe_deserialize_xml({type_annotation}, response.text())"
1085
+ )
1086
+ else:
1087
+ retval.append(
1088
+ f" error = _failsafe_deserialize({type_annotation}, response.json())"
1089
+ )
1079
1090
  else:
1080
1091
  retval.append(
1081
1092
  f" error = self._deserialize.failsafe_deserialize({type_annotation}, "