@autorest/python 6.32.3 → 6.33.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 (26) hide show
  1. package/autorest/m2r.py +1 -2
  2. package/autorest/m4reformatter/__init__.py +1 -2
  3. package/autorest/multiapi/models/imports.py +7 -2
  4. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +13 -2
  5. package/autorest/preprocess.py +1 -2
  6. package/generator/build/lib/pygen/codegen/models/client.py +39 -2
  7. package/generator/build/lib/pygen/codegen/models/enum_type.py +2 -2
  8. package/generator/build/lib/pygen/codegen/models/model_type.py +1 -1
  9. package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +32 -6
  10. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +20 -1
  11. package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +2 -2
  12. package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +1 -1
  13. package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +2 -8
  14. package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +12 -11
  15. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  16. package/generator/pygen/codegen/models/client.py +39 -2
  17. package/generator/pygen/codegen/models/enum_type.py +2 -2
  18. package/generator/pygen/codegen/models/model_type.py +1 -1
  19. package/generator/pygen/codegen/serializers/client_serializer.py +32 -6
  20. package/generator/pygen/codegen/serializers/general_serializer.py +20 -1
  21. package/generator/pygen/codegen/serializers/sample_serializer.py +2 -2
  22. package/generator/pygen/codegen/templates/client.py.jinja2 +1 -1
  23. package/generator/pygen/codegen/templates/config.py.jinja2 +2 -8
  24. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +12 -11
  25. package/package.json +2 -2
  26. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
package/autorest/m2r.py CHANGED
@@ -3,8 +3,7 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- """An autorest MD to RST plugin.
7
- """
6
+ """An autorest MD to RST plugin."""
8
7
  import logging
9
8
  from typing import Any, Dict, Set, Union
10
9
 
@@ -4,8 +4,7 @@
4
4
  # Licensed under the MIT License. See License.txt in the project root for
5
5
  # license information.
6
6
  # --------------------------------------------------------------------------
7
- """The modelerfour reformatter autorest plugin.
8
- """
7
+ """The modelerfour reformatter autorest plugin."""
9
8
  import re
10
9
  import copy
11
10
  import logging
@@ -123,9 +123,14 @@ class FileImport:
123
123
  ],
124
124
  convert_list_to_tuple(name_import),
125
125
  )
126
- self._imports.setdefault(typing_section, {}).setdefault(import_type, {}).setdefault(from_section, set()).add(
127
- name_input
126
+ target_values = (
127
+ self._imports.setdefault(typing_section, {}).setdefault(import_type, {}).setdefault(from_section, set())
128
128
  )
129
+ if isinstance(target_values, list):
130
+ if name_input not in target_values:
131
+ target_values.append(name_input)
132
+ else:
133
+ target_values.add(name_input)
129
134
 
130
135
  def add_submodule_import(
131
136
  self,
@@ -18,6 +18,7 @@ def __init__(
18
18
  {% set async_prefix = "Async" if async_mode else "" %}
19
19
  {% set a_prefix = "a" if async_mode else "" %}
20
20
  {% set await = "await " if async_mode else "" %}
21
+ {% set credential_scopes = "credential_scopes=credential_scopes, " if code_model.config.credential_scopes is not none and code_model.azure_arm else "" %}
21
22
  # coding=utf-8
22
23
  # --------------------------------------------------------------------------
23
24
  # Copyright (c) Microsoft Corporation. All rights reserved.
@@ -77,6 +78,7 @@ class {{ code_model.client.name }}({% if code_model.operation_mixin_group.mixin_
77
78
  )
78
79
 
79
80
  {{ method_signature()|indent }}
81
+ {% if not code_model.azure_arm %}
80
82
  {% if not code_model.client.host_value %}
81
83
  {% for parameterized_host_template, api_versions in code_model.client.parameterized_host_template_to_api_version|dictsort %}
82
84
  {% set if_statement = "if" if loop.first else "elif" %}
@@ -86,9 +88,17 @@ class {{ code_model.client.name }}({% if code_model.operation_mixin_group.mixin_
86
88
  else:
87
89
  raise ValueError("API version {} is not available".format(api_version))
88
90
  {% endif %}
91
+ {% endif %}
89
92
  if api_version:
90
93
  kwargs.setdefault('api_version', api_version)
91
- self._config = {{ code_model.client.name }}Configuration({{ code_model.global_parameters.call }}{{ ", " if code_model.global_parameters.call }}**kwargs)
94
+ {% if credential_scopes %}
95
+ _cloud = kwargs.pop("cloud_setting", None) or settings.current.azure_cloud # type: ignore
96
+ _endpoints = get_arm_endpoints(_cloud)
97
+ if not base_url:
98
+ base_url = _endpoints["resource_manager"]
99
+ credential_scopes = kwargs.pop("credential_scopes", _endpoints["credential_scopes"])
100
+ {% endif %}
101
+ self._config = {{ code_model.client.name }}Configuration({{ code_model.global_parameters.call }}{{ ", " if code_model.global_parameters.call }}{{ credential_scopes }}**kwargs)
92
102
  _policies = kwargs.pop("policies", None)
93
103
  if _policies is None:
94
104
  _policies = [
@@ -96,7 +106,8 @@ class {{ code_model.client.name }}({% if code_model.operation_mixin_group.mixin_
96
106
  {{ p }},
97
107
  {% endfor %}
98
108
  ]
99
- self._client: {{ async_prefix }}{{ code_model.client.pipeline_client }} = {{ async_prefix }}{{ code_model.client.pipeline_client }}(base_url={{ code_model.host_variable_name }}, policies=_policies, **kwargs)
109
+ {% set host_variable_name = "cast(str, " + code_model.host_variable_name + ")" if credential_scopes else code_model.host_variable_name %}
110
+ self._client: {{ async_prefix }}{{ code_model.client.pipeline_client }} = {{ async_prefix }}{{ code_model.client.pipeline_client }}(base_url={{ host_variable_name }}, policies=_policies, **kwargs)
100
111
  super({{ code_model.client.name }}, self).__init__(
101
112
  api_version=api_version,
102
113
  profile=profile
@@ -3,8 +3,7 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- """The preprocessing autorest plugin.
7
- """
6
+ """The preprocessing autorest plugin."""
8
7
  from typing import Dict, Any
9
8
  from pygen.preprocess import PreProcessPlugin
10
9
  from . import YamlUpdatePluginAutorest
@@ -15,7 +15,7 @@ from .request_builder import (
15
15
  OverloadedRequestBuilder,
16
16
  get_request_builder,
17
17
  )
18
- from .parameter import Parameter, ParameterMethodLocation
18
+ from .parameter import Parameter, ParameterMethodLocation, ParameterLocation
19
19
  from .lro_operation import LROOperation
20
20
  from .lro_paging_operation import LROPagingOperation
21
21
  from ...utils import extract_original_name, NAME_LENGTH_LIMIT
@@ -54,7 +54,7 @@ class _ClientConfigBase(Generic[ParameterListType], BaseModel):
54
54
  return self.yaml_data["name"]
55
55
 
56
56
 
57
- class Client(_ClientConfigBase[ClientGlobalParameterList]):
57
+ class Client(_ClientConfigBase[ClientGlobalParameterList]): # pylint: disable=too-many-public-methods
58
58
  """Model representing our service client"""
59
59
 
60
60
  def __init__(
@@ -79,6 +79,27 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
79
79
  self.request_id_header_name = self.yaml_data.get("requestIdHeaderName", None)
80
80
  self.has_etag: bool = yaml_data.get("hasEtag", False)
81
81
 
82
+ # update the host parameter value. In later logic, SDK will overwrite it
83
+ # with value from cloud_setting if users don't provide it.
84
+ if self.need_cloud_setting:
85
+ for p in self.parameters.parameters:
86
+ if p.location == ParameterLocation.ENDPOINT_PATH:
87
+ p.client_default_value = None
88
+ p.optional = True
89
+ break
90
+
91
+ @property
92
+ def need_cloud_setting(self) -> bool:
93
+ return bool(
94
+ self.code_model.options.get("azure_arm", False)
95
+ and self.credential_scopes is not None
96
+ and self.endpoint_parameter is not None
97
+ )
98
+
99
+ @property
100
+ def endpoint_parameter(self) -> Optional[Parameter]:
101
+ return next((p for p in self.parameters.parameters if p.location == ParameterLocation.ENDPOINT_PATH), None)
102
+
82
103
  def _build_request_builders(
83
104
  self,
84
105
  ) -> List[Union[RequestBuilder, OverloadedRequestBuilder]]:
@@ -233,6 +254,10 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
233
254
  "Self",
234
255
  ImportType.STDLIB,
235
256
  )
257
+ if self.need_cloud_setting:
258
+ file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
259
+ file_import.add_submodule_import("azure.core.settings", "settings", ImportType.SDKCORE)
260
+ file_import.add_submodule_import("azure.mgmt.core.tools", "get_arm_endpoints", ImportType.SDKCORE)
236
261
  return file_import
237
262
 
238
263
  @property
@@ -332,6 +357,18 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
332
357
  )
333
358
  return file_import
334
359
 
360
+ @property
361
+ def credential_scopes(self) -> Optional[List[str]]:
362
+ """Credential scopes for this client"""
363
+
364
+ if self.credential:
365
+ if hasattr(getattr(self.credential.type, "policy", None), "credential_scopes"):
366
+ return self.credential.type.policy.credential_scopes # type: ignore
367
+ for t in getattr(self.credential.type, "types", []):
368
+ if hasattr(getattr(t, "policy", None), "credential_scopes"):
369
+ return t.policy.credential_scopes
370
+ return None
371
+
335
372
  @classmethod
336
373
  def from_yaml(
337
374
  cls,
@@ -52,7 +52,7 @@ class EnumValue(BaseType):
52
52
  """The python type used for RST syntax input and type annotation."""
53
53
 
54
54
  type_annotation = self.value_type.type_annotation(**kwargs)
55
- enum_type_annotation = f"{self.code_model.namespace}.models.{self.name}"
55
+ enum_type_annotation = f"{self.enum_type.client_namespace}.models.{self.name}"
56
56
  return f"{type_annotation} or ~{enum_type_annotation}"
57
57
 
58
58
  def get_json_template_representation(
@@ -198,7 +198,7 @@ class EnumType(BaseType):
198
198
  """The python type used for RST syntax input and type annotation."""
199
199
  if self.code_model.options["models_mode"]:
200
200
  type_annotation = self.value_type.type_annotation(**kwargs)
201
- enum_type_annotation = f"{self.code_model.namespace}.models.{self.name}"
201
+ enum_type_annotation = f"{self.client_namespace}.models.{self.name}"
202
202
  return f"{type_annotation} or ~{enum_type_annotation}"
203
203
  return self.value_type.type_annotation(**kwargs)
204
204
 
@@ -292,7 +292,7 @@ class GeneratedModelType(ModelType):
292
292
 
293
293
  def docstring_type(self, **kwargs: Any) -> str:
294
294
  type_annotation = self.type_annotation(need_model_alias=False, skip_quote=True, **kwargs)
295
- return f"~{self.code_model.namespace}.models.{type_annotation}"
295
+ return f"~{self.client_namespace}.models.{type_annotation}"
296
296
 
297
297
  def docstring_text(self, **kwargs: Any) -> str:
298
298
  return self.name
@@ -3,10 +3,10 @@
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 List
6
+ from typing import List, cast
7
7
 
8
8
  from . import utils
9
- from ..models import Client, ParameterMethodLocation
9
+ from ..models import Client, ParameterMethodLocation, Parameter, ParameterLocation
10
10
  from .parameter_serializer import ParameterSerializer, PopKwargType
11
11
  from ...utils import build_policies
12
12
 
@@ -77,17 +77,40 @@ class ClientSerializer:
77
77
  retval.append('"""')
78
78
  return retval
79
79
 
80
- def initialize_config(self) -> str:
80
+ def initialize_config(self) -> List[str]:
81
+ retval = []
82
+ additional_signatures = []
83
+ if self.client.need_cloud_setting:
84
+ additional_signatures.append("credential_scopes=credential_scopes")
85
+ endpoint_parameter = cast(Parameter, self.client.endpoint_parameter)
86
+ retval.extend(
87
+ [
88
+ '_cloud = kwargs.pop("cloud_setting", None) or settings.current.azure_cloud # type: ignore',
89
+ "_endpoints = get_arm_endpoints(_cloud)",
90
+ f"if not {endpoint_parameter.client_name}:",
91
+ f' {endpoint_parameter.client_name} = _endpoints["resource_manager"]',
92
+ 'credential_scopes = kwargs.pop("credential_scopes", _endpoints["credential_scopes"])',
93
+ ]
94
+ )
81
95
  config_name = f"{self.client.name}Configuration"
82
96
  config_call = ", ".join(
83
97
  [
84
- f"{p.client_name}={p.client_name}"
98
+ (
99
+ f"{p.client_name}="
100
+ + (
101
+ f"cast(str, {p.client_name})"
102
+ if self.client.need_cloud_setting and p.location == ParameterLocation.ENDPOINT_PATH
103
+ else p.client_name
104
+ )
105
+ )
85
106
  for p in self.client.config.parameters.method
86
107
  if p.method_location != ParameterMethodLocation.KWARG
87
108
  ]
109
+ + additional_signatures
88
110
  + ["**kwargs"]
89
111
  )
90
- return f"self._config = {config_name}({config_call})"
112
+ retval.append(f"self._config = {config_name}({config_call})")
113
+ return retval
91
114
 
92
115
  @property
93
116
  def host_variable_name(self) -> str:
@@ -104,8 +127,11 @@ class ClientSerializer:
104
127
  result = []
105
128
  pipeline_client_name = self.client.pipeline_class(async_mode)
106
129
  endpoint_name = "base_url" if self.client.code_model.is_azure_flavor else "endpoint"
130
+ host_variable_name = (
131
+ f"cast(str, {self.host_variable_name})" if self.client.need_cloud_setting else self.host_variable_name
132
+ )
107
133
  params = {
108
- endpoint_name: self.host_variable_name,
134
+ endpoint_name: host_variable_name,
109
135
  "policies": "_policies",
110
136
  }
111
137
  if not self.client.code_model.is_legacy and self.client.request_id_header_name:
@@ -16,13 +16,29 @@ from ..models.utils import NamespaceType
16
16
  from .client_serializer import ClientSerializer, ConfigSerializer
17
17
  from .base_serializer import BaseSerializer
18
18
 
19
+ VERSION_MAP = {
20
+ "msrest": "0.7.1",
21
+ "isodate": "0.6.1",
22
+ "azure-mgmt-core": "1.5.0",
23
+ "azure-core": "1.30.0",
24
+ "typing-extensions": "4.6.0",
25
+ "corehttp": "1.0.0b6",
26
+ }
27
+
28
+ MIN_PYTHON_VERSION = "3.9"
29
+ MAX_PYTHON_VERSION = "3.12"
30
+
19
31
 
20
32
  class GeneralSerializer(BaseSerializer):
21
33
  """General serializer for SDK root level files"""
22
34
 
23
35
  def serialize_setup_file(self) -> str:
24
36
  template = self.env.get_template("packaging_templates/setup.py.jinja2")
25
- params = {}
37
+ params = {
38
+ "VERSION_MAP": VERSION_MAP,
39
+ "MIN_PYTHON_VERSION": MIN_PYTHON_VERSION,
40
+ "MAX_PYTHON_VERSION": MAX_PYTHON_VERSION,
41
+ }
26
42
  params.update(self.code_model.options)
27
43
  return template.render(code_model=self.code_model, **params)
28
44
 
@@ -48,6 +64,9 @@ class GeneralSerializer(BaseSerializer):
48
64
  "pkgutil_names": [".".join(package_parts[: i + 1]) for i in range(len(package_parts))],
49
65
  "init_names": ["/".join(package_parts[: i + 1]) + "/__init__.py" for i in range(len(package_parts))],
50
66
  "client_name": self.code_model.clients[0].name,
67
+ "VERSION_MAP": VERSION_MAP,
68
+ "MIN_PYTHON_VERSION": MIN_PYTHON_VERSION,
69
+ "MAX_PYTHON_VERSION": MAX_PYTHON_VERSION,
51
70
  }
52
71
  params.update(self.code_model.options)
53
72
  params.update(kwargs)
@@ -62,7 +62,7 @@ class SampleSerializer(BaseSerializer):
62
62
  ImportType.SDKCORE,
63
63
  )
64
64
  for param in self.operation.parameters.positional + self.operation.parameters.keyword_only:
65
- if not param.client_default_value and not param.optional and param.wire_name in self.sample_params:
65
+ if param.client_default_value is None and not param.optional and param.wire_name in self.sample_params:
66
66
  imports.merge(param.type.imports_for_sample())
67
67
  return FileImportSerializer(imports, True)
68
68
 
@@ -80,7 +80,7 @@ class SampleSerializer(BaseSerializer):
80
80
  for p in (
81
81
  self.code_model.clients[0].parameters.positional + self.code_model.clients[0].parameters.keyword_only
82
82
  )
83
- if not (p.optional or p.client_default_value)
83
+ if not p.optional and p.client_default_value is None
84
84
  ]
85
85
  client_params = {
86
86
  p.client_name: special_param.get(
@@ -9,7 +9,7 @@
9
9
  {% if client.has_parameterized_host %}
10
10
  {{ serializer.host_variable_name }} = {{ keywords.escape_str(client.url) }}
11
11
  {% endif %}
12
- {{ serializer.initialize_config() }}
12
+ {{ op_tools.serialize(serializer.initialize_config()) | indent(8) }}
13
13
  {{ op_tools.serialize(serializer.initialize_pipeline_client(async_mode)) | indent(8) }}
14
14
 
15
15
  {{ op_tools.serialize(serializer.serializers_and_operation_groups_properties()) | indent(8) }}
@@ -21,14 +21,8 @@ class {{ client.name }}Configuration: {{ client.config.pylint_disable() }}
21
21
  {% if serializer.set_constants() %}
22
22
  {{ op_tools.serialize(serializer.set_constants()) | indent(8) -}}
23
23
  {% endif %}
24
- {% if client.credential %}
25
- {% set cred_scopes = client.credential.type if client.credential.type.policy is defined and client.credential.type.policy.credential_scopes is defined %}
26
- {% if not cred_scopes %}
27
- {% set cred_scopes = client.credential.type.types | selectattr("policy.credential_scopes") | first if client.credential.type.types is defined %}
28
- {% endif %}
29
- {% if cred_scopes %}
30
- self.credential_scopes = kwargs.pop('credential_scopes', {{ cred_scopes.policy.credential_scopes }})
31
- {% endif %}
24
+ {% if client.credential_scopes is not none %}
25
+ self.credential_scopes = kwargs.pop('credential_scopes', {{ client.credential_scopes }})
32
26
  {% endif %}
33
27
  kwargs.setdefault('sdk_moniker', '{{ client.config.sdk_moniker }}/{}'.format(VERSION))
34
28
  self.polling_interval = kwargs.get("polling_interval", 30)
@@ -1,4 +1,6 @@
1
1
  # coding=utf-8
2
+ {% set min_version = MIN_PYTHON_VERSION.split('.')[1] | int %}
3
+ {% set max_version = MAX_PYTHON_VERSION.split('.')[1] | int %}
2
4
  {% if code_model.license_header %}
3
5
  {{ code_model.license_header }}
4
6
  {% endif %}
@@ -67,10 +69,9 @@ setup(
67
69
  "Programming Language :: Python",
68
70
  "Programming Language :: Python :: 3 :: Only",
69
71
  "Programming Language :: Python :: 3",
70
- "Programming Language :: Python :: 3.9",
71
- "Programming Language :: Python :: 3.10",
72
- "Programming Language :: Python :: 3.11",
73
- "Programming Language :: Python :: 3.12",
72
+ {% for version in range(min_version, max_version + 1) %}
73
+ "Programming Language :: Python :: 3.{{ version }}",
74
+ {% endfor %}
74
75
  "License :: OSI Approved :: MIT License",
75
76
  ],
76
77
  zip_safe=False,
@@ -95,21 +96,21 @@ setup(
95
96
  {% endif %}
96
97
  install_requires=[
97
98
  {% if code_model.is_legacy %}
98
- "msrest>=0.7.1",
99
+ "msrest>={{ VERSION_MAP["msrest"] }}",
99
100
  {% else %}
100
- "isodate>=0.6.1",
101
+ "isodate>={{ VERSION_MAP["isodate"] }}",
101
102
  {% endif %}
102
103
  {% if azure_arm %}
103
- "azure-mgmt-core>=1.3.2",
104
+ "azure-mgmt-core>={{ VERSION_MAP["azure-mgmt-core"] }}",
104
105
  {% elif code_model.is_azure_flavor %}
105
- "azure-core>=1.30.0",
106
+ "azure-core>={{ VERSION_MAP["azure-core"] }}",
106
107
  {% else %}
107
- "corehttp[requests]",
108
+ "corehttp[requests]>={{ VERSION_MAP["corehttp"] }}",
108
109
  {% endif %}
109
- "typing-extensions>=4.6.0",
110
+ "typing-extensions>={{ VERSION_MAP['typing-extensions'] }}",
110
111
  ],
111
112
  {% if package_mode %}
112
- python_requires=">=3.9",
113
+ python_requires=">={{ MIN_PYTHON_VERSION }}",
113
114
  {% else %}
114
115
  long_description="""\
115
116
  {{ code_model.description }}
@@ -15,7 +15,7 @@ from .request_builder import (
15
15
  OverloadedRequestBuilder,
16
16
  get_request_builder,
17
17
  )
18
- from .parameter import Parameter, ParameterMethodLocation
18
+ from .parameter import Parameter, ParameterMethodLocation, ParameterLocation
19
19
  from .lro_operation import LROOperation
20
20
  from .lro_paging_operation import LROPagingOperation
21
21
  from ...utils import extract_original_name, NAME_LENGTH_LIMIT
@@ -54,7 +54,7 @@ class _ClientConfigBase(Generic[ParameterListType], BaseModel):
54
54
  return self.yaml_data["name"]
55
55
 
56
56
 
57
- class Client(_ClientConfigBase[ClientGlobalParameterList]):
57
+ class Client(_ClientConfigBase[ClientGlobalParameterList]): # pylint: disable=too-many-public-methods
58
58
  """Model representing our service client"""
59
59
 
60
60
  def __init__(
@@ -79,6 +79,27 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
79
79
  self.request_id_header_name = self.yaml_data.get("requestIdHeaderName", None)
80
80
  self.has_etag: bool = yaml_data.get("hasEtag", False)
81
81
 
82
+ # update the host parameter value. In later logic, SDK will overwrite it
83
+ # with value from cloud_setting if users don't provide it.
84
+ if self.need_cloud_setting:
85
+ for p in self.parameters.parameters:
86
+ if p.location == ParameterLocation.ENDPOINT_PATH:
87
+ p.client_default_value = None
88
+ p.optional = True
89
+ break
90
+
91
+ @property
92
+ def need_cloud_setting(self) -> bool:
93
+ return bool(
94
+ self.code_model.options.get("azure_arm", False)
95
+ and self.credential_scopes is not None
96
+ and self.endpoint_parameter is not None
97
+ )
98
+
99
+ @property
100
+ def endpoint_parameter(self) -> Optional[Parameter]:
101
+ return next((p for p in self.parameters.parameters if p.location == ParameterLocation.ENDPOINT_PATH), None)
102
+
82
103
  def _build_request_builders(
83
104
  self,
84
105
  ) -> List[Union[RequestBuilder, OverloadedRequestBuilder]]:
@@ -233,6 +254,10 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
233
254
  "Self",
234
255
  ImportType.STDLIB,
235
256
  )
257
+ if self.need_cloud_setting:
258
+ file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
259
+ file_import.add_submodule_import("azure.core.settings", "settings", ImportType.SDKCORE)
260
+ file_import.add_submodule_import("azure.mgmt.core.tools", "get_arm_endpoints", ImportType.SDKCORE)
236
261
  return file_import
237
262
 
238
263
  @property
@@ -332,6 +357,18 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
332
357
  )
333
358
  return file_import
334
359
 
360
+ @property
361
+ def credential_scopes(self) -> Optional[List[str]]:
362
+ """Credential scopes for this client"""
363
+
364
+ if self.credential:
365
+ if hasattr(getattr(self.credential.type, "policy", None), "credential_scopes"):
366
+ return self.credential.type.policy.credential_scopes # type: ignore
367
+ for t in getattr(self.credential.type, "types", []):
368
+ if hasattr(getattr(t, "policy", None), "credential_scopes"):
369
+ return t.policy.credential_scopes
370
+ return None
371
+
335
372
  @classmethod
336
373
  def from_yaml(
337
374
  cls,
@@ -52,7 +52,7 @@ class EnumValue(BaseType):
52
52
  """The python type used for RST syntax input and type annotation."""
53
53
 
54
54
  type_annotation = self.value_type.type_annotation(**kwargs)
55
- enum_type_annotation = f"{self.code_model.namespace}.models.{self.name}"
55
+ enum_type_annotation = f"{self.enum_type.client_namespace}.models.{self.name}"
56
56
  return f"{type_annotation} or ~{enum_type_annotation}"
57
57
 
58
58
  def get_json_template_representation(
@@ -198,7 +198,7 @@ class EnumType(BaseType):
198
198
  """The python type used for RST syntax input and type annotation."""
199
199
  if self.code_model.options["models_mode"]:
200
200
  type_annotation = self.value_type.type_annotation(**kwargs)
201
- enum_type_annotation = f"{self.code_model.namespace}.models.{self.name}"
201
+ enum_type_annotation = f"{self.client_namespace}.models.{self.name}"
202
202
  return f"{type_annotation} or ~{enum_type_annotation}"
203
203
  return self.value_type.type_annotation(**kwargs)
204
204
 
@@ -292,7 +292,7 @@ class GeneratedModelType(ModelType):
292
292
 
293
293
  def docstring_type(self, **kwargs: Any) -> str:
294
294
  type_annotation = self.type_annotation(need_model_alias=False, skip_quote=True, **kwargs)
295
- return f"~{self.code_model.namespace}.models.{type_annotation}"
295
+ return f"~{self.client_namespace}.models.{type_annotation}"
296
296
 
297
297
  def docstring_text(self, **kwargs: Any) -> str:
298
298
  return self.name
@@ -3,10 +3,10 @@
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 List
6
+ from typing import List, cast
7
7
 
8
8
  from . import utils
9
- from ..models import Client, ParameterMethodLocation
9
+ from ..models import Client, ParameterMethodLocation, Parameter, ParameterLocation
10
10
  from .parameter_serializer import ParameterSerializer, PopKwargType
11
11
  from ...utils import build_policies
12
12
 
@@ -77,17 +77,40 @@ class ClientSerializer:
77
77
  retval.append('"""')
78
78
  return retval
79
79
 
80
- def initialize_config(self) -> str:
80
+ def initialize_config(self) -> List[str]:
81
+ retval = []
82
+ additional_signatures = []
83
+ if self.client.need_cloud_setting:
84
+ additional_signatures.append("credential_scopes=credential_scopes")
85
+ endpoint_parameter = cast(Parameter, self.client.endpoint_parameter)
86
+ retval.extend(
87
+ [
88
+ '_cloud = kwargs.pop("cloud_setting", None) or settings.current.azure_cloud # type: ignore',
89
+ "_endpoints = get_arm_endpoints(_cloud)",
90
+ f"if not {endpoint_parameter.client_name}:",
91
+ f' {endpoint_parameter.client_name} = _endpoints["resource_manager"]',
92
+ 'credential_scopes = kwargs.pop("credential_scopes", _endpoints["credential_scopes"])',
93
+ ]
94
+ )
81
95
  config_name = f"{self.client.name}Configuration"
82
96
  config_call = ", ".join(
83
97
  [
84
- f"{p.client_name}={p.client_name}"
98
+ (
99
+ f"{p.client_name}="
100
+ + (
101
+ f"cast(str, {p.client_name})"
102
+ if self.client.need_cloud_setting and p.location == ParameterLocation.ENDPOINT_PATH
103
+ else p.client_name
104
+ )
105
+ )
85
106
  for p in self.client.config.parameters.method
86
107
  if p.method_location != ParameterMethodLocation.KWARG
87
108
  ]
109
+ + additional_signatures
88
110
  + ["**kwargs"]
89
111
  )
90
- return f"self._config = {config_name}({config_call})"
112
+ retval.append(f"self._config = {config_name}({config_call})")
113
+ return retval
91
114
 
92
115
  @property
93
116
  def host_variable_name(self) -> str:
@@ -104,8 +127,11 @@ class ClientSerializer:
104
127
  result = []
105
128
  pipeline_client_name = self.client.pipeline_class(async_mode)
106
129
  endpoint_name = "base_url" if self.client.code_model.is_azure_flavor else "endpoint"
130
+ host_variable_name = (
131
+ f"cast(str, {self.host_variable_name})" if self.client.need_cloud_setting else self.host_variable_name
132
+ )
107
133
  params = {
108
- endpoint_name: self.host_variable_name,
134
+ endpoint_name: host_variable_name,
109
135
  "policies": "_policies",
110
136
  }
111
137
  if not self.client.code_model.is_legacy and self.client.request_id_header_name:
@@ -16,13 +16,29 @@ from ..models.utils import NamespaceType
16
16
  from .client_serializer import ClientSerializer, ConfigSerializer
17
17
  from .base_serializer import BaseSerializer
18
18
 
19
+ VERSION_MAP = {
20
+ "msrest": "0.7.1",
21
+ "isodate": "0.6.1",
22
+ "azure-mgmt-core": "1.5.0",
23
+ "azure-core": "1.30.0",
24
+ "typing-extensions": "4.6.0",
25
+ "corehttp": "1.0.0b6",
26
+ }
27
+
28
+ MIN_PYTHON_VERSION = "3.9"
29
+ MAX_PYTHON_VERSION = "3.12"
30
+
19
31
 
20
32
  class GeneralSerializer(BaseSerializer):
21
33
  """General serializer for SDK root level files"""
22
34
 
23
35
  def serialize_setup_file(self) -> str:
24
36
  template = self.env.get_template("packaging_templates/setup.py.jinja2")
25
- params = {}
37
+ params = {
38
+ "VERSION_MAP": VERSION_MAP,
39
+ "MIN_PYTHON_VERSION": MIN_PYTHON_VERSION,
40
+ "MAX_PYTHON_VERSION": MAX_PYTHON_VERSION,
41
+ }
26
42
  params.update(self.code_model.options)
27
43
  return template.render(code_model=self.code_model, **params)
28
44
 
@@ -48,6 +64,9 @@ class GeneralSerializer(BaseSerializer):
48
64
  "pkgutil_names": [".".join(package_parts[: i + 1]) for i in range(len(package_parts))],
49
65
  "init_names": ["/".join(package_parts[: i + 1]) + "/__init__.py" for i in range(len(package_parts))],
50
66
  "client_name": self.code_model.clients[0].name,
67
+ "VERSION_MAP": VERSION_MAP,
68
+ "MIN_PYTHON_VERSION": MIN_PYTHON_VERSION,
69
+ "MAX_PYTHON_VERSION": MAX_PYTHON_VERSION,
51
70
  }
52
71
  params.update(self.code_model.options)
53
72
  params.update(kwargs)
@@ -62,7 +62,7 @@ class SampleSerializer(BaseSerializer):
62
62
  ImportType.SDKCORE,
63
63
  )
64
64
  for param in self.operation.parameters.positional + self.operation.parameters.keyword_only:
65
- if not param.client_default_value and not param.optional and param.wire_name in self.sample_params:
65
+ if param.client_default_value is None and not param.optional and param.wire_name in self.sample_params:
66
66
  imports.merge(param.type.imports_for_sample())
67
67
  return FileImportSerializer(imports, True)
68
68
 
@@ -80,7 +80,7 @@ class SampleSerializer(BaseSerializer):
80
80
  for p in (
81
81
  self.code_model.clients[0].parameters.positional + self.code_model.clients[0].parameters.keyword_only
82
82
  )
83
- if not (p.optional or p.client_default_value)
83
+ if not p.optional and p.client_default_value is None
84
84
  ]
85
85
  client_params = {
86
86
  p.client_name: special_param.get(
@@ -9,7 +9,7 @@
9
9
  {% if client.has_parameterized_host %}
10
10
  {{ serializer.host_variable_name }} = {{ keywords.escape_str(client.url) }}
11
11
  {% endif %}
12
- {{ serializer.initialize_config() }}
12
+ {{ op_tools.serialize(serializer.initialize_config()) | indent(8) }}
13
13
  {{ op_tools.serialize(serializer.initialize_pipeline_client(async_mode)) | indent(8) }}
14
14
 
15
15
  {{ op_tools.serialize(serializer.serializers_and_operation_groups_properties()) | indent(8) }}
@@ -21,14 +21,8 @@ class {{ client.name }}Configuration: {{ client.config.pylint_disable() }}
21
21
  {% if serializer.set_constants() %}
22
22
  {{ op_tools.serialize(serializer.set_constants()) | indent(8) -}}
23
23
  {% endif %}
24
- {% if client.credential %}
25
- {% set cred_scopes = client.credential.type if client.credential.type.policy is defined and client.credential.type.policy.credential_scopes is defined %}
26
- {% if not cred_scopes %}
27
- {% set cred_scopes = client.credential.type.types | selectattr("policy.credential_scopes") | first if client.credential.type.types is defined %}
28
- {% endif %}
29
- {% if cred_scopes %}
30
- self.credential_scopes = kwargs.pop('credential_scopes', {{ cred_scopes.policy.credential_scopes }})
31
- {% endif %}
24
+ {% if client.credential_scopes is not none %}
25
+ self.credential_scopes = kwargs.pop('credential_scopes', {{ client.credential_scopes }})
32
26
  {% endif %}
33
27
  kwargs.setdefault('sdk_moniker', '{{ client.config.sdk_moniker }}/{}'.format(VERSION))
34
28
  self.polling_interval = kwargs.get("polling_interval", 30)
@@ -1,4 +1,6 @@
1
1
  # coding=utf-8
2
+ {% set min_version = MIN_PYTHON_VERSION.split('.')[1] | int %}
3
+ {% set max_version = MAX_PYTHON_VERSION.split('.')[1] | int %}
2
4
  {% if code_model.license_header %}
3
5
  {{ code_model.license_header }}
4
6
  {% endif %}
@@ -67,10 +69,9 @@ setup(
67
69
  "Programming Language :: Python",
68
70
  "Programming Language :: Python :: 3 :: Only",
69
71
  "Programming Language :: Python :: 3",
70
- "Programming Language :: Python :: 3.9",
71
- "Programming Language :: Python :: 3.10",
72
- "Programming Language :: Python :: 3.11",
73
- "Programming Language :: Python :: 3.12",
72
+ {% for version in range(min_version, max_version + 1) %}
73
+ "Programming Language :: Python :: 3.{{ version }}",
74
+ {% endfor %}
74
75
  "License :: OSI Approved :: MIT License",
75
76
  ],
76
77
  zip_safe=False,
@@ -95,21 +96,21 @@ setup(
95
96
  {% endif %}
96
97
  install_requires=[
97
98
  {% if code_model.is_legacy %}
98
- "msrest>=0.7.1",
99
+ "msrest>={{ VERSION_MAP["msrest"] }}",
99
100
  {% else %}
100
- "isodate>=0.6.1",
101
+ "isodate>={{ VERSION_MAP["isodate"] }}",
101
102
  {% endif %}
102
103
  {% if azure_arm %}
103
- "azure-mgmt-core>=1.3.2",
104
+ "azure-mgmt-core>={{ VERSION_MAP["azure-mgmt-core"] }}",
104
105
  {% elif code_model.is_azure_flavor %}
105
- "azure-core>=1.30.0",
106
+ "azure-core>={{ VERSION_MAP["azure-core"] }}",
106
107
  {% else %}
107
- "corehttp[requests]",
108
+ "corehttp[requests]>={{ VERSION_MAP["corehttp"] }}",
108
109
  {% endif %}
109
- "typing-extensions>=4.6.0",
110
+ "typing-extensions>={{ VERSION_MAP['typing-extensions'] }}",
110
111
  ],
111
112
  {% if package_mode %}
112
- python_requires=">=3.9",
113
+ python_requires=">={{ MIN_PYTHON_VERSION }}",
113
114
  {% else %}
114
115
  long_description="""\
115
116
  {{ code_model.description }}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autorest/python",
3
- "version": "6.32.3",
3
+ "version": "6.33.0",
4
4
  "description": "The Python extension for generators in AutoRest.",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "homepage": "https://github.com/Azure/autorest.python/blob/main/README.md",
21
21
  "dependencies": {
22
- "@typespec/http-client-python": "~0.9.2",
22
+ "@typespec/http-client-python": "~0.10.0",
23
23
  "@autorest/system-requirements": "~1.0.2",
24
24
  "fs-extra": "~11.2.0",
25
25
  "tsx": "~4.19.1"