@azure-tools/typespec-python 0.28.0 → 0.30.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.
- package/dist/scripts/eng/format.d.ts +2 -0
- package/dist/scripts/eng/format.d.ts.map +1 -0
- package/dist/scripts/eng/format.js +4 -0
- package/dist/scripts/eng/format.js.map +1 -0
- package/dist/scripts/eng/lint.d.ts +5 -0
- package/dist/scripts/eng/lint.d.ts.map +1 -0
- package/dist/scripts/eng/lint.js +66 -0
- package/dist/scripts/eng/lint.js.map +1 -0
- package/dist/scripts/{regenerate.d.ts.map → eng/regenerate.d.ts.map} +1 -1
- package/dist/scripts/{regenerate.js → eng/regenerate.js} +33 -30
- package/dist/scripts/eng/regenerate.js.map +1 -0
- package/dist/scripts/eng/run-tests.d.ts +2 -0
- package/dist/scripts/eng/run-tests.d.ts.map +1 -0
- package/dist/scripts/eng/run-tests.js +71 -0
- package/dist/scripts/eng/run-tests.js.map +1 -0
- package/dist/scripts/eng/utils.d.ts +3 -0
- package/dist/scripts/eng/utils.d.ts.map +1 -0
- package/dist/scripts/eng/utils.js +39 -0
- package/dist/scripts/eng/utils.js.map +1 -0
- package/dist/scripts/run-python3.d.ts +2 -0
- package/dist/scripts/run-python3.d.ts.map +1 -0
- package/dist/scripts/run-python3.js +23 -0
- package/dist/scripts/run-python3.js.map +1 -0
- package/dist/scripts/system-requirements.d.ts +17 -0
- package/dist/scripts/system-requirements.d.ts.map +1 -0
- package/{scripts/system-requirements.cjs → dist/scripts/system-requirements.js} +80 -97
- package/dist/scripts/system-requirements.js.map +1 -0
- package/dist/src/code-model.d.ts.map +1 -1
- package/dist/src/code-model.js +23 -17
- package/dist/src/code-model.js.map +1 -1
- package/dist/src/emitter.d.ts.map +1 -1
- package/dist/src/emitter.js +14 -3
- package/dist/src/emitter.js.map +1 -1
- package/dist/src/external-process.js +1 -1
- package/dist/src/external-process.js.map +1 -1
- package/dist/src/http.js +34 -23
- package/dist/src/http.js.map +1 -1
- package/dist/src/lib.d.ts +1 -0
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +1 -0
- package/dist/src/lib.js.map +1 -1
- package/dist/src/types.d.ts +7 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +42 -7
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils.d.ts +3 -3
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +11 -13
- package/dist/src/utils.js.map +1 -1
- package/generator/pygen/black.py +2 -3
- package/generator/pygen/codegen/models/__init__.py +2 -0
- package/generator/pygen/codegen/models/code_model.py +2 -4
- package/generator/pygen/codegen/models/combined_type.py +1 -1
- package/generator/pygen/codegen/models/credential_types.py +7 -14
- package/generator/pygen/codegen/models/enum_type.py +1 -1
- package/generator/pygen/codegen/models/lro_operation.py +0 -1
- package/generator/pygen/codegen/models/lro_paging_operation.py +1 -1
- package/generator/pygen/codegen/models/model_type.py +6 -9
- package/generator/pygen/codegen/models/operation.py +13 -16
- package/generator/pygen/codegen/models/paging_operation.py +0 -1
- package/generator/pygen/codegen/models/parameter_list.py +2 -5
- package/generator/pygen/codegen/models/primitive_types.py +35 -3
- package/generator/pygen/codegen/models/property.py +1 -9
- package/generator/pygen/codegen/serializers/__init__.py +1 -1
- package/generator/pygen/codegen/serializers/builder_serializer.py +12 -13
- package/generator/pygen/codegen/serializers/general_serializer.py +2 -2
- package/generator/pygen/codegen/serializers/model_serializer.py +2 -0
- package/generator/pygen/codegen/serializers/sample_serializer.py +20 -15
- package/generator/pygen/codegen/templates/model_base.py.jinja2 +30 -18
- package/generator/pygen/codegen/templates/vendor.py.jinja2 +0 -2
- package/generator/pygen/m2r.py +1 -1
- package/generator/pygen/postprocess/__init__.py +2 -2
- package/generator/pygen/postprocess/venvtools.py +1 -3
- package/generator/pygen/preprocess/__init__.py +1 -1
- package/generator/pygen/utils.py +1 -3
- package/generator/setup.py +1 -1
- package/package.json +18 -25
- package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
- package/scripts/eng/format.ts +5 -0
- package/scripts/eng/lint.ts +75 -0
- package/scripts/eng/mypy.ini +38 -0
- package/scripts/eng/pylintrc +58 -0
- package/scripts/eng/pyrightconfig.json +6 -0
- package/scripts/{regenerate.ts → eng/regenerate.ts} +45 -33
- package/scripts/eng/run-tests.ts +80 -0
- package/scripts/eng/utils.ts +38 -0
- package/scripts/run-python3.ts +25 -0
- package/scripts/run_tsp.py +7 -5
- package/scripts/system-requirements.ts +253 -0
- package/dist/scripts/regenerate.js.map +0 -1
- package/scripts/run-python3.cjs +0 -22
- /package/dist/scripts/{regenerate.d.ts → eng/regenerate.d.ts} +0 -0
|
@@ -418,8 +418,19 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
|
|
|
418
418
|
file_import.merge(self.get_request_builder_import(self.request_builder, async_mode))
|
|
419
419
|
if self.overloads:
|
|
420
420
|
file_import.add_submodule_import("typing", "overload", ImportType.STDLIB)
|
|
421
|
-
if self.
|
|
422
|
-
|
|
421
|
+
if self.code_model.options["models_mode"] == "dpg":
|
|
422
|
+
if self.parameters.has_body:
|
|
423
|
+
if self.has_form_data_body:
|
|
424
|
+
file_import.add_submodule_import(relative_path, "_model_base", ImportType.LOCAL)
|
|
425
|
+
else:
|
|
426
|
+
file_import.add_submodule_import(
|
|
427
|
+
f"{relative_path}_model_base",
|
|
428
|
+
"SdkJSONEncoder",
|
|
429
|
+
ImportType.LOCAL,
|
|
430
|
+
)
|
|
431
|
+
file_import.add_import("json", ImportType.STDLIB)
|
|
432
|
+
if (self.default_error_deserialization or any(r.type for r in self.responses)) or self.non_default_errors:
|
|
433
|
+
file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL)
|
|
423
434
|
return file_import
|
|
424
435
|
|
|
425
436
|
def get_response_from_status(self, status_code: Optional[Union[str, int]]) -> ResponseType:
|
|
@@ -492,20 +503,6 @@ class Operation(OperationBase[Response]):
|
|
|
492
503
|
)
|
|
493
504
|
if self.has_response_body and not self.has_optional_return_type and not self.code_model.options["models_mode"]:
|
|
494
505
|
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
495
|
-
relative_path = "..." if async_mode else ".."
|
|
496
|
-
if self.code_model.options["models_mode"] == "dpg":
|
|
497
|
-
if self.parameters.has_body:
|
|
498
|
-
if self.has_form_data_body:
|
|
499
|
-
file_import.add_submodule_import(relative_path, "_model_base", ImportType.LOCAL)
|
|
500
|
-
else:
|
|
501
|
-
file_import.add_submodule_import(
|
|
502
|
-
f"{relative_path}_model_base",
|
|
503
|
-
"SdkJSONEncoder",
|
|
504
|
-
ImportType.LOCAL,
|
|
505
|
-
)
|
|
506
|
-
file_import.add_import("json", ImportType.STDLIB)
|
|
507
|
-
if self.default_error_deserialization or any(r.type for r in self.responses):
|
|
508
|
-
file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL)
|
|
509
506
|
|
|
510
507
|
return file_import
|
|
511
508
|
|
|
@@ -261,8 +261,7 @@ class _ParameterListBase(
|
|
|
261
261
|
)
|
|
262
262
|
|
|
263
263
|
|
|
264
|
-
class _ParameterList(_ParameterListBase[Parameter, BodyParameter]):
|
|
265
|
-
"""Base Parameter class for the two operation ParameterLists"""
|
|
264
|
+
class _ParameterList(_ParameterListBase[Parameter, BodyParameter]):
|
|
266
265
|
|
|
267
266
|
@staticmethod
|
|
268
267
|
def parameter_creator() -> Callable[[Dict[str, Any], "CodeModel"], Parameter]:
|
|
@@ -285,9 +284,7 @@ class ParameterList(_ParameterList):
|
|
|
285
284
|
"""ParameterList is the parameter list for Operation classes"""
|
|
286
285
|
|
|
287
286
|
|
|
288
|
-
class _RequestBuilderParameterList(
|
|
289
|
-
_ParameterListBase[RequestBuilderParameter, RequestBuilderBodyParameter] # pylint: disable=unsubscriptable-object
|
|
290
|
-
):
|
|
287
|
+
class _RequestBuilderParameterList(_ParameterListBase[RequestBuilderParameter, RequestBuilderBodyParameter]):
|
|
291
288
|
"""_RequestBuilderParameterList is base parameter list for RequestBuilder classes"""
|
|
292
289
|
|
|
293
290
|
@staticmethod
|
|
@@ -22,8 +22,8 @@ class RawString(object):
|
|
|
22
22
|
return "r'{}'".format(self.string.replace("'", "\\'"))
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
class PrimitiveType(BaseType):
|
|
26
|
-
def description(self, *, is_operation_file: bool) -> str:
|
|
25
|
+
class PrimitiveType(BaseType):
|
|
26
|
+
def description(self, *, is_operation_file: bool) -> str:
|
|
27
27
|
return ""
|
|
28
28
|
|
|
29
29
|
def type_annotation(self, **kwargs: Any) -> str:
|
|
@@ -188,7 +188,7 @@ class AnyObjectType(PrimitiveType):
|
|
|
188
188
|
return "JSON"
|
|
189
189
|
|
|
190
190
|
|
|
191
|
-
class NumberType(PrimitiveType):
|
|
191
|
+
class NumberType(PrimitiveType):
|
|
192
192
|
def __init__(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
|
|
193
193
|
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
194
194
|
self.precision: Optional[int] = yaml_data.get("precision")
|
|
@@ -233,6 +233,12 @@ class NumberType(PrimitiveType): # pylint: disable=abstract-method
|
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
class IntegerType(NumberType):
|
|
236
|
+
|
|
237
|
+
def __init__(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
|
|
238
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
239
|
+
if yaml_data.get("encode") == "string":
|
|
240
|
+
self.encode = "str"
|
|
241
|
+
|
|
236
242
|
@property
|
|
237
243
|
def serialization_type(self) -> str:
|
|
238
244
|
return "int"
|
|
@@ -624,3 +630,29 @@ class SdkCoreType(PrimitiveType):
|
|
|
624
630
|
@property
|
|
625
631
|
def serialization_type(self) -> str:
|
|
626
632
|
return self.name
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
class MultiPartFileType(PrimitiveType):
|
|
636
|
+
def __init__(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
|
|
637
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
638
|
+
self.name = "FileType"
|
|
639
|
+
|
|
640
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
641
|
+
return self.name
|
|
642
|
+
|
|
643
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
644
|
+
return f"~{self.code_model.namespace}._vendor.{self.name}"
|
|
645
|
+
|
|
646
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
647
|
+
file_import = super().imports(**kwargs)
|
|
648
|
+
relative_path = "..." if kwargs.get("async_mode") else ".."
|
|
649
|
+
file_import.add_submodule_import(f"{relative_path}_vendor", self.name, ImportType.LOCAL)
|
|
650
|
+
return file_import
|
|
651
|
+
|
|
652
|
+
@property
|
|
653
|
+
def default_template_representation_declaration(self) -> str:
|
|
654
|
+
return '"filetype"' if self.code_model.for_test else "filetype"
|
|
655
|
+
|
|
656
|
+
@property
|
|
657
|
+
def instance_check_template(self) -> str:
|
|
658
|
+
return f"isinstance({{}}, {self.name})"
|
|
@@ -97,12 +97,9 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
|
|
|
97
97
|
return self.is_discriminator and self.is_polymorphic and cast(ConstantType, self.type).value is None
|
|
98
98
|
|
|
99
99
|
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
100
|
-
types_type_annotation = self.type.type_annotation(is_operation_file=is_operation_file)
|
|
101
|
-
if self.is_multipart_file_input:
|
|
102
|
-
# we only support FileType or list of FileType
|
|
103
|
-
types_type_annotation = types_type_annotation.replace("bytes", "FileType")
|
|
104
100
|
if self.is_base_discriminator:
|
|
105
101
|
return "str"
|
|
102
|
+
types_type_annotation = self.type.type_annotation(is_operation_file=is_operation_file)
|
|
106
103
|
if self.optional and self.client_default_value is None:
|
|
107
104
|
return f"Optional[{types_type_annotation}]"
|
|
108
105
|
return types_type_annotation
|
|
@@ -115,9 +112,6 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
|
|
|
115
112
|
*,
|
|
116
113
|
client_default_value_declaration: Optional[str] = None,
|
|
117
114
|
) -> Any:
|
|
118
|
-
if self.is_multipart_file_input:
|
|
119
|
-
file_type_str = '"filetype"' if self.code_model.for_test else "filetype"
|
|
120
|
-
return f"[{file_type_str}]" if self.type.type == "list" else file_type_str
|
|
121
115
|
if self.client_default_value:
|
|
122
116
|
client_default_value_declaration = self.get_declaration(self.client_default_value)
|
|
123
117
|
# make sure there is no \n otherwise the json template will be invalid
|
|
@@ -156,8 +150,6 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
|
|
|
156
150
|
"rest_discriminator" if self.is_discriminator else "rest_field",
|
|
157
151
|
ImportType.LOCAL,
|
|
158
152
|
)
|
|
159
|
-
if self.is_multipart_file_input:
|
|
160
|
-
file_import.add_submodule_import(".._vendor", "FileType", ImportType.LOCAL)
|
|
161
153
|
return file_import
|
|
162
154
|
|
|
163
155
|
@classmethod
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=too-many-lines
|
|
1
|
+
# pylint: disable=too-many-lines
|
|
2
2
|
# -------------------------------------------------------------------------
|
|
3
3
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
4
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
@@ -23,7 +23,6 @@ from ..models import (
|
|
|
23
23
|
BinaryType,
|
|
24
24
|
BodyParameter,
|
|
25
25
|
ParameterMethodLocation,
|
|
26
|
-
RequestBuilderBodyParameter,
|
|
27
26
|
OverloadedRequestBuilder,
|
|
28
27
|
Property,
|
|
29
28
|
RequestBuilderType,
|
|
@@ -218,7 +217,7 @@ def is_json_model_type(parameters: ParameterListType) -> bool:
|
|
|
218
217
|
)
|
|
219
218
|
|
|
220
219
|
|
|
221
|
-
class _BuilderBaseSerializer(Generic[BuilderType]):
|
|
220
|
+
class _BuilderBaseSerializer(Generic[BuilderType]):
|
|
222
221
|
def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
|
|
223
222
|
self.code_model = code_model
|
|
224
223
|
self.async_mode = async_mode
|
|
@@ -391,7 +390,7 @@ class _BuilderBaseSerializer(Generic[BuilderType]): # pylint: disable=abstract-
|
|
|
391
390
|
############################## REQUEST BUILDERS ##############################
|
|
392
391
|
|
|
393
392
|
|
|
394
|
-
class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]):
|
|
393
|
+
class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]):
|
|
395
394
|
def description_and_summary(self, builder: RequestBuilderType) -> List[str]:
|
|
396
395
|
retval = super().description_and_summary(builder)
|
|
397
396
|
retval += [
|
|
@@ -517,7 +516,7 @@ class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]): # p
|
|
|
517
516
|
############################## NORMAL OPERATIONS ##############################
|
|
518
517
|
|
|
519
518
|
|
|
520
|
-
class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
519
|
+
class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
521
520
|
def description_and_summary(self, builder: OperationType) -> List[str]:
|
|
522
521
|
retval = super().description_and_summary(builder)
|
|
523
522
|
if builder.deprecated:
|
|
@@ -535,9 +534,9 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
535
534
|
return "response"
|
|
536
535
|
|
|
537
536
|
def example_template(self, builder: OperationType) -> List[str]:
|
|
537
|
+
if self.code_model.options["models_mode"] in ("msrest", "dpg"):
|
|
538
|
+
return []
|
|
538
539
|
retval = super().example_template(builder)
|
|
539
|
-
if self.code_model.options["models_mode"] == "msrest":
|
|
540
|
-
return retval
|
|
541
540
|
for response in builder.responses:
|
|
542
541
|
polymorphic_subtypes: List[ModelType] = []
|
|
543
542
|
if not response.type:
|
|
@@ -842,14 +841,14 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
842
841
|
elif request_builder.overloads:
|
|
843
842
|
seen_body_params = set()
|
|
844
843
|
for overload in request_builder.overloads:
|
|
845
|
-
body_param =
|
|
844
|
+
body_param = overload.parameters.body_parameter
|
|
846
845
|
if body_param.client_name in seen_body_params:
|
|
847
846
|
continue
|
|
848
847
|
seen_body_params.add(body_param.client_name)
|
|
849
848
|
|
|
850
849
|
retval.append(f" {body_param.client_name}={body_param.name_in_high_level_operation},")
|
|
851
850
|
elif request_builder.parameters.has_body:
|
|
852
|
-
body_param =
|
|
851
|
+
body_param = request_builder.parameters.body_parameter
|
|
853
852
|
retval.append(f" {body_param.client_name}={body_param.name_in_high_level_operation},")
|
|
854
853
|
retval.append(" headers=_headers,")
|
|
855
854
|
retval.append(" params=_params,")
|
|
@@ -871,7 +870,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
871
870
|
)
|
|
872
871
|
return retval
|
|
873
872
|
|
|
874
|
-
def _call_request_builder_helper(
|
|
873
|
+
def _call_request_builder_helper(
|
|
875
874
|
self,
|
|
876
875
|
builder: OperationType,
|
|
877
876
|
request_builder: RequestBuilderType,
|
|
@@ -1031,7 +1030,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
1031
1030
|
retval.append("deserialized = None")
|
|
1032
1031
|
if builder.any_response_has_headers:
|
|
1033
1032
|
retval.append("response_headers = {}")
|
|
1034
|
-
if builder.has_response_body or builder.any_response_has_headers:
|
|
1033
|
+
if builder.has_response_body or builder.any_response_has_headers: # pylint: disable=too-many-nested-blocks
|
|
1035
1034
|
if len(builder.responses) > 1:
|
|
1036
1035
|
status_codes, res_headers, res_deserialization = [], [], []
|
|
1037
1036
|
for status_code in builder.success_status_codes:
|
|
@@ -1173,7 +1172,7 @@ class OperationSerializer(_OperationSerializer[Operation]): ...
|
|
|
1173
1172
|
PagingOperationType = TypeVar("PagingOperationType", bound=Union[PagingOperation, LROPagingOperation])
|
|
1174
1173
|
|
|
1175
1174
|
|
|
1176
|
-
class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
1175
|
+
class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
1177
1176
|
def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
|
|
1178
1177
|
# for pylint reasons need to redefine init
|
|
1179
1178
|
# probably because inheritance is going too deep
|
|
@@ -1458,7 +1457,7 @@ class LROOperationSerializer(_LROOperationSerializer[LROOperation]): ...
|
|
|
1458
1457
|
class LROPagingOperationSerializer(
|
|
1459
1458
|
_LROOperationSerializer[LROPagingOperation],
|
|
1460
1459
|
_PagingOperationSerializer[LROPagingOperation],
|
|
1461
|
-
):
|
|
1460
|
+
):
|
|
1462
1461
|
@property
|
|
1463
1462
|
def _call_method(self) -> str:
|
|
1464
1463
|
return "await " if self.async_mode else ""
|
|
@@ -124,7 +124,6 @@ class GeneralSerializer(BaseSerializer):
|
|
|
124
124
|
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB)
|
|
125
125
|
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
|
|
126
126
|
file_import.add_submodule_import("typing", "Mapping", ImportType.STDLIB)
|
|
127
|
-
file_import.add_submodule_import("typing", "Sequence", ImportType.STDLIB)
|
|
128
127
|
file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB)
|
|
129
128
|
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB)
|
|
130
129
|
file_import.add_submodule_import("typing", "List", ImportType.STDLIB)
|
|
@@ -183,12 +182,13 @@ class GeneralSerializer(BaseSerializer):
|
|
|
183
182
|
def serialize_cross_language_definition_file(self) -> str:
|
|
184
183
|
cross_langauge_def_dict = {
|
|
185
184
|
f"{self.code_model.namespace}.models.{model.name}": model.cross_language_definition_id
|
|
186
|
-
for model in self.code_model.
|
|
185
|
+
for model in self.code_model.public_model_types
|
|
187
186
|
}
|
|
188
187
|
cross_langauge_def_dict.update(
|
|
189
188
|
{
|
|
190
189
|
f"{self.code_model.namespace}.models.{enum.name}": enum.cross_language_definition_id
|
|
191
190
|
for enum in self.code_model.enums
|
|
191
|
+
if not enum.internal
|
|
192
192
|
}
|
|
193
193
|
)
|
|
194
194
|
cross_langauge_def_dict.update(
|
|
@@ -194,6 +194,8 @@ class DpgModelSerializer(_ModelSerializer):
|
|
|
194
194
|
)
|
|
195
195
|
|
|
196
196
|
for model in self.code_model.model_types:
|
|
197
|
+
if model.base == "json":
|
|
198
|
+
continue
|
|
197
199
|
file_import.merge(model.imports(is_operation_file=False))
|
|
198
200
|
for prop in model.properties:
|
|
199
201
|
file_import.merge(prop.imports())
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# pylint: disable=too-many-lines
|
|
2
1
|
# -------------------------------------------------------------------------
|
|
3
2
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
@@ -22,7 +21,6 @@ from ..models import (
|
|
|
22
21
|
FileImport,
|
|
23
22
|
)
|
|
24
23
|
from .utils import get_namespace_config, get_namespace_from_package_name
|
|
25
|
-
from ...utils import to_snake_case
|
|
26
24
|
|
|
27
25
|
_LOGGER = logging.getLogger(__name__)
|
|
28
26
|
|
|
@@ -42,7 +40,7 @@ class SampleSerializer(BaseSerializer):
|
|
|
42
40
|
self.operation = operation
|
|
43
41
|
self.sample = sample
|
|
44
42
|
self.file_name = file_name
|
|
45
|
-
self.sample_params =
|
|
43
|
+
self.sample_params = sample.get("parameters", {})
|
|
46
44
|
|
|
47
45
|
def _imports(self) -> FileImportSerializer:
|
|
48
46
|
imports = FileImport(self.code_model)
|
|
@@ -66,8 +64,8 @@ class SampleSerializer(BaseSerializer):
|
|
|
66
64
|
"AzureKeyCredential",
|
|
67
65
|
ImportType.SDKCORE,
|
|
68
66
|
)
|
|
69
|
-
for param in self.operation.parameters.positional:
|
|
70
|
-
if not param.client_default_value and not param.optional and param.
|
|
67
|
+
for param in self.operation.parameters.positional + self.operation.parameters.keyword_only:
|
|
68
|
+
if not param.client_default_value and not param.optional and param.wire_name in self.sample_params:
|
|
71
69
|
imports.merge(param.type.imports_for_sample())
|
|
72
70
|
return FileImportSerializer(imports, True)
|
|
73
71
|
|
|
@@ -80,15 +78,19 @@ class SampleSerializer(BaseSerializer):
|
|
|
80
78
|
elif isinstance(credential_type, KeyCredentialType):
|
|
81
79
|
special_param.update({"credential": 'AzureKeyCredential(key=os.getenv("AZURE_KEY"))'})
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
p
|
|
81
|
+
params = [
|
|
82
|
+
p
|
|
83
|
+
for p in (
|
|
84
|
+
self.code_model.clients[0].parameters.positional + self.code_model.clients[0].parameters.keyword_only
|
|
85
|
+
)
|
|
86
|
+
if not (p.optional or p.client_default_value)
|
|
85
87
|
]
|
|
86
88
|
client_params = {
|
|
87
89
|
p.client_name: special_param.get(
|
|
88
90
|
p.client_name,
|
|
89
|
-
f'"{self.sample_params.get(p.
|
|
91
|
+
f'"{self.sample_params.get(p.wire_name) or p.client_name.upper()}"',
|
|
90
92
|
)
|
|
91
|
-
for p in
|
|
93
|
+
for p in params
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
return client_params
|
|
@@ -103,15 +105,18 @@ class SampleSerializer(BaseSerializer):
|
|
|
103
105
|
|
|
104
106
|
# prepare operation parameters
|
|
105
107
|
def _operation_params(self) -> Dict[str, Any]:
|
|
106
|
-
|
|
108
|
+
params = [
|
|
109
|
+
p
|
|
110
|
+
for p in (self.operation.parameters.positional + self.operation.parameters.keyword_only)
|
|
111
|
+
if not p.client_default_value
|
|
112
|
+
]
|
|
107
113
|
failure_info = "fail to find required param named {}"
|
|
108
114
|
operation_params = {}
|
|
109
|
-
for param in
|
|
110
|
-
name = param.client_name
|
|
111
|
-
param_value = self.sample_params.get(name)
|
|
115
|
+
for param in params:
|
|
112
116
|
if not param.optional:
|
|
117
|
+
param_value = self.sample_params.get(param.wire_name)
|
|
113
118
|
if not param_value:
|
|
114
|
-
raise Exception(failure_info.format(
|
|
119
|
+
raise Exception(failure_info.format(param.client_name)) # pylint: disable=broad-exception-raised
|
|
115
120
|
operation_params[param.client_name] = self.handle_param(param, param_value)
|
|
116
121
|
return operation_params
|
|
117
122
|
|
|
@@ -145,7 +150,7 @@ class SampleSerializer(BaseSerializer):
|
|
|
145
150
|
name = self.sample.get("x-ms-original-file", "")
|
|
146
151
|
if "specification" in name:
|
|
147
152
|
return "specification" + name.split("specification")[-1]
|
|
148
|
-
return ""
|
|
153
|
+
return name if self.code_model.options["from_typespec"] else ""
|
|
149
154
|
|
|
150
155
|
def serialize(self) -> str:
|
|
151
156
|
operation_result, return_var = self._operation_result()
|
|
@@ -454,6 +454,10 @@ def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-m
|
|
|
454
454
|
return float(o)
|
|
455
455
|
if isinstance(o, enum.Enum):
|
|
456
456
|
return o.value
|
|
457
|
+
if isinstance(o, int):
|
|
458
|
+
if format == "str":
|
|
459
|
+
return str(o)
|
|
460
|
+
return o
|
|
457
461
|
try:
|
|
458
462
|
# First try datetime.datetime
|
|
459
463
|
return _serialize_datetime(o, format)
|
|
@@ -489,6 +493,9 @@ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typin
|
|
|
489
493
|
|
|
490
494
|
class Model(_MyMutableMapping):
|
|
491
495
|
_is_model = True
|
|
496
|
+
# label whether current class's _attr_to_rest_field has been calculated
|
|
497
|
+
# could not see _attr_to_rest_field directly because subclass inherits it from parent class
|
|
498
|
+
_calculated: typing.Set[str] = set()
|
|
492
499
|
|
|
493
500
|
def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
|
|
494
501
|
class_name = self.__class__.__name__
|
|
@@ -521,24 +528,27 @@ class Model(_MyMutableMapping):
|
|
|
521
528
|
return Model(self.__dict__)
|
|
522
529
|
|
|
523
530
|
def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: disable=unused-argument
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
rf.
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
531
|
+
if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated:
|
|
532
|
+
# we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping',
|
|
533
|
+
# 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object'
|
|
534
|
+
mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order
|
|
535
|
+
attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
|
|
536
|
+
k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type")
|
|
537
|
+
}
|
|
538
|
+
annotations = {
|
|
539
|
+
k: v
|
|
540
|
+
for mro_class in mros
|
|
541
|
+
if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
|
|
542
|
+
for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
|
|
543
|
+
}
|
|
544
|
+
for attr, rf in attr_to_rest_field.items():
|
|
545
|
+
rf._module = cls.__module__
|
|
546
|
+
if not rf._type:
|
|
547
|
+
rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
|
|
548
|
+
if not rf._rest_name_input:
|
|
549
|
+
rf._rest_name_input = attr
|
|
550
|
+
cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
|
|
551
|
+
cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}")
|
|
542
552
|
|
|
543
553
|
return super().__new__(cls) # pylint: disable=no-value-for-parameter
|
|
544
554
|
|
|
@@ -669,6 +679,8 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
|
|
|
669
679
|
rf: typing.Optional["_RestField"] = None,
|
|
670
680
|
) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]:
|
|
671
681
|
if not annotation or annotation in [int, float]:
|
|
682
|
+
if annotation is int and rf and rf._format == "str":
|
|
683
|
+
return int
|
|
672
684
|
return None
|
|
673
685
|
|
|
674
686
|
# is it a type alias?
|
|
@@ -70,8 +70,6 @@ FileType = Union[
|
|
|
70
70
|
Tuple[Optional[str], FileContent, Optional[str]],
|
|
71
71
|
]
|
|
72
72
|
|
|
73
|
-
FilesType = Union[Mapping[str, FileType], Sequence[Tuple[str, FileType]]]
|
|
74
|
-
|
|
75
73
|
def serialize_multipart_data_entry(data_entry: Any) -> Any:
|
|
76
74
|
if isinstance(data_entry, (list, tuple, dict, Model)):
|
|
77
75
|
return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True)
|
package/generator/pygen/m2r.py
CHANGED
|
@@ -27,7 +27,7 @@ class GeneratorRenderer(m2r2.RestRenderer):
|
|
|
27
27
|
return f":code:`{html}`"
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
class M2R(YamlUpdatePlugin):
|
|
30
|
+
class M2R(YamlUpdatePlugin):
|
|
31
31
|
"""A plugin to convert any description and summary from MD to RST."""
|
|
32
32
|
|
|
33
33
|
def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
|
|
@@ -3,7 +3,7 @@
|
|
|
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 Tuple, Any
|
|
6
|
+
from typing import Tuple, Any
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
import os
|
|
9
9
|
import shutil
|
|
@@ -28,7 +28,7 @@ def format_file(file: Path, file_content: str) -> str:
|
|
|
28
28
|
return file_content
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class PostProcessPlugin(Plugin):
|
|
31
|
+
class PostProcessPlugin(Plugin):
|
|
32
32
|
def __init__(self, **kwargs: Any):
|
|
33
33
|
super().__init__(**kwargs)
|
|
34
34
|
output_folder_uri = self.options["outputFolderUri"]
|
|
@@ -52,9 +52,7 @@ def create(
|
|
|
52
52
|
return builder.context
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def python_run(
|
|
56
|
-
venv_context, module, command, directory=_ROOT_DIR
|
|
57
|
-
) -> Optional[str]:
|
|
55
|
+
def python_run(venv_context, module, command, directory=_ROOT_DIR) -> Optional[str]:
|
|
58
56
|
try:
|
|
59
57
|
cmd_line = [
|
|
60
58
|
venv_context.env_exe,
|
|
@@ -163,7 +163,7 @@ def has_multi_part_content_type(yaml_data: Dict[str, Any]) -> bool:
|
|
|
163
163
|
return any(ct for ct in yaml_data.get("contentTypes", []) if ct == "multipart/form-data")
|
|
164
164
|
|
|
165
165
|
|
|
166
|
-
class PreProcessPlugin(YamlUpdatePlugin):
|
|
166
|
+
class PreProcessPlugin(YamlUpdatePlugin):
|
|
167
167
|
"""Add Python naming information."""
|
|
168
168
|
|
|
169
169
|
@property
|
package/generator/pygen/utils.py
CHANGED
|
@@ -82,9 +82,7 @@ def parse_args(
|
|
|
82
82
|
return value
|
|
83
83
|
|
|
84
84
|
unknown_args_ret = {
|
|
85
|
-
ua.strip("--").split("=", maxsplit=1)[0]: _get_value(
|
|
86
|
-
ua.strip("--").split("=", maxsplit=1)[1] # pylint: disable=bad-str-strip-call
|
|
87
|
-
)
|
|
85
|
+
ua.strip("--").split("=", maxsplit=1)[0]: _get_value(ua.strip("--").split("=", maxsplit=1)[1])
|
|
88
86
|
for ua in unknown_args
|
|
89
87
|
}
|
|
90
88
|
return args, unknown_args_ret
|
package/generator/setup.py
CHANGED
|
@@ -15,7 +15,7 @@ from setuptools import setup, find_packages
|
|
|
15
15
|
|
|
16
16
|
# Version extraction inspired from 'requests'
|
|
17
17
|
with open(os.path.join("pygen", "_version.py"), "r") as fd:
|
|
18
|
-
version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1)
|
|
18
|
+
version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) # type: ignore
|
|
19
19
|
|
|
20
20
|
if not version:
|
|
21
21
|
raise RuntimeError("Cannot find version information")
|