@autorest/python 5.13.0 → 5.16.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.
Files changed (101) hide show
  1. package/ChangeLog.md +67 -0
  2. package/autorest/__init__.py +1 -2
  3. package/autorest/black/__init__.py +12 -5
  4. package/autorest/codegen/__init__.py +239 -105
  5. package/autorest/codegen/models/__init__.py +29 -18
  6. package/autorest/codegen/models/base_builder.py +48 -11
  7. package/autorest/codegen/models/base_model.py +6 -4
  8. package/autorest/codegen/models/base_schema.py +21 -24
  9. package/autorest/codegen/models/client.py +70 -20
  10. package/autorest/codegen/models/code_model.py +144 -129
  11. package/autorest/codegen/models/constant_schema.py +32 -16
  12. package/autorest/codegen/models/credential_model.py +55 -0
  13. package/autorest/codegen/models/credential_schema.py +21 -16
  14. package/autorest/codegen/models/credential_schema_policy.py +11 -15
  15. package/autorest/codegen/models/dictionary_schema.py +27 -24
  16. package/autorest/codegen/models/enum_schema.py +41 -62
  17. package/autorest/codegen/models/imports.py +72 -41
  18. package/autorest/codegen/models/list_schema.py +40 -18
  19. package/autorest/codegen/models/lro_operation.py +61 -25
  20. package/autorest/codegen/models/lro_paging_operation.py +5 -6
  21. package/autorest/codegen/models/object_schema.py +113 -59
  22. package/autorest/codegen/models/operation.py +251 -111
  23. package/autorest/codegen/models/operation_group.py +67 -32
  24. package/autorest/codegen/models/paging_operation.py +48 -21
  25. package/autorest/codegen/models/parameter.py +182 -90
  26. package/autorest/codegen/models/parameter_list.py +184 -163
  27. package/autorest/codegen/models/primitive_schemas.py +89 -70
  28. package/autorest/codegen/models/property.py +49 -31
  29. package/autorest/codegen/models/request_builder.py +67 -32
  30. package/autorest/codegen/models/request_builder_parameter.py +54 -23
  31. package/autorest/codegen/models/request_builder_parameter_list.py +77 -108
  32. package/autorest/codegen/models/schema_request.py +16 -6
  33. package/autorest/codegen/models/schema_response.py +35 -17
  34. package/autorest/codegen/models/utils.py +24 -1
  35. package/autorest/codegen/serializers/__init__.py +273 -89
  36. package/autorest/codegen/serializers/builder_serializer.py +711 -333
  37. package/autorest/codegen/serializers/client_serializer.py +114 -43
  38. package/autorest/codegen/serializers/general_serializer.py +84 -25
  39. package/autorest/codegen/serializers/import_serializer.py +93 -31
  40. package/autorest/codegen/serializers/metadata_serializer.py +73 -24
  41. package/autorest/codegen/serializers/model_base_serializer.py +42 -14
  42. package/autorest/codegen/serializers/model_generic_serializer.py +1 -4
  43. package/autorest/codegen/serializers/model_init_serializer.py +5 -1
  44. package/autorest/codegen/serializers/model_python3_serializer.py +9 -8
  45. package/autorest/codegen/serializers/operation_groups_serializer.py +20 -8
  46. package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
  47. package/autorest/codegen/serializers/patch_serializer.py +14 -2
  48. package/autorest/codegen/serializers/{rest_serializer.py → request_builders_serializer.py} +29 -12
  49. package/autorest/codegen/serializers/utils.py +60 -21
  50. package/autorest/codegen/templates/CHANGELOG.md.jinja2 +6 -0
  51. package/autorest/codegen/templates/LICENSE.jinja2 +21 -0
  52. package/autorest/codegen/templates/MANIFEST.in.jinja2 +7 -0
  53. package/autorest/codegen/templates/README.md.jinja2 +105 -0
  54. package/autorest/codegen/templates/config.py.jinja2 +4 -4
  55. package/autorest/codegen/templates/dev_requirements.txt.jinja2 +10 -0
  56. package/autorest/codegen/templates/enum.py.jinja2 +1 -1
  57. package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
  58. package/autorest/codegen/templates/init.py.jinja2 +9 -6
  59. package/autorest/codegen/templates/keywords.jinja2 +14 -1
  60. package/autorest/codegen/templates/lro_operation.py.jinja2 +5 -7
  61. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +5 -7
  62. package/autorest/codegen/templates/metadata.json.jinja2 +10 -9
  63. package/autorest/codegen/templates/model.py.jinja2 +1 -6
  64. package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
  65. package/autorest/codegen/templates/operation.py.jinja2 +8 -11
  66. package/autorest/codegen/templates/operation_group.py.jinja2 +15 -18
  67. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -2
  68. package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
  69. package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
  70. package/autorest/codegen/templates/patch.py.jinja2 +18 -29
  71. package/autorest/codegen/templates/request_builder.py.jinja2 +19 -14
  72. package/autorest/codegen/templates/setup.py.jinja2 +79 -20
  73. package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
  74. package/autorest/jsonrpc/__init__.py +7 -12
  75. package/autorest/jsonrpc/localapi.py +4 -3
  76. package/autorest/jsonrpc/server.py +13 -6
  77. package/autorest/jsonrpc/stdstream.py +13 -6
  78. package/autorest/m2r/__init__.py +5 -8
  79. package/autorest/multiapi/__init__.py +24 -14
  80. package/autorest/multiapi/models/client.py +21 -11
  81. package/autorest/multiapi/models/code_model.py +23 -10
  82. package/autorest/multiapi/models/config.py +4 -1
  83. package/autorest/multiapi/models/constant_global_parameter.py +1 -0
  84. package/autorest/multiapi/models/global_parameter.py +2 -1
  85. package/autorest/multiapi/models/global_parameters.py +14 -8
  86. package/autorest/multiapi/models/imports.py +35 -18
  87. package/autorest/multiapi/models/mixin_operation.py +5 -5
  88. package/autorest/multiapi/models/operation_group.py +2 -1
  89. package/autorest/multiapi/models/operation_mixin_group.py +21 -10
  90. package/autorest/multiapi/serializers/__init__.py +18 -23
  91. package/autorest/multiapi/serializers/import_serializer.py +47 -15
  92. package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
  93. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +1 -1
  94. package/autorest/multiapi/utils.py +3 -3
  95. package/autorest/namer/__init__.py +2 -4
  96. package/autorest/namer/name_converter.py +200 -103
  97. package/autorest/namer/python_mappings.py +10 -22
  98. package/package.json +3 -3
  99. package/run-python3.js +2 -3
  100. package/venvtools.py +1 -1
  101. package/autorest/codegen/models/rest.py +0 -42
@@ -4,19 +4,23 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  import logging
7
- from typing import Dict, List, Any, Set
7
+ from typing import Dict, List, Any, Set, TYPE_CHECKING
8
8
 
9
9
  from .base_model import BaseModel
10
10
  from .operation import Operation
11
11
  from .lro_operation import LROOperation
12
12
  from .paging_operation import PagingOperation
13
13
  from .lro_paging_operation import LROPagingOperation
14
- from .imports import FileImport, ImportType
14
+ from .imports import FileImport, ImportType, TypingSection
15
+
16
+ if TYPE_CHECKING:
17
+ from .code_model import CodeModel
15
18
 
16
19
 
17
20
  _LOGGER = logging.getLogger(__name__)
18
21
 
19
- def _get_operation(code_model, yaml_data: Dict[str, Any]) -> Operation:
22
+
23
+ def _get_operation(yaml_data: Dict[str, Any], code_model: "CodeModel") -> Operation:
20
24
  lro_operation = yaml_data.get("extensions", {}).get("x-ms-long-running-operation")
21
25
  paging_operation = yaml_data.get("extensions", {}).get("x-ms-pageable")
22
26
  operation_schema = Operation
@@ -31,101 +35,132 @@ def _get_operation(code_model, yaml_data: Dict[str, Any]) -> Operation:
31
35
 
32
36
 
33
37
  class OperationGroup(BaseModel):
34
- """Represent an operation group.
38
+ """Represent an operation group."""
35
39
 
36
- """
37
40
  def __init__(
38
41
  self,
39
- code_model,
40
42
  yaml_data: Dict[str, Any],
43
+ code_model: "CodeModel",
41
44
  name: str,
42
45
  class_name: str,
43
46
  operations: List[Operation],
44
- api_versions: Set[str]
47
+ api_versions: Set[str],
45
48
  ) -> None:
46
- super().__init__(yaml_data)
47
- self.code_model = code_model
49
+ super().__init__(yaml_data, code_model)
48
50
  self.name = name
49
51
  self.class_name = class_name
50
52
  self.operations = operations
51
53
  self.api_versions = api_versions
52
54
 
55
+ @property
56
+ def has_abstract_operations(self) -> bool:
57
+ return any(o for o in self.operations if o.abstract)
58
+
59
+ def base_class(self, async_mode: bool) -> str:
60
+ base_classes: List[str] = []
61
+ if self.is_empty_operation_group and self.code_model.need_mixin_abc:
62
+ base_classes.append("MixinABC")
63
+ if not (async_mode or self.code_model.options["python3_only"]):
64
+ base_classes.append("object")
65
+ if self.has_abstract_operations:
66
+ base_classes.append("abc.ABC")
67
+ return ", ".join(base_classes)
68
+
53
69
  def imports_for_multiapi(self, async_mode: bool) -> FileImport:
54
70
  file_import = FileImport()
55
71
  for operation in self.operations:
56
72
  file_import.merge(operation.imports_for_multiapi(async_mode))
73
+ file_import.add_submodule_import(
74
+ ".." if async_mode else ".", "models", ImportType.LOCAL, alias="_models"
75
+ )
57
76
  return file_import
58
77
 
59
- def imports(self, async_mode: bool) -> FileImport:
78
+ def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
60
79
  file_import = FileImport()
61
- file_import.add_submodule_import("azure.core.exceptions", "ClientAuthenticationError", ImportType.AZURECORE)
62
- file_import.add_submodule_import("azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE)
63
- file_import.add_submodule_import("azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE)
80
+
64
81
  for operation in self.operations:
65
- file_import.merge(operation.imports(async_mode))
82
+ file_import.merge(operation.imports(async_mode, is_python3_file))
66
83
  local_path = "..." if async_mode else ".."
67
84
  if self.code_model.has_schemas and self.code_model.options["models_mode"]:
68
- file_import.add_submodule_import(local_path, "models", ImportType.LOCAL, alias="_models")
85
+ file_import.add_submodule_import(
86
+ local_path, "models", ImportType.LOCAL, alias="_models"
87
+ )
69
88
  if self.code_model.options["builders_visibility"] == "embedded" and async_mode:
70
89
  if not self.code_model.options["combine_operation_files"]:
71
- operation_group_name = "" if self.is_empty_operation_group else self.name
90
+ operation_group_name = (
91
+ "" if self.is_empty_operation_group else self.name
92
+ )
72
93
  operation_group_builders = [
73
- r for r in self.code_model.rest.request_builders
94
+ r
95
+ for r in self.code_model.request_builders
74
96
  if r.operation_group_name == operation_group_name
75
97
  ]
76
98
  else:
77
- operation_group_builders = self.code_model.rest.request_builders
99
+ operation_group_builders = self.code_model.request_builders
78
100
  for request_builder in operation_group_builders:
101
+ if request_builder.abstract:
102
+ continue
79
103
  python3_only = self.code_model.options["python3_only"]
80
- typed_sync_operation_file = self.code_model.options["add_python3_operation_files"]
81
- suffix = "_py3" if typed_sync_operation_file and not python3_only else ""
104
+ typed_sync_operation_file = self.code_model.options[
105
+ "add_python3_operation_files"
106
+ ]
107
+ suffix = (
108
+ "_py3" if typed_sync_operation_file and not python3_only else ""
109
+ )
82
110
  file_import.add_submodule_import(
83
111
  f"...{self.code_model.operations_folder_name}.{self.filename}{suffix}",
84
112
  request_builder.name,
85
- import_type=ImportType.LOCAL
113
+ import_type=ImportType.LOCAL,
86
114
  )
115
+ if self.code_model.need_mixin_abc:
116
+ file_import.add_submodule_import(".._vendor", "MixinABC", ImportType.LOCAL)
117
+ file_import.add_submodule_import(
118
+ "typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL
119
+ )
120
+ file_import.define_mypy_type("T", "TypeVar('T')")
87
121
  type_value = "Optional[Callable[[PipelineResponse[HttpRequest, {}HttpResponse], T, Dict[str, Any]], Any]]"
88
122
  file_import.define_mypy_type(
89
- "ClsType",
90
- type_value.format(""),
91
- type_value.format("Async")
123
+ "ClsType", type_value.format(""), type_value.format("Async")
92
124
  )
93
125
  return file_import
94
126
 
95
-
96
127
  @property
97
128
  def filename(self) -> str:
98
129
  basename = self.name
99
130
  if self.is_empty_operation_group:
100
131
  basename = self.code_model.module_name
101
132
 
102
- if basename == "operations" or self.code_model.options["combine_operation_files"]:
133
+ if (
134
+ basename == "operations"
135
+ or self.code_model.options["combine_operation_files"]
136
+ ):
103
137
  return f"_operations"
104
138
  return f"_{basename}_operations"
105
139
 
106
140
  @property
107
141
  def is_empty_operation_group(self) -> bool:
108
- """The operation group with no name is the direct client methods.
109
- """
142
+ """The operation group with no name is the direct client methods."""
110
143
  return not self.yaml_data["language"]["default"]["name"]
111
144
 
112
145
  @classmethod
113
- def from_yaml(cls, code_model, yaml_data: Dict[str, Any]) -> "OperationGroup":
146
+ def from_yaml(
147
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
148
+ ) -> "OperationGroup":
114
149
  name = yaml_data["language"]["python"]["name"]
115
150
  _LOGGER.debug("Parsing %s operation group", name)
116
151
 
117
152
  operations = []
118
153
  api_versions: Set[str] = set()
119
154
  for operation_yaml in yaml_data["operations"]:
120
- operation = _get_operation(code_model, operation_yaml)
155
+ operation = _get_operation(operation_yaml, code_model)
121
156
  operations.append(operation)
122
157
  api_versions.update(operation.api_versions)
123
158
 
124
159
  return cls(
125
- code_model=code_model,
126
160
  yaml_data=yaml_data,
161
+ code_model=code_model,
127
162
  name=name,
128
163
  class_name=yaml_data["language"]["python"]["className"],
129
164
  operations=operations,
130
- api_versions=api_versions
165
+ api_versions=api_versions,
131
166
  )
@@ -4,7 +4,7 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  import logging
7
- from typing import cast, Dict, List, Any, Optional, Set
7
+ from typing import cast, Dict, List, Any, Optional, Set, TYPE_CHECKING
8
8
 
9
9
  from .operation import Operation
10
10
  from .schema_response import SchemaResponse
@@ -14,14 +14,18 @@ from .object_schema import ObjectSchema
14
14
  from .schema_request import SchemaRequest
15
15
  from .parameter_list import ParameterList
16
16
 
17
+ if TYPE_CHECKING:
18
+ from .code_model import CodeModel
19
+
17
20
  _LOGGER = logging.getLogger(__name__)
18
21
 
19
22
 
20
23
  class PagingOperation(Operation):
21
24
  def __init__(
22
25
  self,
23
- code_model,
24
26
  yaml_data: Dict[str, Any],
27
+ code_model: "CodeModel",
28
+ request_builder: RequestBuilder,
25
29
  name: str,
26
30
  description: str,
27
31
  api_versions: Set[str],
@@ -34,11 +38,13 @@ class PagingOperation(Operation):
34
38
  want_description_docstring: bool = True,
35
39
  want_tracing: bool = True,
36
40
  *,
37
- override_success_response_to_200: bool = False
41
+ abstract: bool = False,
42
+ override_success_response_to_200: bool = False,
38
43
  ) -> None:
39
- super(PagingOperation, self).__init__(
40
- code_model,
44
+ super().__init__(
41
45
  yaml_data,
46
+ code_model,
47
+ request_builder,
42
48
  name,
43
49
  description,
44
50
  api_versions,
@@ -49,11 +55,16 @@ class PagingOperation(Operation):
49
55
  responses,
50
56
  exceptions,
51
57
  want_description_docstring,
52
- want_tracing
58
+ want_tracing=want_tracing,
59
+ abstract=abstract,
53
60
  )
54
61
  self._item_name: str = yaml_data["extensions"]["x-ms-pageable"].get("itemName")
55
- self._next_link_name: str = yaml_data["extensions"]["x-ms-pageable"].get("nextLinkName")
56
- self.operation_name: str = yaml_data["extensions"]["x-ms-pageable"].get("operationName")
62
+ self._next_link_name: str = yaml_data["extensions"]["x-ms-pageable"].get(
63
+ "nextLinkName"
64
+ )
65
+ self.operation_name: str = yaml_data["extensions"]["x-ms-pageable"].get(
66
+ "operationName"
67
+ )
57
68
  self.next_operation: Optional[Operation] = None
58
69
  self.override_success_response_to_200 = override_success_response_to_200
59
70
 
@@ -61,12 +72,13 @@ class PagingOperation(Operation):
61
72
  response = self.responses[0]
62
73
  if not isinstance(response.schema, ObjectSchema):
63
74
  raise ValueError(
64
- "The response of a paging operation must be of type " + f"ObjectSchema but {response.schema} is not"
75
+ "The response of a paging operation must be of type "
76
+ + f"ObjectSchema but {response.schema} is not"
65
77
  )
66
78
  return response
67
79
 
68
80
  def _find_python_name(self, rest_api_name: str, log_name: str) -> str:
69
- response = self._get_response()
81
+ response = self.responses[0]
70
82
  response_schema = cast(ObjectSchema, response.schema)
71
83
  if response_schema:
72
84
  for prop in response_schema.properties:
@@ -84,7 +96,8 @@ class PagingOperation(Operation):
84
96
  item_name = self._item_name or "value"
85
97
  try:
86
98
  return (
87
- self._find_python_name(item_name, "itemName") if code_model.options["models_mode"]
99
+ self._find_python_name(item_name, "itemName")
100
+ if code_model.options["models_mode"]
88
101
  else item_name
89
102
  )
90
103
  except ValueError:
@@ -125,12 +138,16 @@ class PagingOperation(Operation):
125
138
  def _imports_shared(self, async_mode: bool) -> FileImport:
126
139
  file_import = super()._imports_shared(async_mode)
127
140
  if async_mode:
128
- file_import.add_submodule_import("typing", "AsyncIterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
141
+ file_import.add_submodule_import(
142
+ "typing", "AsyncIterable", ImportType.STDLIB, TypingSection.CONDITIONAL
143
+ )
129
144
  else:
130
- file_import.add_submodule_import("typing", "Iterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
145
+ file_import.add_submodule_import(
146
+ "typing", "Iterable", ImportType.STDLIB, TypingSection.CONDITIONAL
147
+ )
131
148
  if (
132
- self.next_request_builder and
133
- self.code_model.options["builders_visibility"] == "embedded"
149
+ self.next_request_builder
150
+ and self.code_model.options["builders_visibility"] == "embedded"
134
151
  and not async_mode
135
152
  ):
136
153
  file_import.merge(self.next_request_builder.imports())
@@ -141,14 +158,20 @@ class PagingOperation(Operation):
141
158
  pager_import_path = ".".join(self.get_pager_path(async_mode).split(".")[:-1])
142
159
  pager = self.get_pager(async_mode)
143
160
 
144
- file_import.add_submodule_import(pager_import_path, pager, ImportType.AZURECORE, TypingSection.CONDITIONAL)
161
+ file_import.add_submodule_import(
162
+ pager_import_path, pager, ImportType.AZURECORE, TypingSection.CONDITIONAL
163
+ )
145
164
 
146
165
  return file_import
147
166
 
148
- def imports(self, async_mode: bool) -> FileImport:
149
- file_import = super(PagingOperation, self).imports(async_mode)
167
+ def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
168
+ file_import = self._imports_base(async_mode, is_python3_file)
150
169
  # operation adds an import for distributed_trace_async, we don't want it
151
- file_import.imports = [i for i in file_import.imports if not i.submodule_name == "distributed_trace_async"]
170
+ file_import.imports = [
171
+ i
172
+ for i in file_import.imports
173
+ if not i.submodule_name == "distributed_trace_async"
174
+ ]
152
175
 
153
176
  pager_import_path = ".".join(self.get_pager_path(async_mode).split(".")[:-1])
154
177
  pager = self.get_pager(async_mode)
@@ -156,11 +179,15 @@ class PagingOperation(Operation):
156
179
  file_import.add_submodule_import(pager_import_path, pager, ImportType.AZURECORE)
157
180
 
158
181
  if async_mode:
159
- file_import.add_submodule_import("azure.core.async_paging", "AsyncList", ImportType.AZURECORE)
182
+ file_import.add_submodule_import(
183
+ "azure.core.async_paging", "AsyncList", ImportType.AZURECORE
184
+ )
160
185
 
161
186
  if self.code_model.options["tracing"] and self.want_tracing:
162
187
  file_import.add_submodule_import(
163
- "azure.core.tracing.decorator", "distributed_trace", ImportType.AZURECORE,
188
+ "azure.core.tracing.decorator",
189
+ "distributed_trace",
190
+ ImportType.AZURECORE,
164
191
  )
165
192
 
166
193
  return file_import