@typespec/http-client-python 0.28.3 → 0.29.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/code-model.d.ts.map +1 -1
- package/dist/emitter/code-model.js +1 -0
- package/dist/emitter/code-model.js.map +1 -1
- package/dist/emitter/constants.d.ts +6 -0
- package/dist/emitter/constants.d.ts.map +1 -0
- package/dist/emitter/constants.js +27 -0
- package/dist/emitter/constants.js.map +1 -0
- package/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +169 -94
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/http.d.ts.map +1 -1
- package/dist/emitter/http.js +33 -1
- package/dist/emitter/http.js.map +1 -1
- package/dist/emitter/lib.d.ts +33 -2
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +17 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/run-python3.js +1 -1
- package/dist/emitter/run-python3.js.map +1 -1
- package/dist/emitter/types.d.ts.map +1 -1
- package/dist/emitter/types.js +31 -5
- package/dist/emitter/types.js.map +1 -1
- package/emitter/src/code-model.ts +1 -0
- package/emitter/src/constants.ts +27 -0
- package/emitter/src/emitter.ts +216 -96
- package/emitter/src/http.ts +29 -1
- package/emitter/src/lib.ts +20 -0
- package/emitter/src/run-python3.ts +1 -1
- package/emitter/src/types.ts +35 -5
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/emitter/test/utils.test.ts +3 -0
- package/emitter/tsconfig.build.json +2 -1
- package/emitter/tsconfig.json +2 -1
- package/eng/scripts/ci/config/eslint-ci.config.mjs +10 -0
- package/eng/scripts/ci/config/mypy.ini +1 -1
- package/eng/scripts/ci/config/pylintrc +1 -1
- package/eng/scripts/ci/config/pyrightconfig.json +1 -1
- package/eng/scripts/ci/dev_requirements.txt +1 -1
- package/eng/scripts/ci/lint.ts +11 -4
- package/eng/scripts/ci/regenerate-common.ts +407 -136
- package/eng/scripts/ci/regenerate.ts +103 -194
- package/eng/scripts/ci/run-tests.ts +153 -48
- package/eng/scripts/ci/run_apiview.py +22 -16
- package/eng/scripts/ci/run_mypy.py +28 -18
- package/eng/scripts/ci/run_pylint.py +23 -16
- package/eng/scripts/ci/run_pyright.py +5 -2
- package/eng/scripts/ci/run_sphinx_build.py +24 -9
- package/eng/scripts/ci/util.py +61 -25
- 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/build_pygen_wheel.py +3 -3
- package/eng/scripts/setup/install.py +3 -3
- package/eng/scripts/setup/install.ts +1 -1
- package/eng/scripts/setup/prepare.py +2 -2
- package/eng/scripts/setup/run-python3.ts +1 -1
- package/eng/scripts/setup/run_batch.py +197 -0
- package/eng/scripts/setup/venvtools.py +0 -1
- package/generator/build/lib/pygen/__init__.py +1 -3
- package/generator/build/lib/pygen/codegen/__init__.py +0 -1
- package/generator/build/lib/pygen/codegen/models/base.py +0 -1
- package/generator/build/lib/pygen/codegen/models/client.py +2 -1
- package/generator/build/lib/pygen/codegen/models/code_model.py +1 -0
- package/generator/build/lib/pygen/codegen/models/enum_type.py +0 -1
- package/generator/build/lib/pygen/codegen/models/model_type.py +1 -7
- package/generator/build/lib/pygen/codegen/models/parameter.py +16 -14
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +27 -12
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +12 -3
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +6 -2
- package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +17 -4
- package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +17 -11
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +19 -7
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +11 -3
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +5 -1
- package/generator/build/lib/pygen/preprocess/__init__.py +37 -30
- package/generator/component-detection-pip-report.json +7 -7
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/__init__.py +1 -3
- package/generator/pygen/codegen/__init__.py +0 -1
- package/generator/pygen/codegen/models/base.py +0 -1
- package/generator/pygen/codegen/models/client.py +2 -1
- package/generator/pygen/codegen/models/code_model.py +1 -0
- package/generator/pygen/codegen/models/enum_type.py +0 -1
- package/generator/pygen/codegen/models/model_type.py +1 -7
- package/generator/pygen/codegen/models/parameter.py +16 -14
- package/generator/pygen/codegen/serializers/__init__.py +27 -12
- package/generator/pygen/codegen/serializers/builder_serializer.py +12 -3
- package/generator/pygen/codegen/serializers/general_serializer.py +6 -2
- package/generator/pygen/codegen/serializers/import_serializer.py +17 -4
- package/generator/pygen/codegen/serializers/parameter_serializer.py +17 -11
- package/generator/pygen/codegen/templates/model_base.py.jinja2 +19 -7
- package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +11 -3
- package/generator/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +1 -1
- package/generator/pygen/codegen/templates/serialization.py.jinja2 +5 -1
- package/generator/pygen/preprocess/__init__.py +37 -30
- package/generator/pygen.egg-info/PKG-INFO +1 -2
- package/generator/pygen.egg-info/requires.txt +1 -1
- package/generator/setup.py +1 -2
- package/package.json +24 -9
|
@@ -16,7 +16,6 @@ from .utils import TYPESPEC_PACKAGE_MODE, VALID_PACKAGE_MODE
|
|
|
16
16
|
|
|
17
17
|
from ._version import VERSION
|
|
18
18
|
|
|
19
|
-
|
|
20
19
|
__version__ = VERSION
|
|
21
20
|
_LOGGER = logging.getLogger(__name__)
|
|
22
21
|
|
|
@@ -237,8 +236,7 @@ class ReaderAndWriter:
|
|
|
237
236
|
def write_file(self, filename: Union[str, Path], file_content: str) -> None:
|
|
238
237
|
"""Directly writing to disk"""
|
|
239
238
|
file_folder = Path(filename).parent
|
|
240
|
-
|
|
241
|
-
Path.mkdir(self.output_folder / file_folder, parents=True)
|
|
239
|
+
Path.mkdir(self.output_folder / file_folder, parents=True, exist_ok=True)
|
|
242
240
|
with open(self.output_folder / Path(filename), "w", encoding="utf-8") as fd:
|
|
243
241
|
fd.write(file_content)
|
|
244
242
|
|
|
@@ -291,11 +291,12 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
291
291
|
ImportType.SDKCORE,
|
|
292
292
|
)
|
|
293
293
|
|
|
294
|
-
# import for "Self"
|
|
294
|
+
# import for "Self" (typing.Self available from Python 3.11+)
|
|
295
295
|
file_import.add_submodule_import(
|
|
296
296
|
"typing_extensions",
|
|
297
297
|
"Self",
|
|
298
298
|
ImportType.STDLIB,
|
|
299
|
+
version_modules=(((3, 11), "typing", None),),
|
|
299
300
|
)
|
|
300
301
|
if self.need_cloud_setting:
|
|
301
302
|
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
@@ -95,6 +95,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
95
95
|
t for t in self.types_map.values() if isinstance(t, CombinedType) and t.name
|
|
96
96
|
]
|
|
97
97
|
self.cross_language_package_id = self.yaml_data.get("crossLanguagePackageId")
|
|
98
|
+
self.cross_language_version = self.yaml_data.get("crossLanguageVersion")
|
|
98
99
|
self.for_test: bool = False
|
|
99
100
|
# key is typespec namespace, value is models/clients/opeartion_groups/enums cache in the namespace
|
|
100
101
|
self._client_namespace_types: dict[str, ClientNamespaceType] = {}
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from collections import OrderedDict
|
|
8
|
-
from typing import Any, Optional, TYPE_CHECKING, cast
|
|
9
|
-
import sys
|
|
8
|
+
from typing import Any, Literal, Optional, TYPE_CHECKING, cast
|
|
10
9
|
from .utils import add_to_pylint_disable, NamespaceType, LOCALS_LENGTH_LIMIT
|
|
11
10
|
from .base import BaseType
|
|
12
11
|
from .constant_type import ConstantType
|
|
@@ -14,11 +13,6 @@ from .property import Property
|
|
|
14
13
|
from .imports import FileImport, ImportType, TypingSection
|
|
15
14
|
from ...utils import NAME_LENGTH_LIMIT
|
|
16
15
|
|
|
17
|
-
if sys.version_info >= (3, 8):
|
|
18
|
-
from typing import Literal
|
|
19
|
-
else:
|
|
20
|
-
from typing_extensions import Literal # type: ignore
|
|
21
|
-
|
|
22
16
|
if TYPE_CHECKING:
|
|
23
17
|
from .code_model import CodeModel
|
|
24
18
|
|
|
@@ -61,6 +61,7 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
|
|
|
61
61
|
) -> None:
|
|
62
62
|
super().__init__(yaml_data, code_model)
|
|
63
63
|
self.wire_name: str = yaml_data.get("wireName", "")
|
|
64
|
+
self.etag_role: Optional[str] = yaml_data.get("etagRole", None)
|
|
64
65
|
self.client_name: str = self.yaml_data["clientName"]
|
|
65
66
|
self.optional: bool = self.yaml_data["optional"]
|
|
66
67
|
self.implementation: Optional[str] = yaml_data.get("implementation", None)
|
|
@@ -108,25 +109,24 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
|
|
|
108
109
|
type_description = self.type.description(is_operation_file=True)
|
|
109
110
|
if type_description:
|
|
110
111
|
base_description = add_to_description(base_description, type_description)
|
|
111
|
-
if self.optional and isinstance(self.type, ConstantType):
|
|
112
|
-
|
|
113
|
-
base_description
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
else:
|
|
118
|
-
base_description = add_to_description(
|
|
119
|
-
base_description,
|
|
120
|
-
f"Known values are {self.get_declaration()} and None.",
|
|
121
|
-
)
|
|
112
|
+
if (self.optional or self.is_api_version) and isinstance(self.type, ConstantType):
|
|
113
|
+
base_description = add_to_description(
|
|
114
|
+
base_description,
|
|
115
|
+
f"Known values are {self.get_declaration()} and None.",
|
|
116
|
+
)
|
|
122
117
|
if not (self.optional or self.client_default_value):
|
|
123
118
|
base_description = add_to_description(base_description, "Required.")
|
|
124
|
-
if self.
|
|
119
|
+
if self.is_api_version:
|
|
120
|
+
base_description = add_to_description(
|
|
121
|
+
base_description,
|
|
122
|
+
"Default value is None. If not set, the operation's default API version will be used.",
|
|
123
|
+
)
|
|
124
|
+
elif self.client_default_value is not None:
|
|
125
125
|
base_description = add_to_description(
|
|
126
126
|
base_description,
|
|
127
127
|
f"Default value is {self.client_default_value_declaration}.",
|
|
128
128
|
)
|
|
129
|
-
|
|
129
|
+
elif self.optional:
|
|
130
130
|
base_description = add_to_description(
|
|
131
131
|
base_description,
|
|
132
132
|
f"Default value is {self.client_default_value_declaration}.",
|
|
@@ -378,6 +378,8 @@ class ClientParameter(Parameter):
|
|
|
378
378
|
def method_location(self) -> ParameterMethodLocation:
|
|
379
379
|
if self.constant:
|
|
380
380
|
return ParameterMethodLocation.KWARG
|
|
381
|
+
if self.is_api_version:
|
|
382
|
+
return ParameterMethodLocation.KWARG
|
|
381
383
|
if (
|
|
382
384
|
self.is_host
|
|
383
385
|
and (self.code_model.options["version-tolerant"] or self.code_model.options["low-level-client"])
|
|
@@ -409,6 +411,6 @@ class ConfigParameter(Parameter):
|
|
|
409
411
|
|
|
410
412
|
@property
|
|
411
413
|
def method_location(self) -> ParameterMethodLocation:
|
|
412
|
-
if self.constant:
|
|
414
|
+
if self.constant or self.is_api_version:
|
|
413
415
|
return ParameterMethodLocation.KWARG
|
|
414
416
|
return ParameterMethodLocation.POSITIONAL
|
|
@@ -42,15 +42,15 @@ __all__ = [
|
|
|
42
42
|
"JinjaSerializer",
|
|
43
43
|
]
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
_DEFAULT_PACKAGE_FILES = (
|
|
46
46
|
"CHANGELOG.md.jinja2",
|
|
47
47
|
"dev_requirements.txt.jinja2",
|
|
48
48
|
"LICENSE.jinja2",
|
|
49
49
|
"MANIFEST.in.jinja2",
|
|
50
50
|
"README.md.jinja2",
|
|
51
|
-
|
|
51
|
+
)
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
_DEFAULT_REGENERATE_FILES = frozenset({"MANIFEST.in"})
|
|
54
54
|
AsyncInfo = namedtuple("AsyncInfo", ["async_mode", "async_path"])
|
|
55
55
|
|
|
56
56
|
|
|
@@ -75,15 +75,17 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
75
75
|
) -> None:
|
|
76
76
|
super().__init__(output_folder=output_folder, **kwargs)
|
|
77
77
|
self.code_model = code_model
|
|
78
|
+
self._package_files: list[str] = list(_DEFAULT_PACKAGE_FILES)
|
|
79
|
+
self._regenerate_files: set[str] = set(_DEFAULT_REGENERATE_FILES)
|
|
78
80
|
self._regenerate_setup_py()
|
|
79
81
|
|
|
80
82
|
def _regenerate_setup_py(self):
|
|
81
83
|
if self.code_model.options["keep-setup-py"] or self.code_model.options["basic-setup-py"]:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
self._package_files.append("setup.py.jinja2")
|
|
85
|
+
self._regenerate_files.add("setup.py")
|
|
84
86
|
else:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
self._package_files.append("pyproject.toml.jinja2")
|
|
88
|
+
self._regenerate_files.add("pyproject.toml")
|
|
87
89
|
|
|
88
90
|
@property
|
|
89
91
|
def has_aio_folder(self) -> bool:
|
|
@@ -180,6 +182,17 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
180
182
|
elif client_namespace_type.clients:
|
|
181
183
|
# add clients folder if there are clients in this namespace
|
|
182
184
|
self._serialize_client_and_config_files(client_namespace, client_namespace_type.clients, env)
|
|
185
|
+
# When generation-subdir is configured, generated code goes into a subdirectory
|
|
186
|
+
# (e.g., _generated/). We also need an __init__.py in the parent namespace dir
|
|
187
|
+
# so that the package is discoverable by find_packages() / pip install.
|
|
188
|
+
root_dir = self.code_model.get_root_dir()
|
|
189
|
+
if self.code_model.options.get("generation-subdir") and not self.read_file(
|
|
190
|
+
root_dir / Path("__init__.py")
|
|
191
|
+
):
|
|
192
|
+
self.write_file(
|
|
193
|
+
root_dir / Path("__init__.py"),
|
|
194
|
+
general_serializer.serialize_pkgutil_init_file(),
|
|
195
|
+
)
|
|
183
196
|
else:
|
|
184
197
|
# add pkgutil init file if no clients in this namespace
|
|
185
198
|
self.write_file(
|
|
@@ -242,7 +255,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
242
255
|
lstrip_blocks=True,
|
|
243
256
|
)
|
|
244
257
|
|
|
245
|
-
package_files =
|
|
258
|
+
package_files = list(self._package_files)
|
|
246
259
|
if not self.code_model.license_description:
|
|
247
260
|
package_files.remove("LICENSE.jinja2")
|
|
248
261
|
elif Path(self.code_model.options["package-mode"]).exists():
|
|
@@ -261,7 +274,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
261
274
|
continue
|
|
262
275
|
file = template_name.replace(".jinja2", "")
|
|
263
276
|
output_file = root_of_sdk / file
|
|
264
|
-
if not self.read_file(output_file) or file in
|
|
277
|
+
if not self.read_file(output_file) or file in self._regenerate_files:
|
|
265
278
|
if self.keep_version_file and file == "setup.py" and not self.code_model.options["azure-arm"]:
|
|
266
279
|
# don't regenerate setup.py file if the version file is more up to date for data-plane
|
|
267
280
|
continue
|
|
@@ -482,32 +495,34 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
482
495
|
|
|
483
496
|
def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
|
|
484
497
|
root_dir = self.code_model.get_root_dir()
|
|
498
|
+
generation_dir = self.code_model.get_generation_dir(namespace)
|
|
485
499
|
# write _utils folder
|
|
486
500
|
self._serialize_and_write_utils_folder(env, self.code_model.namespace)
|
|
487
501
|
|
|
488
502
|
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
489
503
|
|
|
490
504
|
# write _version.py
|
|
505
|
+
# Always write at root namespace since pyproject.toml references it there
|
|
491
506
|
self._serialize_and_write_version_file(general_serializer)
|
|
492
|
-
# if there's a subdir, we need to write another version file in the subdir
|
|
493
507
|
if self.code_model.options.get("generation-subdir"):
|
|
494
508
|
self._serialize_and_write_version_file(general_serializer, namespace)
|
|
495
509
|
|
|
496
510
|
# write the empty py.typed file
|
|
511
|
+
# Always write at root namespace since MANIFEST.in references it there
|
|
497
512
|
pytyped_value = "# Marker file for PEP 561."
|
|
498
513
|
self.write_file(root_dir / Path("py.typed"), pytyped_value)
|
|
499
514
|
|
|
500
515
|
# write _validation.py
|
|
501
516
|
if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
|
|
502
517
|
self.write_file(
|
|
503
|
-
|
|
518
|
+
generation_dir / Path("_validation.py"),
|
|
504
519
|
general_serializer.serialize_validation_file(),
|
|
505
520
|
)
|
|
506
521
|
|
|
507
522
|
# write _types.py
|
|
508
523
|
if self.code_model.named_unions:
|
|
509
524
|
self.write_file(
|
|
510
|
-
|
|
525
|
+
generation_dir / Path("_types.py"),
|
|
511
526
|
TypesSerializer(code_model=self.code_model, env=env).serialize(),
|
|
512
527
|
)
|
|
513
528
|
|
|
@@ -107,10 +107,18 @@ def _serialize_grouped_body(builder: BuilderType) -> list[str]:
|
|
|
107
107
|
groupers = [p for p in builder.parameters if p.grouper]
|
|
108
108
|
for grouper in groupers:
|
|
109
109
|
retval.append(f"if {grouper.client_name} is not None:")
|
|
110
|
+
# Keys in property_to_parameter_name are original client names (e.g. "from", "custom_header").
|
|
111
|
+
# Attribute access needs the padded client_name from the model property (e.g. "from_property").
|
|
112
|
+
# Build lookup from both wire_name and client_name to handle all cases.
|
|
113
|
+
grouper_model = cast(ModelType, grouper.type)
|
|
114
|
+
prop_name_to_client = {}
|
|
115
|
+
for prop in grouper_model.properties:
|
|
116
|
+
prop_name_to_client[prop.wire_name] = prop.client_name
|
|
117
|
+
prop_name_to_client[prop.client_name] = prop.client_name
|
|
110
118
|
retval.extend(
|
|
111
119
|
[
|
|
112
|
-
f" {parameter} = {grouper.client_name}.{
|
|
113
|
-
for
|
|
120
|
+
f" {parameter} = {grouper.client_name}.{prop_name_to_client[prop_name]}"
|
|
121
|
+
for prop_name, parameter in grouper.property_to_parameter_name.items()
|
|
114
122
|
]
|
|
115
123
|
)
|
|
116
124
|
return retval
|
|
@@ -1353,7 +1361,8 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1353
1361
|
except StopIteration:
|
|
1354
1362
|
pass
|
|
1355
1363
|
|
|
1356
|
-
|
|
1364
|
+
header_str = ", headers=_headers"
|
|
1365
|
+
retval.append(f'_request = HttpRequest("{builder.next_link_verb}", {next_link_str}{header_str}{query_str})')
|
|
1357
1366
|
retval.extend(self._postprocess_http_request(builder, "_request.url"))
|
|
1358
1367
|
|
|
1359
1368
|
return retval
|
|
@@ -28,7 +28,7 @@ VERSION_MAP = {
|
|
|
28
28
|
"corehttp": "1.0.0b6",
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
MIN_PYTHON_VERSION = "3.
|
|
31
|
+
MIN_PYTHON_VERSION = "3.10"
|
|
32
32
|
MAX_PYTHON_VERSION = "3.13"
|
|
33
33
|
|
|
34
34
|
|
|
@@ -155,7 +155,10 @@ class GeneralSerializer(BaseSerializer):
|
|
|
155
155
|
"VERSION_MAP": VERSION_MAP,
|
|
156
156
|
"MIN_PYTHON_VERSION": MIN_PYTHON_VERSION,
|
|
157
157
|
"MAX_PYTHON_VERSION": MAX_PYTHON_VERSION,
|
|
158
|
-
"ADDITIONAL_DEPENDENCIES": [
|
|
158
|
+
"ADDITIONAL_DEPENDENCIES": [
|
|
159
|
+
dep if dep.startswith('"') else f'"{dep}"'
|
|
160
|
+
for dep in (f"{item[0]}>={item[1]}" for item in additional_version_map.items())
|
|
161
|
+
],
|
|
159
162
|
}
|
|
160
163
|
params |= {"options": self.code_model.options}
|
|
161
164
|
params |= kwargs
|
|
@@ -326,6 +329,7 @@ class GeneralSerializer(BaseSerializer):
|
|
|
326
329
|
{
|
|
327
330
|
"CrossLanguagePackageId": self.code_model.cross_language_package_id,
|
|
328
331
|
"CrossLanguageDefinitionId": cross_langauge_def_dict,
|
|
332
|
+
"CrossLanguageVersion": self.code_model.cross_language_version,
|
|
329
333
|
},
|
|
330
334
|
indent=4,
|
|
331
335
|
)
|
|
@@ -50,20 +50,25 @@ def _serialize_import_type(imports: list[ImportModel], delimiter: str) -> str:
|
|
|
50
50
|
import_list = []
|
|
51
51
|
for module_name in sorted(set(i.module_name for i in imports)):
|
|
52
52
|
normal_imports = [i for i in imports if i.module_name == module_name and not i.version_modules]
|
|
53
|
-
versioned_imports = [i for i in imports if i.module_name == module_name and i.version_modules]
|
|
54
53
|
if normal_imports:
|
|
55
54
|
import_list.append(_serialize_package(normal_imports, delimiter))
|
|
56
|
-
for i in versioned_imports:
|
|
57
|
-
import_list.append(_serialize_versioned_package(i, delimiter))
|
|
58
55
|
return delimiter.join(import_list)
|
|
59
56
|
|
|
60
57
|
|
|
58
|
+
def _serialize_versioned_imports(imports: list[ImportModel], delimiter: str) -> str:
|
|
59
|
+
"""Serialize all versioned imports together, to be emitted after all regular imports."""
|
|
60
|
+
return delimiter.join(_serialize_versioned_package(i, delimiter) for i in imports if i.version_modules)
|
|
61
|
+
|
|
62
|
+
|
|
61
63
|
def _get_import_clauses(imports: list[ImportModel], delimiter: str) -> list[str]:
|
|
62
64
|
import_clause = []
|
|
63
65
|
for import_type in ImportType:
|
|
64
|
-
imports_with_import_type = [i for i in imports if i.import_type == import_type]
|
|
66
|
+
imports_with_import_type = [i for i in imports if i.import_type == import_type and not i.version_modules]
|
|
65
67
|
if imports_with_import_type:
|
|
66
68
|
import_clause.append(_serialize_import_type(imports_with_import_type, delimiter))
|
|
69
|
+
versioned = [i for i in imports if i.version_modules]
|
|
70
|
+
if versioned:
|
|
71
|
+
import_clause.append(_serialize_versioned_imports(versioned, delimiter))
|
|
67
72
|
return import_clause
|
|
68
73
|
|
|
69
74
|
|
|
@@ -79,6 +84,13 @@ class FileImportSerializer:
|
|
|
79
84
|
if any(self.file_import.get_imports_from_section(TypingSection.TYPING)):
|
|
80
85
|
self.file_import.add_submodule_import("typing", "TYPE_CHECKING", ImportType.STDLIB)
|
|
81
86
|
|
|
87
|
+
def _add_sys_import_if_needed(self):
|
|
88
|
+
all_imports = list(self.file_import.get_imports_from_section(TypingSection.REGULAR)) + list(
|
|
89
|
+
self.file_import.get_imports_from_section(TypingSection.TYPING)
|
|
90
|
+
)
|
|
91
|
+
if any(i.version_modules for i in all_imports):
|
|
92
|
+
self.file_import.add_import("sys", ImportType.STDLIB)
|
|
93
|
+
|
|
82
94
|
def get_typing_definitions(self) -> str:
|
|
83
95
|
def declare_definition(type_name: str, type_definition: TypeDefinition) -> list[str]:
|
|
84
96
|
ret: list[str] = []
|
|
@@ -95,6 +107,7 @@ class FileImportSerializer:
|
|
|
95
107
|
|
|
96
108
|
def __str__(self) -> str:
|
|
97
109
|
self._add_type_checking_import()
|
|
110
|
+
self._add_sys_import_if_needed()
|
|
98
111
|
regular_imports = ""
|
|
99
112
|
regular_imports_list = self._get_imports_list(TypingSection.REGULAR)
|
|
100
113
|
|
|
@@ -39,16 +39,6 @@ SPECIAL_HEADER_SERIALIZATION: dict[str, list[str]] = {
|
|
|
39
39
|
"client-request-id": [],
|
|
40
40
|
"x-ms-client-request-id": [],
|
|
41
41
|
"return-client-request-id": [],
|
|
42
|
-
"etag": [
|
|
43
|
-
"""if_match = prep_if_match(etag, match_condition)""",
|
|
44
|
-
"""if if_match is not None:""",
|
|
45
|
-
""" _headers["If-Match"] = _SERIALIZER.header("if_match", if_match, "str")""",
|
|
46
|
-
],
|
|
47
|
-
"match-condition": [
|
|
48
|
-
"""if_none_match = prep_if_none_match(etag, match_condition)""",
|
|
49
|
-
"""if if_none_match is not None:""",
|
|
50
|
-
""" _headers["If-None-Match"] = _SERIALIZER.header("if_none_match", if_none_match, "str")""",
|
|
51
|
-
],
|
|
52
42
|
}
|
|
53
43
|
|
|
54
44
|
|
|
@@ -157,6 +147,20 @@ class ParameterSerializer:
|
|
|
157
147
|
):
|
|
158
148
|
return SPECIAL_HEADER_SERIALIZATION[param.wire_name.lower()]
|
|
159
149
|
|
|
150
|
+
if not is_legacy and param.location == ParameterLocation.HEADER and param.etag_role is not None:
|
|
151
|
+
header_name = param.wire_name
|
|
152
|
+
if param.etag_role == "ifMatch":
|
|
153
|
+
return [
|
|
154
|
+
"""if_match = prep_if_match(etag, match_condition)""",
|
|
155
|
+
"""if if_match is not None:""",
|
|
156
|
+
f""" _headers["{header_name}"] = _SERIALIZER.header("if_match", if_match, "str")""",
|
|
157
|
+
]
|
|
158
|
+
return [
|
|
159
|
+
"""if_none_match = prep_if_none_match(etag, match_condition)""",
|
|
160
|
+
"""if if_none_match is not None:""",
|
|
161
|
+
f""" _headers["{header_name}"] = _SERIALIZER.header("if_none_match", if_none_match, "str")""",
|
|
162
|
+
]
|
|
163
|
+
|
|
160
164
|
set_parameter = "_{}['{}'] = {}".format(
|
|
161
165
|
kwarg_name,
|
|
162
166
|
param.wire_name,
|
|
@@ -202,11 +206,13 @@ class ParameterSerializer:
|
|
|
202
206
|
if is_content_type_optional and not type_annotation.startswith("Optional[")
|
|
203
207
|
else type_annotation
|
|
204
208
|
)
|
|
205
|
-
if kwarg.client_default_value is not None or kwarg.optional or kwarg.constant:
|
|
209
|
+
if kwarg.client_default_value is not None or kwarg.optional or kwarg.constant or kwarg.is_api_version:
|
|
206
210
|
if check_client_input and kwarg.check_client_input:
|
|
207
211
|
default_value = f"self._config.{kwarg.client_name}"
|
|
208
212
|
elif kwarg.constant:
|
|
209
213
|
default_value = kwarg.type.get_declaration(None)
|
|
214
|
+
elif kwarg.is_api_version and kwarg.client_default_value is None and kwarg.api_versions:
|
|
215
|
+
default_value = f'"{kwarg.api_versions[-1]}"'
|
|
210
216
|
else:
|
|
211
217
|
default_value = kwarg.client_default_value_declaration
|
|
212
218
|
if check_kwarg_dict and (kwarg.location in [ParameterLocation.HEADER, ParameterLocation.QUERY]):
|
|
@@ -19,17 +19,22 @@ from datetime import datetime, date, time, timedelta, timezone
|
|
|
19
19
|
from json import JSONEncoder
|
|
20
20
|
import xml.etree.ElementTree as ET
|
|
21
21
|
from collections.abc import MutableMapping
|
|
22
|
-
from typing_extensions import Self
|
|
23
22
|
import isodate
|
|
24
23
|
from {{ code_model.core_library }}.exceptions import DeserializationError
|
|
25
24
|
from {{ code_model.core_library }}{{ "" if code_model.is_azure_flavor else ".utils" }} import CaseInsensitiveEnumMeta
|
|
26
25
|
from {{ code_model.core_library }}.{{ "" if code_model.is_azure_flavor else "runtime." }}pipeline import PipelineResponse
|
|
27
26
|
from {{ code_model.core_library }}.serialization import _Null
|
|
27
|
+
|
|
28
28
|
{% if code_model.has_external_type %}
|
|
29
29
|
from {{ code_model.core_library }}.serialization import TypeHandlerRegistry
|
|
30
30
|
{% endif %}
|
|
31
31
|
from {{ code_model.core_library }}.rest import HttpResponse
|
|
32
32
|
|
|
33
|
+
if sys.version_info >= (3, 11):
|
|
34
|
+
from typing import Self
|
|
35
|
+
else:
|
|
36
|
+
from typing_extensions import Self
|
|
37
|
+
|
|
33
38
|
_LOGGER = logging.getLogger(__name__)
|
|
34
39
|
|
|
35
40
|
__all__ = ["SdkJSONEncoder", "Model", "rest_field", "rest_discriminator"]
|
|
@@ -617,11 +622,7 @@ class Model(_MyMutableMapping):
|
|
|
617
622
|
class_name = self.__class__.__name__
|
|
618
623
|
if len(args) > 1:
|
|
619
624
|
raise TypeError(f"{class_name}.__init__() takes 2 positional arguments but {len(args) + 1} were given")
|
|
620
|
-
dict_to_pass = {
|
|
621
|
-
rest_field._rest_name: rest_field._default
|
|
622
|
-
for rest_field in self._attr_to_rest_field.values()
|
|
623
|
-
if rest_field._default is not _UNSET
|
|
624
|
-
}
|
|
625
|
+
dict_to_pass: dict[str, typing.Any] = {}
|
|
625
626
|
if args:
|
|
626
627
|
if isinstance(args[0], ET.Element):
|
|
627
628
|
dict_to_pass.update(self._init_from_xml(args[0]))
|
|
@@ -641,6 +642,14 @@ class Model(_MyMutableMapping):
|
|
|
641
642
|
if v is not None
|
|
642
643
|
}
|
|
643
644
|
)
|
|
645
|
+
# Apply client default values for fields the caller didn't set so that
|
|
646
|
+
# defaults are part of `_data` and therefore included during serialization.
|
|
647
|
+
for rf in self._attr_to_rest_field.values():
|
|
648
|
+
if rf._default is _UNSET:
|
|
649
|
+
continue
|
|
650
|
+
if rf._rest_name in dict_to_pass:
|
|
651
|
+
continue
|
|
652
|
+
dict_to_pass[rf._rest_name] = _create_value(rf, rf._default)
|
|
644
653
|
super().__init__(dict_to_pass)
|
|
645
654
|
|
|
646
655
|
def _init_from_xml(self, element: ET.Element) -> dict[str, typing.Any]:
|
|
@@ -1160,7 +1169,10 @@ class _RestField:
|
|
|
1160
1169
|
# by this point, type and rest_name will have a value bc we default
|
|
1161
1170
|
# them in __new__ of the Model class
|
|
1162
1171
|
# Use _data.get() directly to avoid triggering __getitem__ which clears the cache
|
|
1163
|
-
item = obj._data.get(self._rest_name)
|
|
1172
|
+
item = obj._data.get(self._rest_name, _UNSET)
|
|
1173
|
+
if item is _UNSET:
|
|
1174
|
+
# Field not set by user; return the client default if one exists, otherwise None
|
|
1175
|
+
return self._default if self._default is not _UNSET else None
|
|
1164
1176
|
if item is None:
|
|
1165
1177
|
return item
|
|
1166
1178
|
if self._is_model:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Microsoft Azure SDK for Python
|
|
4
4
|
|
|
5
5
|
This is the Microsoft {{options["package-pprint-name"]}} Client Library.
|
|
6
|
-
This package has been tested with Python 3.
|
|
6
|
+
This package has been tested with Python 3.10+.
|
|
7
7
|
For a more complete view of Azure libraries, see the [azure sdk python release](https://aka.ms/azsdk/python/all).
|
|
8
8
|
|
|
9
9
|
# Usage
|
|
@@ -14,6 +14,10 @@ For docs and references, see [Python SDK References](https://docs.microsoft.com/
|
|
|
14
14
|
Code samples for this package can be found at [{{options["package-pprint-name"]}}](https://docs.microsoft.com/samples/browse/?languages=python&term=Getting%20started%20-%20Managing&terms=Getting%20started%20-%20Managing) on docs.microsoft.com.
|
|
15
15
|
Additional code samples for different Azure services are available at [Samples Repo](https://aka.ms/azsdk/python/mgmt/samples)
|
|
16
16
|
|
|
17
|
+
# Use with AI tools
|
|
18
|
+
|
|
19
|
+
AI coding tools such as VS Code and GitHub Copilot can help you write and debug code that uses this library. See [Using the Azure SDK for Python with AI tools](https://aka.ms/azsdk/python/ai) for available integrations.
|
|
20
|
+
|
|
17
21
|
# Provide Feedback
|
|
18
22
|
|
|
19
23
|
If you encounter any bugs or have suggestions, please file an issue in the
|
|
@@ -36,10 +40,14 @@ python -m pip install {{ options["package-name"] }}
|
|
|
36
40
|
|
|
37
41
|
#### Prequisites
|
|
38
42
|
|
|
39
|
-
- Python 3.
|
|
43
|
+
- Python 3.10 or later is required to use this package.
|
|
40
44
|
- You need an [Azure subscription][azure_sub] to use this package.
|
|
41
45
|
- An existing {{ options["package-pprint-name"] }} instance.
|
|
42
46
|
|
|
47
|
+
### Use with AI tools
|
|
48
|
+
|
|
49
|
+
AI coding tools such as VS Code and GitHub Copilot can help you write and debug code that uses this library. See [Using the Azure SDK for Python with AI tools](https://aka.ms/azsdk/python/ai) for available integrations.
|
|
50
|
+
|
|
43
51
|
{% if token_credential and client_name %}
|
|
44
52
|
#### Create with an Azure Active Directory Credential
|
|
45
53
|
To use an [Azure Active Directory (AAD) token credential][authenticate_with_token],
|
|
@@ -113,7 +121,7 @@ This package is generated by `@typespec/http-client-python` with Typespec.
|
|
|
113
121
|
|
|
114
122
|
### Prequisites
|
|
115
123
|
|
|
116
|
-
- Python 3.
|
|
124
|
+
- Python 3.10 or later is required to use this package.
|
|
117
125
|
|
|
118
126
|
### Install the package
|
|
119
127
|
|
|
@@ -35,11 +35,15 @@ except ImportError:
|
|
|
35
35
|
import xml.etree.ElementTree as ET
|
|
36
36
|
|
|
37
37
|
import isodate # type: ignore
|
|
38
|
-
from typing_extensions import Self
|
|
39
38
|
|
|
40
39
|
from {{ code_model.core_library }}.exceptions import DeserializationError, SerializationError
|
|
41
40
|
from {{ code_model.core_library }}.serialization import NULL as CoreNull
|
|
42
41
|
|
|
42
|
+
if sys.version_info >= (3, 11):
|
|
43
|
+
from typing import Self
|
|
44
|
+
else:
|
|
45
|
+
from typing_extensions import Self
|
|
46
|
+
|
|
43
47
|
_BOM = codecs.BOM_UTF8.decode(encoding="utf-8")
|
|
44
48
|
|
|
45
49
|
JSON = MutableMapping[str, Any]
|