@typespec/http-client-python 0.29.2 → 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/emitter/http.d.ts.map +1 -1
- package/dist/emitter/http.js +3 -2
- package/dist/emitter/http.js.map +1 -1
- package/dist/emitter/types.d.ts.map +1 -1
- package/dist/emitter/types.js +3 -2
- package/dist/emitter/types.js.map +1 -1
- package/dist/emitter/utils.d.ts +5 -0
- package/dist/emitter/utils.d.ts.map +1 -1
- package/dist/emitter/utils.js +6 -2
- package/dist/emitter/utils.js.map +1 -1
- package/emitter/src/http.ts +3 -1
- package/emitter/src/types.ts +3 -1
- package/emitter/src/utils.ts +8 -2
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/dev_requirements.txt +2 -2
- package/eng/scripts/ci/run_pylint.py +9 -0
- package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
- package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
- package/eng/scripts/setup/package_manager.py +13 -3
- package/generator/build/lib/pygen/codegen/models/operation.py +6 -1
- package/generator/build/lib/pygen/codegen/models/parameter.py +1 -0
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +3 -2
- package/generator/build/lib/pygen/preprocess/__init__.py +17 -5
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/codegen/models/operation.py +6 -1
- package/generator/pygen/codegen/models/parameter.py +1 -0
- package/generator/pygen/codegen/serializers/builder_serializer.py +3 -2
- package/generator/pygen/preprocess/__init__.py +17 -5
- package/generator/pygen.egg-info/PKG-INFO +1 -1
- package/generator/pygen.egg-info/requires.txt +1 -1
- package/generator/setup.py +1 -1
- package/package.json +4 -4
|
@@ -47,6 +47,15 @@ def _single_dir_pylint(mod):
|
|
|
47
47
|
]
|
|
48
48
|
if is_azure:
|
|
49
49
|
pylint_args.append("--load-plugins=pylint_guidelines_checker")
|
|
50
|
+
# Per-package suppressions for generated code where pylint's ignore-paths
|
|
51
|
+
# is not honored (pylint 4.x + recursive + plugin). Keep the scope as
|
|
52
|
+
# narrow as possible: only this package, only the offending check.
|
|
53
|
+
per_package_disables = {
|
|
54
|
+
"azure-client-generator-core-exact-name": ["client-incorrect-naming-convention"],
|
|
55
|
+
}
|
|
56
|
+
extra_disables = per_package_disables.get(mod.name)
|
|
57
|
+
if extra_disables:
|
|
58
|
+
pylint_args.append("--disable={}".format(",".join(extra_disables)))
|
|
50
59
|
pylint_args.append(str(inner_class.absolute()))
|
|
51
60
|
try:
|
|
52
61
|
check_call(pylint_args)
|
|
Binary file
|
|
Binary file
|
|
@@ -100,10 +100,20 @@ def install_packages(packages: list, venv_context=None, package_manager: str = N
|
|
|
100
100
|
|
|
101
101
|
try:
|
|
102
102
|
if cwd:
|
|
103
|
-
subprocess.
|
|
103
|
+
result = subprocess.run(install_cmd + packages, cwd=cwd, capture_output=True, text=True)
|
|
104
104
|
else:
|
|
105
|
-
subprocess.
|
|
106
|
-
|
|
105
|
+
result = subprocess.run(install_cmd + packages, capture_output=True, text=True)
|
|
106
|
+
if result.returncode != 0:
|
|
107
|
+
error_output = (result.stderr or "") + (result.stdout or "")
|
|
108
|
+
error_msg = f"Failed to install packages with {package_manager}: command exited with code {result.returncode}\n{error_output}"
|
|
109
|
+
if "401" in error_output or "Unauthorized" in error_output:
|
|
110
|
+
error_msg += (
|
|
111
|
+
"\n\nReceived a 401 Unauthorized error from the Azure feed. "
|
|
112
|
+
"A pip dependency may not yet be cached. To fix this, follow the authentication steps at: "
|
|
113
|
+
"https://github.com/Azure/azure-sdk-for-python/blob/main/CONTRIBUTING.md#authentication-for-upstream-pull-through"
|
|
114
|
+
)
|
|
115
|
+
raise RuntimeError(error_msg)
|
|
116
|
+
except OSError as e:
|
|
107
117
|
raise RuntimeError(f"Failed to install packages with {package_manager}: {e}")
|
|
108
118
|
|
|
109
119
|
|
|
@@ -91,11 +91,16 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
|
|
|
91
91
|
self.has_etag: bool = self.yaml_data.get("hasEtag", False)
|
|
92
92
|
self.cross_language_definition_id: Optional[str] = self.yaml_data.get("crossLanguageDefinitionId")
|
|
93
93
|
|
|
94
|
+
@property
|
|
95
|
+
def exact_name_params(self) -> set[str]:
|
|
96
|
+
"""Return the set of client names for parameters with isExactName."""
|
|
97
|
+
return {p.client_name for p in self.parameters.method if p.is_exact_name}
|
|
98
|
+
|
|
94
99
|
@property
|
|
95
100
|
def stream_value(self) -> Union[str, bool]:
|
|
96
101
|
return (
|
|
97
102
|
f'kwargs.pop("stream", {self.has_stream_response})'
|
|
98
|
-
if self.expose_stream_keyword and self.has_response_body
|
|
103
|
+
if self.expose_stream_keyword and self.has_response_body and "stream" not in self.exact_name_params
|
|
99
104
|
else self.has_stream_response
|
|
100
105
|
)
|
|
101
106
|
|
|
@@ -87,6 +87,7 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
|
|
|
87
87
|
self.default_to_unset_sentinel: bool = self.yaml_data.get("defaultToUnsetSentinel", False)
|
|
88
88
|
self.hide_in_method: bool = self.yaml_data.get("hideInMethod", False)
|
|
89
89
|
self.is_continuation_token: bool = bool(self.yaml_data.get("isContinuationToken"))
|
|
90
|
+
self.is_exact_name: bool = self.yaml_data.get("isExactName", False)
|
|
90
91
|
|
|
91
92
|
def get_declaration(self, value: Any = None) -> Any:
|
|
92
93
|
return self.type.get_declaration(value)
|
|
@@ -627,7 +627,8 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
627
627
|
return ""
|
|
628
628
|
|
|
629
629
|
def pop_kwargs_from_signature(self, builder: OperationType) -> list[str]:
|
|
630
|
-
|
|
630
|
+
exact_names = builder.exact_name_params
|
|
631
|
+
kwargs_to_pop = [k for k in builder.parameters.kwargs_to_pop if k.client_name not in exact_names]
|
|
631
632
|
kwargs = self.parameter_serializer.pop_kwargs_from_signature(
|
|
632
633
|
kwargs_to_pop,
|
|
633
634
|
check_kwarg_dict=True,
|
|
@@ -645,7 +646,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
645
646
|
body_parameter=builder.parameters.body_parameter if builder.parameters.has_body else None,
|
|
646
647
|
)
|
|
647
648
|
for p in builder.parameters.parameters:
|
|
648
|
-
if p.hide_in_operation_signature and not p.is_continuation_token:
|
|
649
|
+
if p.hide_in_operation_signature and not p.is_continuation_token and p.client_name not in exact_names:
|
|
649
650
|
kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
|
|
650
651
|
cls_annotation = builder.cls_type_annotation(
|
|
651
652
|
async_mode=self.async_mode, serialize_namespace=self.serialize_namespace
|
|
@@ -264,9 +264,10 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
264
264
|
for type in yaml_data:
|
|
265
265
|
for property in type.get("properties", []):
|
|
266
266
|
property["description"] = update_description(property.get("description", ""))
|
|
267
|
-
property
|
|
268
|
-
property["clientName"].
|
|
269
|
-
|
|
267
|
+
if not property.get("isExactName", False):
|
|
268
|
+
property["clientName"] = self.pad_reserved_words(
|
|
269
|
+
property["clientName"].lower(), PadType.PROPERTY, property
|
|
270
|
+
)
|
|
270
271
|
add_redefined_builtin_info(property["clientName"], property)
|
|
271
272
|
if type.get("name"):
|
|
272
273
|
pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
|
|
@@ -362,14 +363,25 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
362
363
|
|
|
363
364
|
def update_parameter(self, yaml_data: dict[str, Any]) -> None:
|
|
364
365
|
yaml_data["description"] = update_description(yaml_data.get("description", ""))
|
|
365
|
-
if not (
|
|
366
|
+
if not yaml_data.get("isExactName", False) and not (
|
|
367
|
+
yaml_data["location"] == "header" and yaml_data["clientName"] in ("content_type", "accept")
|
|
368
|
+
):
|
|
366
369
|
yaml_data["clientName"] = self.pad_reserved_words(
|
|
367
370
|
yaml_data["clientName"].lower(), PadType.PARAMETER, yaml_data
|
|
368
371
|
)
|
|
369
372
|
if yaml_data.get("propertyToParameterName"):
|
|
370
373
|
# need to create a new one with padded values (but NOT keys, since keys are wire names)
|
|
374
|
+
# build a lookup of exact-name properties from the body type's properties
|
|
375
|
+
exact_name_props = set()
|
|
376
|
+
for prop in yaml_data.get("type", {}).get("properties", []):
|
|
377
|
+
if prop.get("isExactName", False):
|
|
378
|
+
exact_name_props.add(prop.get("wireName", ""))
|
|
371
379
|
yaml_data["propertyToParameterName"] = {
|
|
372
|
-
prop:
|
|
380
|
+
prop: (
|
|
381
|
+
param_name
|
|
382
|
+
if prop in exact_name_props
|
|
383
|
+
else self.pad_reserved_words(param_name, PadType.PARAMETER, yaml_data).lower()
|
|
384
|
+
)
|
|
373
385
|
for prop, param_name in yaml_data["propertyToParameterName"].items()
|
|
374
386
|
}
|
|
375
387
|
wire_name_lower = (yaml_data.get("wireName") or "").lower()
|
|
Binary file
|
|
@@ -91,11 +91,16 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
|
|
|
91
91
|
self.has_etag: bool = self.yaml_data.get("hasEtag", False)
|
|
92
92
|
self.cross_language_definition_id: Optional[str] = self.yaml_data.get("crossLanguageDefinitionId")
|
|
93
93
|
|
|
94
|
+
@property
|
|
95
|
+
def exact_name_params(self) -> set[str]:
|
|
96
|
+
"""Return the set of client names for parameters with isExactName."""
|
|
97
|
+
return {p.client_name for p in self.parameters.method if p.is_exact_name}
|
|
98
|
+
|
|
94
99
|
@property
|
|
95
100
|
def stream_value(self) -> Union[str, bool]:
|
|
96
101
|
return (
|
|
97
102
|
f'kwargs.pop("stream", {self.has_stream_response})'
|
|
98
|
-
if self.expose_stream_keyword and self.has_response_body
|
|
103
|
+
if self.expose_stream_keyword and self.has_response_body and "stream" not in self.exact_name_params
|
|
99
104
|
else self.has_stream_response
|
|
100
105
|
)
|
|
101
106
|
|
|
@@ -87,6 +87,7 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
|
|
|
87
87
|
self.default_to_unset_sentinel: bool = self.yaml_data.get("defaultToUnsetSentinel", False)
|
|
88
88
|
self.hide_in_method: bool = self.yaml_data.get("hideInMethod", False)
|
|
89
89
|
self.is_continuation_token: bool = bool(self.yaml_data.get("isContinuationToken"))
|
|
90
|
+
self.is_exact_name: bool = self.yaml_data.get("isExactName", False)
|
|
90
91
|
|
|
91
92
|
def get_declaration(self, value: Any = None) -> Any:
|
|
92
93
|
return self.type.get_declaration(value)
|
|
@@ -627,7 +627,8 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
627
627
|
return ""
|
|
628
628
|
|
|
629
629
|
def pop_kwargs_from_signature(self, builder: OperationType) -> list[str]:
|
|
630
|
-
|
|
630
|
+
exact_names = builder.exact_name_params
|
|
631
|
+
kwargs_to_pop = [k for k in builder.parameters.kwargs_to_pop if k.client_name not in exact_names]
|
|
631
632
|
kwargs = self.parameter_serializer.pop_kwargs_from_signature(
|
|
632
633
|
kwargs_to_pop,
|
|
633
634
|
check_kwarg_dict=True,
|
|
@@ -645,7 +646,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
645
646
|
body_parameter=builder.parameters.body_parameter if builder.parameters.has_body else None,
|
|
646
647
|
)
|
|
647
648
|
for p in builder.parameters.parameters:
|
|
648
|
-
if p.hide_in_operation_signature and not p.is_continuation_token:
|
|
649
|
+
if p.hide_in_operation_signature and not p.is_continuation_token and p.client_name not in exact_names:
|
|
649
650
|
kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
|
|
650
651
|
cls_annotation = builder.cls_type_annotation(
|
|
651
652
|
async_mode=self.async_mode, serialize_namespace=self.serialize_namespace
|
|
@@ -264,9 +264,10 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
264
264
|
for type in yaml_data:
|
|
265
265
|
for property in type.get("properties", []):
|
|
266
266
|
property["description"] = update_description(property.get("description", ""))
|
|
267
|
-
property
|
|
268
|
-
property["clientName"].
|
|
269
|
-
|
|
267
|
+
if not property.get("isExactName", False):
|
|
268
|
+
property["clientName"] = self.pad_reserved_words(
|
|
269
|
+
property["clientName"].lower(), PadType.PROPERTY, property
|
|
270
|
+
)
|
|
270
271
|
add_redefined_builtin_info(property["clientName"], property)
|
|
271
272
|
if type.get("name"):
|
|
272
273
|
pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
|
|
@@ -362,14 +363,25 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
362
363
|
|
|
363
364
|
def update_parameter(self, yaml_data: dict[str, Any]) -> None:
|
|
364
365
|
yaml_data["description"] = update_description(yaml_data.get("description", ""))
|
|
365
|
-
if not (
|
|
366
|
+
if not yaml_data.get("isExactName", False) and not (
|
|
367
|
+
yaml_data["location"] == "header" and yaml_data["clientName"] in ("content_type", "accept")
|
|
368
|
+
):
|
|
366
369
|
yaml_data["clientName"] = self.pad_reserved_words(
|
|
367
370
|
yaml_data["clientName"].lower(), PadType.PARAMETER, yaml_data
|
|
368
371
|
)
|
|
369
372
|
if yaml_data.get("propertyToParameterName"):
|
|
370
373
|
# need to create a new one with padded values (but NOT keys, since keys are wire names)
|
|
374
|
+
# build a lookup of exact-name properties from the body type's properties
|
|
375
|
+
exact_name_props = set()
|
|
376
|
+
for prop in yaml_data.get("type", {}).get("properties", []):
|
|
377
|
+
if prop.get("isExactName", False):
|
|
378
|
+
exact_name_props.add(prop.get("wireName", ""))
|
|
371
379
|
yaml_data["propertyToParameterName"] = {
|
|
372
|
-
prop:
|
|
380
|
+
prop: (
|
|
381
|
+
param_name
|
|
382
|
+
if prop in exact_name_props
|
|
383
|
+
else self.pad_reserved_words(param_name, PadType.PARAMETER, yaml_data).lower()
|
|
384
|
+
)
|
|
373
385
|
for prop, param_name in yaml_data["propertyToParameterName"].items()
|
|
374
386
|
}
|
|
375
387
|
wire_name_lower = (yaml_data.get("wireName") or "").lower()
|
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: black==
|
|
18
|
+
Requires-Dist: black==24.4.0
|
|
19
19
|
Requires-Dist: docutils>=0.20.1
|
|
20
20
|
Requires-Dist: Jinja2==3.1.6
|
|
21
21
|
Requires-Dist: PyYAML==6.0.1
|
package/generator/setup.py
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typespec/http-client-python",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"author": "Microsoft Corporation",
|
|
5
5
|
"description": "TypeSpec emitter for Python SDKs",
|
|
6
6
|
"homepage": "https://typespec.io",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@azure-tools/typespec-azure-core": ">=0.68.0 <1.0.0",
|
|
65
65
|
"@azure-tools/typespec-azure-resource-manager": ">=0.68.0 <1.0.0",
|
|
66
66
|
"@azure-tools/typespec-azure-rulesets": ">=0.68.0 <1.0.0",
|
|
67
|
-
"@azure-tools/typespec-client-generator-core": ">=0.68.
|
|
67
|
+
"@azure-tools/typespec-client-generator-core": ">=0.68.2 <1.0.0",
|
|
68
68
|
"@typespec/compiler": "^1.12.0",
|
|
69
69
|
"@typespec/http": "^1.12.0",
|
|
70
70
|
"@typespec/openapi": "^1.12.0",
|
|
@@ -102,8 +102,8 @@
|
|
|
102
102
|
"@azure-tools/typespec-azure-core": "~0.68.0",
|
|
103
103
|
"@azure-tools/typespec-azure-resource-manager": "~0.68.0",
|
|
104
104
|
"@azure-tools/typespec-azure-rulesets": "~0.68.0",
|
|
105
|
-
"@azure-tools/typespec-client-generator-core": "~0.68.
|
|
106
|
-
"@azure-tools/azure-http-specs": "0.1.0-alpha.
|
|
105
|
+
"@azure-tools/typespec-client-generator-core": "~0.68.2",
|
|
106
|
+
"@azure-tools/azure-http-specs": "0.1.0-alpha.41-dev.1",
|
|
107
107
|
"@typespec/compiler": "^1.12.0",
|
|
108
108
|
"@typespec/http": "^1.12.0",
|
|
109
109
|
"@typespec/openapi": "^1.12.0",
|