@autorest/python 5.15.0 → 5.18.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 (118) hide show
  1. package/ChangeLog.md +98 -4
  2. package/README.md +30 -4
  3. package/autorest/__init__.py +2 -3
  4. package/autorest/black/__init__.py +12 -5
  5. package/autorest/codegen/__init__.py +122 -211
  6. package/autorest/codegen/models/__init__.py +122 -78
  7. package/autorest/codegen/models/base_builder.py +70 -72
  8. package/autorest/codegen/models/base_model.py +7 -5
  9. package/autorest/codegen/models/{base_schema.py → base_type.py} +68 -45
  10. package/autorest/codegen/models/client.py +193 -40
  11. package/autorest/codegen/models/code_model.py +145 -245
  12. package/autorest/codegen/models/combined_type.py +107 -0
  13. package/autorest/codegen/models/constant_type.py +122 -0
  14. package/autorest/codegen/models/credential_types.py +224 -0
  15. package/autorest/codegen/models/dictionary_type.py +131 -0
  16. package/autorest/codegen/models/enum_type.py +195 -0
  17. package/autorest/codegen/models/imports.py +93 -41
  18. package/autorest/codegen/models/list_type.py +149 -0
  19. package/autorest/codegen/models/lro_operation.py +90 -133
  20. package/autorest/codegen/models/lro_paging_operation.py +28 -12
  21. package/autorest/codegen/models/model_type.py +262 -0
  22. package/autorest/codegen/models/operation.py +412 -259
  23. package/autorest/codegen/models/operation_group.py +80 -91
  24. package/autorest/codegen/models/paging_operation.py +101 -117
  25. package/autorest/codegen/models/parameter.py +302 -341
  26. package/autorest/codegen/models/parameter_list.py +373 -357
  27. package/autorest/codegen/models/primitive_types.py +544 -0
  28. package/autorest/codegen/models/property.py +136 -134
  29. package/autorest/codegen/models/request_builder.py +138 -86
  30. package/autorest/codegen/models/request_builder_parameter.py +122 -86
  31. package/autorest/codegen/models/response.py +325 -0
  32. package/autorest/codegen/models/utils.py +13 -17
  33. package/autorest/codegen/serializers/__init__.py +212 -112
  34. package/autorest/codegen/serializers/builder_serializer.py +931 -1040
  35. package/autorest/codegen/serializers/client_serializer.py +140 -84
  36. package/autorest/codegen/serializers/general_serializer.py +26 -50
  37. package/autorest/codegen/serializers/import_serializer.py +96 -31
  38. package/autorest/codegen/serializers/metadata_serializer.py +39 -79
  39. package/autorest/codegen/serializers/model_base_serializer.py +62 -34
  40. package/autorest/codegen/serializers/model_generic_serializer.py +9 -10
  41. package/autorest/codegen/serializers/model_init_serializer.py +4 -2
  42. package/autorest/codegen/serializers/model_python3_serializer.py +29 -22
  43. package/autorest/codegen/serializers/operation_groups_serializer.py +21 -19
  44. package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
  45. package/autorest/codegen/serializers/parameter_serializer.py +174 -0
  46. package/autorest/codegen/serializers/patch_serializer.py +4 -1
  47. package/autorest/codegen/serializers/request_builders_serializer.py +57 -0
  48. package/autorest/codegen/serializers/utils.py +0 -126
  49. package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
  50. package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +7 -7
  51. package/autorest/codegen/templates/config.py.jinja2 +13 -13
  52. package/autorest/codegen/templates/enum.py.jinja2 +4 -4
  53. package/autorest/codegen/templates/enum_container.py.jinja2 +1 -1
  54. package/autorest/codegen/templates/init.py.jinja2 +3 -3
  55. package/autorest/codegen/templates/lro_operation.py.jinja2 +6 -5
  56. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +6 -5
  57. package/autorest/codegen/templates/metadata.json.jinja2 +36 -35
  58. package/autorest/codegen/templates/model.py.jinja2 +23 -24
  59. package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
  60. package/autorest/codegen/templates/model_init.py.jinja2 +3 -5
  61. package/autorest/codegen/templates/operation.py.jinja2 +10 -14
  62. package/autorest/codegen/templates/operation_group.py.jinja2 +9 -15
  63. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -1
  64. package/autorest/codegen/templates/operation_tools.jinja2 +8 -2
  65. package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
  66. package/autorest/codegen/templates/request_builder.py.jinja2 +19 -10
  67. package/autorest/codegen/templates/setup.py.jinja2 +9 -3
  68. package/autorest/codegen/templates/vendor.py.jinja2 +1 -1
  69. package/autorest/jsonrpc/__init__.py +7 -12
  70. package/autorest/jsonrpc/localapi.py +4 -3
  71. package/autorest/jsonrpc/server.py +28 -9
  72. package/autorest/jsonrpc/stdstream.py +13 -6
  73. package/autorest/m2r/__init__.py +5 -8
  74. package/autorest/m4reformatter/__init__.py +1126 -0
  75. package/autorest/multiapi/__init__.py +24 -14
  76. package/autorest/multiapi/models/client.py +21 -11
  77. package/autorest/multiapi/models/code_model.py +23 -10
  78. package/autorest/multiapi/models/config.py +4 -1
  79. package/autorest/multiapi/models/constant_global_parameter.py +1 -0
  80. package/autorest/multiapi/models/global_parameter.py +2 -1
  81. package/autorest/multiapi/models/global_parameters.py +14 -8
  82. package/autorest/multiapi/models/imports.py +24 -17
  83. package/autorest/multiapi/models/mixin_operation.py +5 -5
  84. package/autorest/multiapi/models/operation_group.py +2 -1
  85. package/autorest/multiapi/models/operation_mixin_group.py +21 -10
  86. package/autorest/multiapi/serializers/__init__.py +20 -25
  87. package/autorest/multiapi/serializers/import_serializer.py +47 -17
  88. package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
  89. package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
  90. package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
  91. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +4 -4
  92. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
  93. package/autorest/multiapi/utils.py +3 -3
  94. package/autorest/postprocess/__init__.py +202 -0
  95. package/autorest/postprocess/get_all.py +19 -0
  96. package/autorest/postprocess/venvtools.py +73 -0
  97. package/autorest/preprocess/__init__.py +210 -0
  98. package/autorest/preprocess/helpers.py +54 -0
  99. package/autorest/{namer → preprocess}/python_mappings.py +25 -32
  100. package/package.json +3 -3
  101. package/run-python3.js +2 -3
  102. package/venvtools.py +1 -1
  103. package/autorest/codegen/models/constant_schema.py +0 -101
  104. package/autorest/codegen/models/credential_model.py +0 -47
  105. package/autorest/codegen/models/credential_schema.py +0 -91
  106. package/autorest/codegen/models/credential_schema_policy.py +0 -77
  107. package/autorest/codegen/models/dictionary_schema.py +0 -103
  108. package/autorest/codegen/models/enum_schema.py +0 -215
  109. package/autorest/codegen/models/list_schema.py +0 -123
  110. package/autorest/codegen/models/object_schema.py +0 -253
  111. package/autorest/codegen/models/primitive_schemas.py +0 -466
  112. package/autorest/codegen/models/request_builder_parameter_list.py +0 -280
  113. package/autorest/codegen/models/rest.py +0 -42
  114. package/autorest/codegen/models/schema_request.py +0 -45
  115. package/autorest/codegen/models/schema_response.py +0 -136
  116. package/autorest/codegen/serializers/rest_serializer.py +0 -57
  117. package/autorest/namer/__init__.py +0 -25
  118. package/autorest/namer/name_converter.py +0 -412
@@ -4,7 +4,8 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  from enum import Enum
7
- from typing import Dict, List, Optional, Tuple, Union, Set
7
+ from typing import Dict, List, Optional, Tuple, Union, Set, Mapping
8
+
8
9
 
9
10
  class ImportType(str, Enum):
10
11
  STDLIB = "stdlib"
@@ -12,11 +13,13 @@ class ImportType(str, Enum):
12
13
  AZURECORE = "azurecore"
13
14
  LOCAL = "local"
14
15
 
16
+
15
17
  class TypingSection(str, Enum):
16
18
  REGULAR = "regular" # this import is always a typing import
17
19
  CONDITIONAL = "conditional" # is a typing import when we're dealing with files that py2 will use, else regular
18
20
  TYPING = "typing" # never a typing import
19
21
 
22
+
20
23
  class ImportModel:
21
24
  def __init__(
22
25
  self,
@@ -36,11 +39,11 @@ class ImportModel:
36
39
  def __eq__(self, other):
37
40
  try:
38
41
  return (
39
- self.typing_section == other.typing_section and
40
- self.import_type == other.import_type and
41
- self.module_name == other.module_name and
42
- self.submodule_name == other.submodule_name and
43
- self.alias == other.alias
42
+ self.typing_section == other.typing_section
43
+ and self.import_type == other.import_type
44
+ and self.module_name == other.module_name
45
+ and self.submodule_name == other.submodule_name
46
+ and self.alias == other.alias
44
47
  )
45
48
  except AttributeError:
46
49
  return False
@@ -52,18 +55,32 @@ class ImportModel:
52
55
  retval += hash(getattr(self, attr))
53
56
  return retval
54
57
 
55
- class FileImport:
58
+
59
+ class TypeDefinition:
56
60
  def __init__(
57
61
  self,
58
- imports: List[ImportModel] = None
59
- ) -> None:
62
+ sync_definition: str,
63
+ async_definition: str,
64
+ version_imports: Mapping[Optional[Tuple[int, int]], ImportModel] = None,
65
+ ):
66
+ # version_imports: a map of "python version -> ImportModel".
67
+ # The python version is in form of (major, minor), for instance (3, 9) stands for py3.9.
68
+ # If the python version is None, it's a default ImportModel.
69
+ self.sync_definition = sync_definition
70
+ self.async_definition = async_definition
71
+ self.version_imports = version_imports
72
+
73
+
74
+ class FileImport:
75
+ def __init__(self, imports: List[ImportModel] = None) -> None:
60
76
  self.imports = imports or []
61
77
  # has sync and async type definitions
62
- self.type_definitions: Dict[str, Tuple[str, str]] = {}
78
+ self.type_definitions: Dict[str, TypeDefinition] = {}
63
79
 
64
80
  def _append_import(self, import_model: ImportModel) -> None:
65
81
  if not any(
66
- i for i in self.imports
82
+ i
83
+ for i in self.imports
67
84
  if all(
68
85
  getattr(i, attr) == getattr(import_model, attr)
69
86
  for attr in dir(i)
@@ -72,7 +89,9 @@ class FileImport:
72
89
  ):
73
90
  self.imports.append(import_model)
74
91
 
75
- def get_imports_from_section(self, typing_section: TypingSection) -> List[ImportModel]:
92
+ def get_imports_from_section(
93
+ self, typing_section: TypingSection
94
+ ) -> List[ImportModel]:
76
95
  return [i for i in self.imports if i.typing_section == typing_section]
77
96
 
78
97
  def add_submodule_import(
@@ -83,15 +102,16 @@ class FileImport:
83
102
  typing_section: TypingSection = TypingSection.REGULAR,
84
103
  alias: Optional[str] = None,
85
104
  ) -> None:
86
- """Add an import to this import block.
87
- """
88
- self._append_import(ImportModel(
89
- typing_section=typing_section,
90
- import_type=import_type,
91
- module_name=module_name,
92
- submodule_name=submodule_name,
93
- alias=alias,
94
- ))
105
+ """Add an import to this import block."""
106
+ self._append_import(
107
+ ImportModel(
108
+ typing_section=typing_section,
109
+ import_type=import_type,
110
+ module_name=module_name,
111
+ submodule_name=submodule_name,
112
+ alias=alias,
113
+ )
114
+ )
95
115
 
96
116
  def add_import(
97
117
  self,
@@ -101,16 +121,25 @@ class FileImport:
101
121
  alias: Optional[str] = None,
102
122
  ) -> None:
103
123
  # Implementation detail: a regular import is just a "from" with no from
104
- self._append_import(ImportModel(
105
- typing_section=typing_section,
106
- import_type=import_type,
107
- module_name=module_name,
108
- alias=alias,
109
- ))
124
+ self._append_import(
125
+ ImportModel(
126
+ typing_section=typing_section,
127
+ import_type=import_type,
128
+ module_name=module_name,
129
+ alias=alias,
130
+ )
131
+ )
110
132
 
111
- def define_mypy_type(self, type_name: str, type_value: str, async_type_value: Optional[str] = None):
112
- self.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
113
- self.type_definitions[type_name] = (type_value, async_type_value or type_value)
133
+ def define_mypy_type(
134
+ self,
135
+ type_name: str,
136
+ type_value: str,
137
+ async_type_value: Optional[str] = None,
138
+ version_imports: Mapping[Optional[Tuple[int, int]], ImportModel] = None,
139
+ ):
140
+ self.type_definitions[type_name] = TypeDefinition(
141
+ type_value, async_type_value or type_value, version_imports
142
+ )
114
143
 
115
144
  def merge(self, file_import: "FileImport") -> None:
116
145
  """Merge the given file import format."""
@@ -118,23 +147,46 @@ class FileImport:
118
147
  self._append_import(i)
119
148
  self.type_definitions.update(file_import.type_definitions)
120
149
 
121
- def to_dict(self) -> Dict[
150
+ def define_mutable_mapping_type(self) -> None:
151
+ """Helper function for defining the mutable mapping type"""
152
+ self.define_mypy_type(
153
+ "JSON",
154
+ "MutableMapping[str, Any] # pylint: disable=unsubscriptable-object",
155
+ None,
156
+ {
157
+ (3, 9): ImportModel(
158
+ TypingSection.CONDITIONAL,
159
+ ImportType.STDLIB,
160
+ "collections.abc",
161
+ submodule_name="MutableMapping",
162
+ ),
163
+ None: ImportModel(
164
+ TypingSection.CONDITIONAL,
165
+ ImportType.STDLIB,
166
+ "typing",
167
+ submodule_name="MutableMapping",
168
+ ),
169
+ },
170
+ )
171
+ self.add_submodule_import("typing", "Any", ImportType.STDLIB)
172
+
173
+ def to_dict(
174
+ self,
175
+ ) -> Dict[
122
176
  TypingSection,
123
- Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
177
+ Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
124
178
  ]:
125
179
  retval: Dict[
126
180
  TypingSection,
127
- Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
181
+ Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
128
182
  ] = dict()
129
183
  for i in self.imports:
130
184
  name_import: Optional[Union[str, Tuple[str, str]]] = None
131
185
  if i.submodule_name:
132
- name_import = (i.submodule_name, i.alias) if i.alias else i.submodule_name
133
- retval.setdefault(
134
- i.typing_section, dict()
135
- ).setdefault(
136
- i.import_type, dict()
137
- ).setdefault(
138
- i.module_name, set()
139
- ).add(name_import)
186
+ name_import = (
187
+ (i.submodule_name, i.alias) if i.alias else i.submodule_name
188
+ )
189
+ retval.setdefault(i.typing_section, dict()).setdefault(
190
+ i.import_type, dict()
191
+ ).setdefault(i.module_name, set()).add(name_import)
140
192
  return retval
@@ -0,0 +1,149 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+ from typing import Any, Dict, Optional, Union, TYPE_CHECKING, List
7
+ from .base_type import BaseType
8
+ from .imports import FileImport, ImportType, TypingSection
9
+
10
+ if TYPE_CHECKING:
11
+ from .code_model import CodeModel
12
+ from .model_type import ModelType
13
+
14
+
15
+ class ListType(BaseType):
16
+ def __init__(
17
+ self,
18
+ yaml_data: Dict[str, Any],
19
+ code_model: "CodeModel",
20
+ element_type: BaseType,
21
+ ) -> None:
22
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
23
+ self.element_type = element_type
24
+ self.max_items: Optional[int] = yaml_data.get("maxItems")
25
+ self.min_items: Optional[int] = yaml_data.get("minItems")
26
+ self.unique_items: bool = yaml_data.get("uniqueItems", False)
27
+
28
+ @property
29
+ def serialization_type(self) -> str:
30
+ return f"[{self.element_type.serialization_type}]"
31
+
32
+ def type_annotation(self, **kwargs: Any) -> str:
33
+ if self.code_model.options["version_tolerant"] and self.element_type.is_xml:
34
+ # this means we're version tolerant XML, we just return the XML element
35
+ return self.element_type.type_annotation(**kwargs)
36
+ return f"List[{self.element_type.type_annotation(**kwargs)}]"
37
+
38
+ def description(self, *, is_operation_file: bool) -> str:
39
+ return "" if is_operation_file else self.yaml_data.get("description", "")
40
+
41
+ @property
42
+ def xml_serialization_ctxt(self) -> Optional[str]:
43
+ attrs_list = []
44
+ base_xml_map = super().xml_serialization_ctxt
45
+ if base_xml_map:
46
+ attrs_list.append(base_xml_map)
47
+
48
+ # Attribute at the list level
49
+ if self.xml_metadata.get("wrapped", False):
50
+ attrs_list.append("'wrapped': True")
51
+
52
+ # Attributes of the items
53
+ item_xml_metadata = self.element_type.xml_metadata
54
+ if item_xml_metadata.get("name"):
55
+ attrs_list.append(f"'itemsName': '{item_xml_metadata['name']}'")
56
+ if item_xml_metadata.get("prefix", False):
57
+ attrs_list.append(f"'itemsPrefix': '{item_xml_metadata['prefix']}'")
58
+ if item_xml_metadata.get("namespace", False):
59
+ attrs_list.append(f"'itemsNs': '{item_xml_metadata['namespace']}'")
60
+
61
+ return ", ".join(attrs_list)
62
+
63
+ def docstring_type(self, **kwargs: Any) -> str:
64
+ if (
65
+ self.code_model.options["version_tolerant"]
66
+ and self.element_type.xml_metadata
67
+ ):
68
+ # this means we're version tolerant XML, we just return the XML element
69
+ return self.element_type.docstring_type(**kwargs)
70
+ return f"list[{self.element_type.docstring_type(**kwargs)}]"
71
+
72
+ def docstring_text(self, **kwargs: Any) -> str:
73
+ if (
74
+ self.code_model.options["version_tolerant"]
75
+ and self.element_type.xml_metadata
76
+ ):
77
+ # this means we're version tolerant XML, we just return the XML element
78
+ return self.element_type.docstring_text(**kwargs)
79
+ return f"list of {self.element_type.docstring_text(**kwargs)}"
80
+
81
+ @property
82
+ def validation(self) -> Optional[Dict[str, Union[bool, int, str]]]:
83
+ validation: Dict[str, Union[bool, int, str]] = {}
84
+ if self.max_items:
85
+ validation["max_items"] = self.max_items
86
+ validation["min_items"] = self.min_items or 0
87
+ if self.min_items:
88
+ validation["min_items"] = self.min_items
89
+ if self.unique_items:
90
+ validation["unique"] = True
91
+ return validation or None
92
+
93
+ def get_json_template_representation(
94
+ self,
95
+ *,
96
+ optional: bool = True,
97
+ client_default_value_declaration: Optional[str] = None,
98
+ description: Optional[str] = None,
99
+ ) -> Any:
100
+ return [
101
+ self.element_type.get_json_template_representation(
102
+ optional=optional,
103
+ client_default_value_declaration=client_default_value_declaration,
104
+ description=description,
105
+ )
106
+ ]
107
+
108
+ def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
109
+ from .model_type import ModelType
110
+
111
+ if isinstance(self.element_type, ModelType):
112
+ is_polymorphic_subtype = (
113
+ self.element_type.discriminator_value
114
+ and not self.element_type.discriminated_subtypes
115
+ )
116
+ if (
117
+ self.element_type.name not in (m.name for m in polymorphic_subtypes)
118
+ and is_polymorphic_subtype
119
+ ):
120
+ polymorphic_subtypes.append(self.element_type)
121
+
122
+ @property
123
+ def instance_check_template(self) -> str:
124
+ return "isinstance({}, list)"
125
+
126
+ @classmethod
127
+ def from_yaml(
128
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
129
+ ) -> "ListType":
130
+ from . import build_type
131
+
132
+ return cls(
133
+ yaml_data=yaml_data,
134
+ code_model=code_model,
135
+ element_type=build_type(
136
+ yaml_data=yaml_data["elementType"], code_model=code_model
137
+ ),
138
+ )
139
+
140
+ def imports(self, **kwargs: Any) -> FileImport:
141
+ file_import = FileImport()
142
+ if not (
143
+ self.code_model.options["version_tolerant"] and self.element_type.is_xml
144
+ ):
145
+ file_import.add_submodule_import(
146
+ "typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL
147
+ )
148
+ file_import.merge(self.element_type.imports(**kwargs))
149
+ return file_import
@@ -3,182 +3,139 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- import logging
7
- from typing import Dict, List, Any, Optional, Set, cast
6
+ from typing import Any, Dict, Optional, List, TYPE_CHECKING, TypeVar, Union
8
7
  from .imports import FileImport
9
- from .operation import Operation
10
- from .parameter_list import ParameterList
11
- from .schema_response import SchemaResponse
8
+ from .operation import OperationBase, Operation
9
+ from .response import LROPagingResponse, LROResponse, Response
12
10
  from .imports import ImportType, TypingSection
13
- from .base_schema import BaseSchema
14
- from .schema_request import SchemaRequest
11
+ from .request_builder import RequestBuilder
12
+ from .parameter_list import ParameterList
13
+
14
+ if TYPE_CHECKING:
15
+ from .code_model import CodeModel
15
16
 
16
- _LOGGER = logging.getLogger(__name__)
17
+ LROResponseType = TypeVar(
18
+ "LROResponseType", bound=Union[LROResponse, LROPagingResponse]
19
+ )
17
20
 
18
21
 
19
- class LROOperation(Operation):
22
+ class LROOperationBase(OperationBase[LROResponseType]):
20
23
  def __init__(
21
24
  self,
22
- code_model,
23
25
  yaml_data: Dict[str, Any],
26
+ code_model: "CodeModel",
24
27
  name: str,
25
- description: str,
26
- api_versions: Set[str],
28
+ request_builder: RequestBuilder,
27
29
  parameters: ParameterList,
28
- multiple_content_type_parameters: ParameterList,
29
- schema_requests: List[SchemaRequest],
30
- summary: Optional[str] = None,
31
- responses: Optional[List[SchemaResponse]] = None,
32
- exceptions: Optional[List[SchemaResponse]] = None,
33
- want_description_docstring: bool = True,
34
- want_tracing: bool = True
30
+ responses: List[LROResponseType],
31
+ exceptions: List[Response],
32
+ *,
33
+ overloads: Optional[List[Operation]] = None,
34
+ public: bool = True,
35
+ want_tracing: bool = True,
36
+ abstract: bool = False,
35
37
  ) -> None:
36
- super(LROOperation, self).__init__(
37
- code_model,
38
- yaml_data,
39
- name,
40
- description,
41
- api_versions,
42
- parameters,
43
- multiple_content_type_parameters,
44
- schema_requests,
45
- summary,
46
- responses,
47
- exceptions,
48
- want_description_docstring,
49
- want_tracing,
38
+ super().__init__(
39
+ code_model=code_model,
40
+ yaml_data=yaml_data,
41
+ name=name,
42
+ request_builder=request_builder,
43
+ parameters=parameters,
44
+ responses=responses,
45
+ exceptions=exceptions,
46
+ overloads=overloads,
47
+ public=public,
48
+ want_tracing=want_tracing,
49
+ abstract=abstract,
50
50
  )
51
- self.lro_options = yaml_data.get("extensions", {}).get("x-ms-long-running-operation-options", {})
52
51
  self.name = "begin_" + self.name
52
+ self.lro_options: Dict[str, Any] = self.yaml_data.get("lroOptions", {})
53
+
54
+ @property
55
+ def operation_type(self) -> str:
56
+ return "lro"
53
57
 
54
58
  @property
55
- def lro_response(self) -> Optional[SchemaResponse]:
56
- if not self.responses:
57
- return None
58
- responses_with_bodies = [r for r in self.responses if r.has_body]
59
- num_response_schemas = {r.schema for r in responses_with_bodies}
59
+ def has_optional_return_type(self) -> bool:
60
+ return False
61
+
62
+ @property
63
+ def lro_response(self) -> Optional[LROResponseType]:
64
+ responses_with_bodies = [r for r in self.responses if r.type]
65
+ num_response_schemas = {
66
+ id(r.type.yaml_data) for r in responses_with_bodies if r.type
67
+ }
60
68
  response = None
61
69
  if len(num_response_schemas) > 1:
62
70
  # choose the response that has a status code of 200
63
- responses_with_200_status_codes = [
64
- r for r in responses_with_bodies if 200 in r.status_codes
65
- ]
66
71
  try:
67
- response = responses_with_200_status_codes[0]
68
- schema_types = {r.schema for r in responses_with_bodies}
69
- response_schema = cast(BaseSchema, response.schema).serialization_type
70
- _LOGGER.warning(
71
- "Multiple schema types in responses: %s. Choosing: %s", schema_types, response_schema
72
+ response = next(
73
+ r for r in responses_with_bodies if 200 in r.status_codes
72
74
  )
73
- except IndexError:
75
+ except StopIteration:
74
76
  raise ValueError(
75
- f"Your swagger is invalid because you have multiple response schemas for LRO" +
76
- f" method {self.python_name} and none of them have a 200 status code."
77
+ f"Your swagger is invalid because you have multiple response schemas for LRO"
78
+ + f" method {self.name} and none of them have a 200 status code."
77
79
  )
78
80
 
79
81
  elif num_response_schemas:
80
82
  response = responses_with_bodies[0]
81
83
  return response
82
84
 
85
+ def cls_type_annotation(self, *, async_mode: bool) -> str:
86
+ """We don't want the poller to show up in ClsType, so we call super() on resposne type annotation"""
87
+ return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
88
+
83
89
  @property
84
90
  def initial_operation(self) -> Operation:
85
- operation = Operation(
86
- self.code_model,
87
- yaml_data={},
91
+ """Initial operation that creates the first call for LRO polling"""
92
+ return Operation(
93
+ yaml_data=self.yaml_data,
94
+ code_model=self.code_model,
95
+ request_builder=self.code_model.lookup_request_builder(id(self.yaml_data)),
88
96
  name=self.name[5:] + "_initial",
89
- description="",
90
- api_versions=self.api_versions,
97
+ overloads=self.overloads,
91
98
  parameters=self.parameters,
92
- schema_requests=self.schema_requests,
93
- multiple_content_type_parameters=self.multiple_content_type_parameters,
94
- summary=self.summary,
95
- responses=self.responses,
96
- want_description_docstring=False,
99
+ responses=[
100
+ Response(r.yaml_data, self.code_model, headers=r.headers, type=r.type)
101
+ for r in self.responses
102
+ ],
103
+ exceptions=self.exceptions,
104
+ public=False,
97
105
  want_tracing=False,
98
106
  )
99
- operation.request_builder = self.request_builder
100
- return operation
101
-
102
- @property
103
- def has_optional_return_type(self) -> bool:
104
- """An LROOperation will never have an optional return type, we will always return a poller"""
105
- return False
106
-
107
- def _get_lro_extension(self, extension_base, async_mode, *, azure_arm=None):
108
- extension_name = extension_base + ("-async" if async_mode else "-sync")
109
- extension = self.yaml_data["extensions"][extension_name]
110
- arm_extension = None
111
- if azure_arm is not None:
112
- arm_extension = "azure-arm" if azure_arm else "data-plane"
113
- return extension[arm_extension] if arm_extension else extension
114
-
115
- def get_poller_path(self, async_mode: bool) -> str:
116
- return self._get_lro_extension("poller", async_mode)
117
107
 
118
108
  def get_poller(self, async_mode: bool) -> str:
119
- return self.get_poller_path(async_mode).split(".")[-1]
120
-
121
- def get_default_polling_method_path(self, async_mode: bool, azure_arm: bool) -> str:
122
- return self._get_lro_extension("default-polling-method", async_mode, azure_arm=azure_arm)
123
-
124
- def get_default_polling_method(self, async_mode: bool, azure_arm: bool) -> str:
125
- return self.get_default_polling_method_path(async_mode, azure_arm).split(".")[-1]
109
+ return self.responses[0].get_poller(async_mode)
126
110
 
127
- def get_default_no_polling_method_path(self, async_mode: bool) -> str:
128
- return self._get_lro_extension("default-no-polling-method", async_mode)
129
-
130
- def get_default_no_polling_method(self, async_mode: bool) -> str:
131
- return self.get_default_no_polling_method_path(async_mode).split(".")[-1]
132
-
133
- def get_base_polling_method_path(self, async_mode: bool) -> str:
134
- return self._get_lro_extension("base-polling-method", async_mode)
111
+ def get_polling_method(self, async_mode: bool) -> str:
112
+ return self.responses[0].get_polling_method(async_mode)
135
113
 
136
114
  def get_base_polling_method(self, async_mode: bool) -> str:
137
- return self.get_base_polling_method_path(async_mode).split(".")[-1]
138
-
139
- def imports_for_multiapi(self, async_mode: bool) -> FileImport:
140
- file_import = super().imports_for_multiapi(async_mode)
141
- poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
142
- poller = self.get_poller(async_mode)
143
- file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL)
144
- return file_import
115
+ return self.responses[0].get_base_polling_method(async_mode)
145
116
 
146
- def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
147
- file_import = self._imports_base(async_mode, is_python3_file)
148
- file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
149
-
150
- poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
151
- poller = self.get_poller(async_mode)
152
- file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE)
117
+ def get_base_polling_method_path(self, async_mode: bool) -> str:
118
+ return self.responses[0].get_base_polling_method_path(async_mode)
153
119
 
154
- default_polling_method_import_path = ".".join(
155
- self.get_default_polling_method_path(async_mode, self.code_model.options['azure_arm']).split(".")[:-1]
156
- )
157
- default_polling_method = self.get_default_polling_method(async_mode, self.code_model.options['azure_arm'])
158
- file_import.add_submodule_import(
159
- default_polling_method_import_path, default_polling_method, ImportType.AZURECORE
160
- )
120
+ def get_no_polling_method(self, async_mode: bool) -> str:
121
+ return self.responses[0].get_no_polling_method(async_mode)
161
122
 
162
- default_no_polling_method_import_path = ".".join(
163
- self.get_default_no_polling_method_path(async_mode).split(".")[:-1]
164
- )
165
- default_no_polling_method = self.get_default_no_polling_method(async_mode)
166
- file_import.add_submodule_import(
167
- default_no_polling_method_import_path, default_no_polling_method, ImportType.AZURECORE
168
- )
169
-
170
- base_polling_method_import_path = ".".join(
171
- self.get_base_polling_method_path(async_mode).split(".")[:-1]
172
- )
173
- base_polling_method = self.get_base_polling_method(async_mode)
174
- file_import.add_submodule_import(base_polling_method_import_path, base_polling_method, ImportType.AZURECORE)
175
- file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
123
+ def imports(
124
+ self, async_mode: bool, is_python3_file: bool, **kwargs: Any
125
+ ) -> FileImport:
126
+ file_import = super().imports(async_mode, is_python3_file, **kwargs)
176
127
  if async_mode:
177
- file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
178
- if self.code_model.options["tracing"] and self.want_tracing:
179
128
  file_import.add_submodule_import(
180
- f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
181
- f"distributed_trace{'_async' if async_mode else ''}",
129
+ f"azure.core.tracing.decorator_async",
130
+ f"distributed_trace_async",
182
131
  ImportType.AZURECORE,
183
132
  )
133
+ file_import.add_submodule_import(
134
+ "typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
135
+ )
136
+ file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
184
137
  return file_import
138
+
139
+
140
+ class LROOperation(LROOperationBase[LROResponse]):
141
+ ...