@autorest/python 6.10.2 → 6.11.0

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.
@@ -83,8 +83,9 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
83
83
  self,
84
84
  ) -> List[Union[RequestBuilder, OverloadedRequestBuilder]]:
85
85
  request_builders: List[Union[RequestBuilder, OverloadedRequestBuilder]] = []
86
- for og_group in self.yaml_data["operationGroups"]:
87
- for operation_yaml in og_group["operations"]:
86
+
87
+ def add_og_request_builder(og: Dict[str, Any]):
88
+ for operation_yaml in og["operations"]:
88
89
  request_builder = get_request_builder(
89
90
  operation_yaml,
90
91
  code_model=self.code_model,
@@ -111,6 +112,14 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
111
112
  client=self,
112
113
  )
113
114
  )
115
+
116
+ queue = self.yaml_data["operationGroups"].copy()
117
+ while queue:
118
+ now = queue.pop(0)
119
+ add_og_request_builder(now)
120
+ if now.get("operationGroups"):
121
+ queue.extend(now["operationGroups"])
122
+
114
123
  return request_builders
115
124
 
116
125
  def pipeline_class(self, async_mode: bool) -> str:
@@ -247,7 +256,7 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
247
256
  @property
248
257
  def has_mixin(self) -> bool:
249
258
  """Do we want a mixin ABC class for typing purposes?"""
250
- return any(o for o in self.operation_groups if o.is_mixin)
259
+ return any(og for og in self.operation_groups if og.is_mixin)
251
260
 
252
261
  @property
253
262
  def lro_operations(self) -> List["OperationType"]:
@@ -255,8 +264,7 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
255
264
  return [
256
265
  operation
257
266
  for operation_group in self.operation_groups
258
- for operation in operation_group.operations
259
- if operation.operation_type in ("lro", "lropaging")
267
+ for operation in operation_group.lro_operations
260
268
  ]
261
269
 
262
270
  @property
@@ -267,8 +275,7 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
267
275
  @property
268
276
  def has_operations(self) -> bool:
269
277
  return any(
270
- bool(operation_group.operations)
271
- for operation_group in self.operation_groups
278
+ operation_group.has_operations for operation_group in self.operation_groups
272
279
  )
273
280
 
274
281
  def link_lro_initial_operations(self) -> None:
@@ -65,8 +65,7 @@ class CombinedType(BaseType):
65
65
 
66
66
  def type_annotation(self, **kwargs: Any) -> str:
67
67
  if self.name:
68
- ret = f"_types.{self.name}"
69
- return ret if kwargs.get("is_operation_file") else f'"{ret}"'
68
+ return f'"_types.{self.name}"'
70
69
  return self.type_definition(**kwargs)
71
70
 
72
71
  def type_definition(self, **kwargs: Any) -> str:
@@ -11,6 +11,8 @@ from .base import BaseModel
11
11
  from .operation import get_operation
12
12
  from .imports import FileImport, ImportType, TypingSection
13
13
  from .utils import add_to_pylint_disable, NAME_LENGTH_LIMIT
14
+ from .lro_operation import LROOperation
15
+ from .lro_paging_operation import LROPagingOperation
14
16
 
15
17
  if TYPE_CHECKING:
16
18
  from .code_model import CodeModel
@@ -32,9 +34,17 @@ class OperationGroup(BaseModel):
32
34
  super().__init__(yaml_data, code_model)
33
35
  self.client = client
34
36
  self.class_name: str = yaml_data["className"]
37
+ self.identify_name: str = yaml_data["identifyName"]
35
38
  self.property_name: str = yaml_data["propertyName"]
36
39
  self.operations = operations
37
40
  self.api_versions = api_versions
41
+ self.operation_groups: List[OperationGroup] = []
42
+ if self.code_model.options["show_operations"]:
43
+ self.operation_groups = [
44
+ OperationGroup.from_yaml(op_group, code_model, client)
45
+ for op_group in self.yaml_data.get("operationGroups", [])
46
+ ]
47
+ self.link_lro_initial_operations()
38
48
 
39
49
  @property
40
50
  def has_abstract_operations(self) -> bool:
@@ -43,7 +53,7 @@ class OperationGroup(BaseModel):
43
53
  @property
44
54
  def base_class(self) -> str:
45
55
  base_classes: List[str] = []
46
- if self.is_mixin and self.code_model.need_mixin_abc:
56
+ if self.is_mixin:
47
57
  base_classes.append(f"{self.client.name}MixinABC")
48
58
  return ", ".join(base_classes)
49
59
 
@@ -71,6 +81,8 @@ class OperationGroup(BaseModel):
71
81
  retval = add_to_pylint_disable(retval, "too-many-public-methods")
72
82
  if len(self.class_name) > NAME_LENGTH_LIMIT:
73
83
  retval = add_to_pylint_disable(retval, "name-too-long")
84
+ if len(self.operation_groups) > 6:
85
+ retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
74
86
  return retval
75
87
 
76
88
  @property
@@ -88,6 +100,13 @@ class OperationGroup(BaseModel):
88
100
  file_import.merge(
89
101
  operation.imports(async_mode, relative_path=relative_path)
90
102
  )
103
+ if not self.code_model.options["combine_operation_files"]:
104
+ for og in self.operation_groups:
105
+ file_import.add_submodule_import(
106
+ ".",
107
+ og.class_name,
108
+ ImportType.LOCAL,
109
+ )
91
110
  # for multiapi
92
111
  if (
93
112
  (self.code_model.public_model_types)
@@ -124,7 +143,45 @@ class OperationGroup(BaseModel):
124
143
  @property
125
144
  def is_mixin(self) -> bool:
126
145
  """The operation group with no name is the direct client methods."""
127
- return self.property_name == ""
146
+ return self.identify_name == ""
147
+
148
+ def link_lro_initial_operations(self) -> None:
149
+ """Link each LRO operation to its initial operation"""
150
+ for operation_group in self.operation_groups:
151
+ for operation in operation_group.operations:
152
+ if isinstance(operation, (LROOperation, LROPagingOperation)):
153
+ operation.initial_operation = self.lookup_operation(
154
+ id(operation.yaml_data["initialOperation"])
155
+ )
156
+
157
+ def lookup_operation(self, operation_id: int) -> "OperationType":
158
+ try:
159
+ return next(
160
+ o
161
+ for og in self.operation_groups
162
+ for o in og.operations
163
+ if id(o.yaml_data) == operation_id
164
+ )
165
+ except StopIteration as exc:
166
+ raise KeyError(f"No operation with id {operation_id} found.") from exc
167
+
168
+ @property
169
+ def lro_operations(self) -> List["OperationType"]:
170
+ return [
171
+ operation
172
+ for operation in self.operations
173
+ if operation.operation_type in ("lro", "lropaging")
174
+ ] + [
175
+ operation
176
+ for operation_group in self.operation_groups
177
+ for operation in operation_group.lro_operations
178
+ ]
179
+
180
+ @property
181
+ def has_operations(self) -> bool:
182
+ return any(
183
+ operation_group.has_operations for operation_group in self.operation_groups
184
+ ) or bool(self.operations)
128
185
 
129
186
  @classmethod
130
187
  def from_yaml(
@@ -179,7 +179,7 @@ class _ParameterBase(
179
179
  )
180
180
  if isinstance(self.type, CombinedType) and self.type.name:
181
181
  file_import.add_submodule_import(
182
- "..",
182
+ "..." if async_mode else "..",
183
183
  "_types",
184
184
  ImportType.LOCAL,
185
185
  TypingSection.TYPING,
@@ -120,8 +120,9 @@ class Response(BaseModel):
120
120
  if self.nullable:
121
121
  file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
122
122
  if isinstance(self.type, CombinedType) and self.type.name:
123
+ async_mode = kwargs.get("async_mode", False)
123
124
  file_import.add_submodule_import(
124
- "..",
125
+ "..." if async_mode else "..",
125
126
  "_types",
126
127
  ImportType.LOCAL,
127
128
  TypingSection.TYPING,
@@ -34,6 +34,7 @@ from .utils import (
34
34
  extract_sample_name,
35
35
  get_namespace_from_package_name,
36
36
  get_namespace_config,
37
+ get_all_operation_groups_recursively,
37
38
  )
38
39
 
39
40
  _LOGGER = logging.getLogger(__name__)
@@ -415,14 +416,15 @@ class JinjaSerializer(ReaderAndWriter): # pylint: disable=abstract-method
415
416
  clients=clients,
416
417
  )
417
418
  else:
418
- for client in self.code_model.clients:
419
- for operation_group in client.operation_groups:
420
- self._serialize_and_write_operations_file(
421
- env=env,
422
- namespace_path=namespace_path,
423
- operation_group=operation_group,
424
- clients=self.code_model.clients,
425
- )
419
+ for operation_group in get_all_operation_groups_recursively(
420
+ self.code_model.clients
421
+ ):
422
+ self._serialize_and_write_operations_file(
423
+ env=env,
424
+ namespace_path=namespace_path,
425
+ operation_group=operation_group,
426
+ clients=clients,
427
+ )
426
428
 
427
429
  def _serialize_and_write_version_file(
428
430
  self,
@@ -48,9 +48,8 @@ class ClientSerializer:
48
48
  @property
49
49
  def class_definition(self) -> str:
50
50
  class_name = self.client.name
51
- has_mixin_og = any(og for og in self.client.operation_groups if og.is_mixin)
52
51
  base_class = ""
53
- if has_mixin_og:
52
+ if self.client.has_mixin:
54
53
  base_class = f"{class_name}OperationsMixin"
55
54
  pylint_disable = self.client.pylint_disable
56
55
  if base_class:
@@ -7,6 +7,7 @@ from typing import Optional, List, Union
7
7
  import functools
8
8
  from jinja2 import Environment
9
9
 
10
+ from .utils import get_all_operation_groups_recursively
10
11
  from ..models import (
11
12
  CodeModel,
12
13
  OperationGroup,
@@ -45,18 +46,18 @@ class OperationGroupsSerializer(BaseSerializer):
45
46
  for client in self.clients
46
47
  for r in client.request_builders
47
48
  if r.client.name == operation_group.client.name
48
- and r.group_name == operation_group.property_name
49
+ and r.group_name == operation_group.identify_name
49
50
  and not r.is_overload
50
51
  and not r.abstract
51
52
  and not r.is_lro # lro has already initial builder
52
53
  ]
53
54
 
54
55
  def serialize(self) -> str:
55
- operation_groups = (
56
- [self.operation_group]
57
- if self.operation_group
58
- else [og for client in self.clients for og in client.operation_groups]
59
- )
56
+ if self.operation_group:
57
+ operation_groups = [self.operation_group]
58
+ else:
59
+ operation_groups = get_all_operation_groups_recursively(self.clients)
60
+
60
61
  imports = FileImport(self.code_model)
61
62
  for operation_group in operation_groups:
62
63
  imports.merge(
@@ -3,9 +3,11 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- from typing import Optional
6
+ from typing import Optional, List
7
7
  from pathlib import Path
8
8
 
9
+ from ..models import Client, OperationGroup
10
+
9
11
 
10
12
  def method_signature_and_response_type_annotation_template(
11
13
  *,
@@ -30,3 +32,15 @@ def get_namespace_config(namespace: str, multiapi: bool) -> str:
30
32
 
31
33
  def get_namespace_from_package_name(package_name: Optional[str]) -> str:
32
34
  return (package_name or "").replace("-", ".")
35
+
36
+
37
+ def get_all_operation_groups_recursively(clients: List[Client]) -> List[OperationGroup]:
38
+ operation_groups = []
39
+ queue = []
40
+ for client in clients:
41
+ queue.extend(client.operation_groups)
42
+ while queue:
43
+ operation_groups.append(queue.pop(0))
44
+ if operation_groups[-1].operation_groups:
45
+ queue.extend(operation_groups[-1].operation_groups)
46
+ return operation_groups
@@ -726,7 +726,11 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
726
726
  ):
727
727
  if obj is None:
728
728
  return obj
729
- return _deserialize_with_callable(deserializer, obj)
729
+ try:
730
+ return _deserialize_with_callable(deserializer, obj)
731
+ except Exception:
732
+ pass
733
+ return obj
730
734
 
731
735
  if get_deserializer(annotation, rf):
732
736
  return functools.partial(_deserialize_default, get_deserializer(annotation, rf))
@@ -38,6 +38,13 @@ class {{ operation_group.class_name }}: {{ operation_group.pylint_disable }}
38
38
  {% if code_model.options["multiapi"] %}
39
39
  self._api_version = input_args.pop(0) if input_args else kwargs.pop("api_version")
40
40
  {% endif %}
41
+
42
+ {% for og in operation_group.operation_groups %}
43
+ self.{{ og.property_name }} = {{ og.class_name }}(
44
+ self._client, self._config, self._serialize, self._deserialize{{ ", self._api_version" if code_model.options["multiapi"] else "" }}
45
+ )
46
+ {% endfor %}
47
+
41
48
  {{ check_abstract_methods() }}
42
49
  {% elif operation_group.has_abstract_operations %}
43
50
 
@@ -124,11 +124,9 @@ def update_description(
124
124
  return description
125
125
 
126
126
 
127
- def update_operation_group_class_name(
128
- yaml_data: Dict[str, Any], class_name: str
129
- ) -> str:
127
+ def update_operation_group_class_name(prefix: str, class_name: str) -> str:
130
128
  if class_name == "":
131
- return yaml_data["name"] + "OperationsMixin"
129
+ return prefix + "OperationsMixin"
132
130
  if class_name == "Operations":
133
131
  return "Operations"
134
132
  return class_name + "Operations"
@@ -511,7 +509,13 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
511
509
  ) -> None:
512
510
  operation_groups_yaml_data = client["operationGroups"]
513
511
  for operation_group in operation_groups_yaml_data:
514
- operation_group["clientName"] = client["name"]
512
+ operation_group["identifyName"] = self.pad_reserved_words(
513
+ operation_group.get("name", operation_group["propertyName"]),
514
+ PadType.OPERATION_GROUP,
515
+ )
516
+ operation_group["identifyName"] = to_snake_case(
517
+ operation_group["identifyName"]
518
+ )
515
519
  operation_group["propertyName"] = self.pad_reserved_words(
516
520
  operation_group["propertyName"], PadType.OPERATION_GROUP
517
521
  )
@@ -519,11 +523,14 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
519
523
  operation_group["propertyName"]
520
524
  )
521
525
  operation_group["className"] = update_operation_group_class_name(
522
- client, operation_group["className"]
526
+ client["name"], operation_group["className"]
523
527
  )
524
528
  for operation in operation_group["operations"]:
525
529
  self.get_operation_updater(operation)(code_model, operation)
526
530
 
531
+ if operation_group.get("operationGroups"):
532
+ self.update_operation_groups(code_model, operation_group)
533
+
527
534
  def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
528
535
  """Convert in place the YAML str."""
529
536
  self.update_types(yaml_data["types"])
@@ -93,6 +93,7 @@ _always_reserved = [
93
93
  "yield",
94
94
  "async",
95
95
  "await",
96
+ "int",
96
97
  ]
97
98
 
98
99
  RESERVED_WORDS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autorest/python",
3
- "version": "6.10.2",
3
+ "version": "6.11.0",
4
4
  "description": "The Python extension for generators in AutoRest.",
5
5
  "main": "index.js",
6
6
  "repository": {