From 9317dde2d3df38f5f91fb2a34401c4bda403e228 Mon Sep 17 00:00:00 2001 From: azure-sdk Date: Wed, 29 Jul 2026 17:38:19 +0000 Subject: [PATCH 1/3] Configurations: 'specification/edgezones/EdgeZones.Management/tspconfig.yaml', SDK Release Type: stable, and CommitSHA: 'b11c849d192da49ae3d359f8b16d422f65850666' in SpecRepo: 'https://github.com/Azure/azure-rest-api-specs' Pipeline run: https://dev.azure.com/azure-sdk/internal/_build/results?buildId=6635035 Refer to https://eng.ms/docs/products/azure-developer-experience/develop/sdk-release/sdk-release-prerequisites to prepare for SDK release. --- .../azure-mgmt-edgezones/CHANGELOG.md | 6 + .../azure-mgmt-edgezones/MANIFEST.in | 9 +- sdk/edgezones/azure-mgmt-edgezones/README.md | 6 +- sdk/edgezones/azure-mgmt-edgezones/_meta.json | 6 - .../azure-mgmt-edgezones/_metadata.json | 11 + sdk/edgezones/azure-mgmt-edgezones/api.md | 310 +++++++ .../azure-mgmt-edgezones/api.metadata.yml | 3 + .../apiview-properties.json | 18 +- .../azure-mgmt-edgezones/azure/__init__.py | 2 +- .../azure/mgmt/__init__.py | 2 +- .../azure/mgmt/edgezones/_client.py | 44 +- .../azure/mgmt/edgezones/_configuration.py | 16 +- .../azure/mgmt/edgezones/_patch.py | 13 +- .../azure/mgmt/edgezones/_utils/__init__.py | 6 + .../{_model_base.py => _utils/model_base.py} | 806 +++++++++++++++--- .../serialization.py} | 207 ++++- .../azure/mgmt/edgezones/_version.py | 2 +- .../azure/mgmt/edgezones/aio/_client.py | 46 +- .../mgmt/edgezones/aio/_configuration.py | 16 +- .../azure/mgmt/edgezones/aio/_patch.py | 13 +- .../edgezones/aio/operations/_operations.py | 73 +- .../mgmt/edgezones/aio/operations/_patch.py | 13 +- .../azure/mgmt/edgezones/models/_enums.py | 16 +- .../azure/mgmt/edgezones/models/_models.py | 37 +- .../azure/mgmt/edgezones/models/_patch.py | 13 +- .../mgmt/edgezones/operations/_operations.py | 87 +- .../azure/mgmt/edgezones/operations/_patch.py | 13 +- .../generated_samples/extended_zones_get.py | 2 +- .../extended_zones_list_by_subscription.py | 2 +- .../extended_zones_register.py | 2 +- .../extended_zones_unregister.py | 2 +- .../generated_samples/operations_list.py | 2 +- .../azure-mgmt-edgezones/pyproject.toml | 82 ++ .../azure-mgmt-edgezones/sdk_packaging.toml | 12 - sdk/edgezones/azure-mgmt-edgezones/setup.py | 83 -- .../azure-mgmt-edgezones/tsp-location.yaml | 2 +- 36 files changed, 1542 insertions(+), 441 deletions(-) delete mode 100644 sdk/edgezones/azure-mgmt-edgezones/_meta.json create mode 100644 sdk/edgezones/azure-mgmt-edgezones/_metadata.json create mode 100644 sdk/edgezones/azure-mgmt-edgezones/api.md create mode 100644 sdk/edgezones/azure-mgmt-edgezones/api.metadata.yml create mode 100644 sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/__init__.py rename sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/{_model_base.py => _utils/model_base.py} (57%) rename sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/{_serialization.py => _utils/serialization.py} (91%) delete mode 100644 sdk/edgezones/azure-mgmt-edgezones/sdk_packaging.toml delete mode 100644 sdk/edgezones/azure-mgmt-edgezones/setup.py diff --git a/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md b/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md index 91ba2f109b91..104cf602ecd0 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md +++ b/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md @@ -1,5 +1,11 @@ # Release History +## 1.0.0 (2026-07-29) + +### Features Added + + - Client `EdgeZonesMgmtClient` added parameter `cloud_setting` in method `__init__` + ## 1.0.0b2 (2025-04-01) ### Other Changes diff --git a/sdk/edgezones/azure-mgmt-edgezones/MANIFEST.in b/sdk/edgezones/azure-mgmt-edgezones/MANIFEST.in index 670c5ad792f6..bcb4fe9630ea 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/MANIFEST.in +++ b/sdk/edgezones/azure-mgmt-edgezones/MANIFEST.in @@ -1,8 +1,7 @@ -include _meta.json -recursive-include tests *.py *.json -recursive-include samples *.py *.md include *.md -include azure/__init__.py -include azure/mgmt/__init__.py include LICENSE include azure/mgmt/edgezones/py.typed +recursive-include tests *.py +recursive-include samples *.py *.md +include azure/__init__.py +include azure/mgmt/__init__.py diff --git a/sdk/edgezones/azure-mgmt-edgezones/README.md b/sdk/edgezones/azure-mgmt-edgezones/README.md index dc37925b6891..5ae58eb2413a 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/README.md +++ b/sdk/edgezones/azure-mgmt-edgezones/README.md @@ -1,7 +1,7 @@ # Microsoft Azure SDK for Python This is the Microsoft Azure Edgezones Management Client Library. -This package has been tested with Python 3.8+. +This package has been tested with Python 3.10+. For a more complete view of Azure libraries, see the [azure sdk python release](https://aka.ms/azsdk/python/all). ## _Disclaimer_ @@ -12,7 +12,7 @@ _Azure SDK Python packages support for Python 2.7 has ended 01 January 2022. For ### Prerequisites -- Python 3.8+ is required to use this package. +- Python 3.10+ is required to use this package. - [Azure subscription](https://azure.microsoft.com/free/) ### Install the package @@ -24,7 +24,7 @@ pip install azure-identity ### Authentication -By default, [Azure Active Directory](https://aka.ms/awps/aad) token authentication depends on correct configuration of the following environment variables. +By default, [Microsoft Entra](https://learn.microsoft.com/entra/fundamentals/what-is-entra) token authentication depends on correct configuration of the following environment variables. - `AZURE_CLIENT_ID` for Azure client ID. - `AZURE_TENANT_ID` for Azure tenant ID. diff --git a/sdk/edgezones/azure-mgmt-edgezones/_meta.json b/sdk/edgezones/azure-mgmt-edgezones/_meta.json deleted file mode 100644 index e604bbb8d3a2..000000000000 --- a/sdk/edgezones/azure-mgmt-edgezones/_meta.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "commit": "3db6867b8e524ea6d1bc7a3bbb989fe50dd2f184", - "repository_url": "https://github.com/Azure/azure-rest-api-specs", - "typespec_src": "specification/edgezones/EdgeZones.Management", - "@azure-tools/typespec-python": "0.41.0" -} \ No newline at end of file diff --git a/sdk/edgezones/azure-mgmt-edgezones/_metadata.json b/sdk/edgezones/azure-mgmt-edgezones/_metadata.json new file mode 100644 index 000000000000..026d5c6ddb34 --- /dev/null +++ b/sdk/edgezones/azure-mgmt-edgezones/_metadata.json @@ -0,0 +1,11 @@ +{ + "apiVersion": "2026-10-01", + "apiVersions": { + "Microsoft.EdgeZones": "2026-10-01" + }, + "commit": "b11c849d192da49ae3d359f8b16d422f65850666", + "repository_url": "https://github.com/Azure/azure-rest-api-specs", + "typespec_src": "specification/edgezones/EdgeZones.Management", + "emitterVersion": "0.63.3", + "httpClientPythonVersion": "^0.34.2" +} \ No newline at end of file diff --git a/sdk/edgezones/azure-mgmt-edgezones/api.md b/sdk/edgezones/azure-mgmt-edgezones/api.md new file mode 100644 index 000000000000..53028d767fa0 --- /dev/null +++ b/sdk/edgezones/azure-mgmt-edgezones/api.md @@ -0,0 +1,310 @@ +```py +namespace azure.mgmt.edgezones + + class azure.mgmt.edgezones.EdgeZonesMgmtClient: implements ContextManager + extended_zones: ExtendedZonesOperations + operations: Operations + + def __init__( + self, + credential: TokenCredential, + subscription_id: str, + base_url: Optional[str] = None, + *, + api_version: str = ..., + cloud_setting: Optional[AzureClouds] = ..., + **kwargs: Any + ) -> None: ... + + def close(self) -> None: ... + + def send_request( + self, + request: HttpRequest, + *, + stream: bool = False, + **kwargs: Any + ) -> HttpResponse: ... + + +namespace azure.mgmt.edgezones.aio + + class azure.mgmt.edgezones.aio.EdgeZonesMgmtClient: implements AsyncContextManager + extended_zones: ExtendedZonesOperations + operations: Operations + + def __init__( + self, + credential: AsyncTokenCredential, + subscription_id: str, + base_url: Optional[str] = None, + *, + api_version: str = ..., + cloud_setting: Optional[AzureClouds] = ..., + **kwargs: Any + ) -> None: ... + + async def close(self) -> None: ... + + def send_request( + self, + request: HttpRequest, + *, + stream: bool = False, + **kwargs: Any + ) -> Awaitable[AsyncHttpResponse]: ... + + +namespace azure.mgmt.edgezones.aio.operations + + class azure.mgmt.edgezones.aio.operations.ExtendedZonesOperations: + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + @distributed_trace_async + async def get( + self, + extended_zone_name: str, + **kwargs: Any + ) -> ExtendedZone: ... + + @distributed_trace + def list_by_subscription(self, **kwargs: Any) -> AsyncItemPaged[ExtendedZone]: ... + + @distributed_trace_async + async def register( + self, + extended_zone_name: str, + **kwargs: Any + ) -> ExtendedZone: ... + + @distributed_trace_async + async def unregister( + self, + extended_zone_name: str, + **kwargs: Any + ) -> ExtendedZone: ... + + + class azure.mgmt.edgezones.aio.operations.Operations: + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + @distributed_trace + def list(self, **kwargs: Any) -> AsyncItemPaged[Operation]: ... + + +namespace azure.mgmt.edgezones.models + + class azure.mgmt.edgezones.models.ActionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + INTERNAL = "Internal" + + + class azure.mgmt.edgezones.models.CreatedByType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + APPLICATION = "Application" + KEY = "Key" + MANAGED_IDENTITY = "ManagedIdentity" + USER = "User" + + + class azure.mgmt.edgezones.models.ErrorAdditionalInfo(_Model): + info: Optional[Any] + type: Optional[str] + + + class azure.mgmt.edgezones.models.ErrorDetail(_Model): + additional_info: Optional[list[ErrorAdditionalInfo]] + code: Optional[str] + details: Optional[list[ErrorDetail]] + message: Optional[str] + target: Optional[str] + + + class azure.mgmt.edgezones.models.ErrorResponse(_Model): + error: Optional[ErrorDetail] + + @overload + def __init__( + self, + *, + error: Optional[ErrorDetail] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.mgmt.edgezones.models.ExtendedZone(ProxyResource): + id: str + name: str + properties: Optional[ExtendedZoneProperties] + system_data: SystemData + type: str + + @overload + def __init__( + self, + *, + properties: Optional[ExtendedZoneProperties] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.mgmt.edgezones.models.ExtendedZoneProperties(_Model): + display_name: str + geography: str + geography_group: str + home_location: str + latitude: str + longitude: str + provisioning_state: Optional[Union[str, ProvisioningState]] + region_category: str + region_type: str + regional_display_name: str + registration_state: Optional[Union[str, RegistrationState]] + + + class azure.mgmt.edgezones.models.Operation(_Model): + action_type: Optional[Union[str, ActionType]] + display: Optional[OperationDisplay] + is_data_action: Optional[bool] + name: Optional[str] + origin: Optional[Union[str, Origin]] + + @overload + def __init__( + self, + *, + display: Optional[OperationDisplay] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.mgmt.edgezones.models.OperationDisplay(_Model): + description: Optional[str] + operation: Optional[str] + provider: Optional[str] + resource: Optional[str] + + + class azure.mgmt.edgezones.models.Origin(str, Enum, metaclass=CaseInsensitiveEnumMeta): + SYSTEM = "system" + USER = "user" + USER_SYSTEM = "user,system" + + + class azure.mgmt.edgezones.models.ProvisioningState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ACCEPTED = "Accepted" + CANCELED = "Canceled" + DELETING = "Deleting" + FAILED = "Failed" + PROVISIONING = "Provisioning" + SUCCEEDED = "Succeeded" + UPDATING = "Updating" + + + class azure.mgmt.edgezones.models.ProxyResource(Resource): + id: str + name: str + system_data: SystemData + type: str + + + class azure.mgmt.edgezones.models.RegistrationState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + NOT_REGISTERED = "NotRegistered" + PENDING_REGISTER = "PendingRegister" + PENDING_UNREGISTER = "PendingUnregister" + REGISTERED = "Registered" + + + class azure.mgmt.edgezones.models.Resource(_Model): + id: Optional[str] + name: Optional[str] + system_data: Optional[SystemData] + type: Optional[str] + + + class azure.mgmt.edgezones.models.SystemData(_Model): + created_at: Optional[datetime] + created_by: Optional[str] + created_by_type: Optional[Union[str, CreatedByType]] + last_modified_at: Optional[datetime] + last_modified_by: Optional[str] + last_modified_by_type: Optional[Union[str, CreatedByType]] + + @overload + def __init__( + self, + *, + created_at: Optional[datetime] = ..., + created_by: Optional[str] = ..., + created_by_type: Optional[Union[str, CreatedByType]] = ..., + last_modified_at: Optional[datetime] = ..., + last_modified_by: Optional[str] = ..., + last_modified_by_type: Optional[Union[str, CreatedByType]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + +namespace azure.mgmt.edgezones.operations + + class azure.mgmt.edgezones.operations.ExtendedZonesOperations: + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + @distributed_trace + def get( + self, + extended_zone_name: str, + **kwargs: Any + ) -> ExtendedZone: ... + + @distributed_trace + def list_by_subscription(self, **kwargs: Any) -> ItemPaged[ExtendedZone]: ... + + @distributed_trace + def register( + self, + extended_zone_name: str, + **kwargs: Any + ) -> ExtendedZone: ... + + @distributed_trace + def unregister( + self, + extended_zone_name: str, + **kwargs: Any + ) -> ExtendedZone: ... + + + class azure.mgmt.edgezones.operations.Operations: + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + @distributed_trace + def list(self, **kwargs: Any) -> ItemPaged[Operation]: ... + + +``` \ No newline at end of file diff --git a/sdk/edgezones/azure-mgmt-edgezones/api.metadata.yml b/sdk/edgezones/azure-mgmt-edgezones/api.metadata.yml new file mode 100644 index 000000000000..2a7b289ce8db --- /dev/null +++ b/sdk/edgezones/azure-mgmt-edgezones/api.metadata.yml @@ -0,0 +1,3 @@ +apiMdSha256: 546c2eb05ed36362c6c5fb3c2d13fcb626e7d581daa5136e7af69b43e9807c5d +parserVersion: 0.3.30 +pythonVersion: 3.13.14 diff --git a/sdk/edgezones/azure-mgmt-edgezones/apiview-properties.json b/sdk/edgezones/azure-mgmt-edgezones/apiview-properties.json index f18790aeac62..48f2f7f41ca1 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/apiview-properties.json +++ b/sdk/edgezones/azure-mgmt-edgezones/apiview-properties.json @@ -16,10 +16,16 @@ "azure.mgmt.edgezones.models.CreatedByType": "Azure.ResourceManager.CommonTypes.createdByType", "azure.mgmt.edgezones.models.ProvisioningState": "Microsoft.EdgeZones.ProvisioningState", "azure.mgmt.edgezones.models.RegistrationState": "Microsoft.EdgeZones.RegistrationState", - "azure.mgmt.edgezones.EdgeZonesMgmtClient.operations.list": "Azure.ResourceManager.Operations.list", - "azure.mgmt.edgezones.EdgeZonesMgmtClient.extended_zones.get": "Microsoft.EdgeZones.ExtendedZones.get", - "azure.mgmt.edgezones.EdgeZonesMgmtClient.extended_zones.list_by_subscription": "Microsoft.EdgeZones.ExtendedZones.listBySubscription", - "azure.mgmt.edgezones.EdgeZonesMgmtClient.extended_zones.register": "Microsoft.EdgeZones.ExtendedZones.register", - "azure.mgmt.edgezones.EdgeZonesMgmtClient.extended_zones.unregister": "Microsoft.EdgeZones.ExtendedZones.unregister" - } + "azure.mgmt.edgezones.operations.Operations.list": "Azure.ResourceManager.Operations.list", + "azure.mgmt.edgezones.aio.operations.Operations.list": "Azure.ResourceManager.Operations.list", + "azure.mgmt.edgezones.operations.ExtendedZonesOperations.get": "Microsoft.EdgeZones.ExtendedZones.get", + "azure.mgmt.edgezones.aio.operations.ExtendedZonesOperations.get": "Microsoft.EdgeZones.ExtendedZones.get", + "azure.mgmt.edgezones.operations.ExtendedZonesOperations.list_by_subscription": "Microsoft.EdgeZones.ExtendedZones.listBySubscription", + "azure.mgmt.edgezones.aio.operations.ExtendedZonesOperations.list_by_subscription": "Microsoft.EdgeZones.ExtendedZones.listBySubscription", + "azure.mgmt.edgezones.operations.ExtendedZonesOperations.register": "Microsoft.EdgeZones.ExtendedZones.register", + "azure.mgmt.edgezones.aio.operations.ExtendedZonesOperations.register": "Microsoft.EdgeZones.ExtendedZones.register", + "azure.mgmt.edgezones.operations.ExtendedZonesOperations.unregister": "Microsoft.EdgeZones.ExtendedZones.unregister", + "azure.mgmt.edgezones.aio.operations.ExtendedZonesOperations.unregister": "Microsoft.EdgeZones.ExtendedZones.unregister" + }, + "CrossLanguageVersion": "cebec8fdf5a4" } \ No newline at end of file diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/__init__.py b/sdk/edgezones/azure-mgmt-edgezones/azure/__init__.py index 8db66d3d0f0f..d55ccad1f573 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/__init__.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/__init__.py @@ -1 +1 @@ -__path__ = __import__("pkgutil").extend_path(__path__, __name__) +__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/__init__.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/__init__.py index 8db66d3d0f0f..d55ccad1f573 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/__init__.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/__init__.py @@ -1 +1 @@ -__path__ = __import__("pkgutil").extend_path(__path__, __name__) +__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_client.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_client.py index 04ce188c2ce9..e810b5efd1cb 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_client.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_client.py @@ -7,19 +7,27 @@ # -------------------------------------------------------------------------- from copy import deepcopy -from typing import Any, TYPE_CHECKING -from typing_extensions import Self +import sys +from typing import Any, Optional, TYPE_CHECKING, cast from azure.core.pipeline import policies from azure.core.rest import HttpRequest, HttpResponse +from azure.core.settings import settings from azure.mgmt.core import ARMPipelineClient from azure.mgmt.core.policies import ARMAutoResourceProviderRegistrationPolicy +from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import EdgeZonesMgmtClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ExtendedZonesOperations, Operations +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # type: ignore + if TYPE_CHECKING: + from azure.core import AzureClouds from azure.core.credentials import TokenCredential @@ -34,11 +42,14 @@ class EdgeZonesMgmtClient: :type credential: ~azure.core.credentials.TokenCredential :param subscription_id: The ID of the target subscription. The value must be an UUID. Required. :type subscription_id: str - :param base_url: Service host. Default value is "https://management.azure.com". + :param base_url: Service host. Default value is None. :type base_url: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-04-01-preview". Note that overriding this default value may result in unsupported - behavior. + :keyword cloud_setting: The cloud setting for which to get the ARM endpoint. Default value is + None. + :paramtype cloud_setting: ~azure.core.AzureClouds + :keyword api_version: The API version to use for this operation. Known values are "2026-10-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -46,13 +57,26 @@ def __init__( self, credential: "TokenCredential", subscription_id: str, - base_url: str = "https://management.azure.com", + base_url: Optional[str] = None, + *, + cloud_setting: Optional["AzureClouds"] = None, **kwargs: Any ) -> None: _endpoint = "{endpoint}" + _cloud = cloud_setting or settings.current.azure_cloud # type: ignore + _endpoints = get_arm_endpoints(_cloud) + if not base_url: + base_url = _endpoints["resource_manager"] + credential_scopes = kwargs.pop("credential_scopes", _endpoints["credential_scopes"]) self._config = EdgeZonesMgmtClientConfiguration( - credential=credential, subscription_id=subscription_id, base_url=base_url, **kwargs + credential=credential, + subscription_id=subscription_id, + base_url=cast(str, base_url), + cloud_setting=cloud_setting, + credential_scopes=credential_scopes, + **kwargs ) + _policies = kwargs.pop("policies", None) if _policies is None: _policies = [ @@ -71,7 +95,7 @@ def __init__( policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, self._config.http_logging_policy, ] - self._client: ARMPipelineClient = ARMPipelineClient(base_url=_endpoint, policies=_policies, **kwargs) + self._client: ARMPipelineClient = ARMPipelineClient(base_url=cast(str, _endpoint), policies=_policies, **kwargs) self._serialize = Serializer() self._deserialize = Deserializer() diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_configuration.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_configuration.py index 48032cd2c19a..66f1e602d6c7 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_configuration.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_configuration.py @@ -6,7 +6,7 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, TYPE_CHECKING +from typing import Any, Optional, TYPE_CHECKING from azure.core.pipeline import policies from azure.mgmt.core.policies import ARMChallengeAuthenticationPolicy, ARMHttpLoggingPolicy @@ -14,6 +14,7 @@ from ._version import VERSION if TYPE_CHECKING: + from azure.core import AzureClouds from azure.core.credentials import TokenCredential @@ -29,9 +30,12 @@ class EdgeZonesMgmtClientConfiguration: # pylint: disable=too-many-instance-att :type subscription_id: str :param base_url: Service host. Default value is "https://management.azure.com". :type base_url: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-04-01-preview". Note that overriding this default value may result in unsupported - behavior. + :param cloud_setting: The cloud setting for which to get the ARM endpoint. Default value is + None. + :type cloud_setting: ~azure.core.AzureClouds + :keyword api_version: The API version to use for this operation. Known values are "2026-10-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -40,9 +44,10 @@ def __init__( credential: "TokenCredential", subscription_id: str, base_url: str = "https://management.azure.com", + cloud_setting: Optional["AzureClouds"] = None, **kwargs: Any ) -> None: - api_version: str = kwargs.pop("api_version", "2024-04-01-preview") + api_version: str = kwargs.pop("api_version", "2026-10-01") if credential is None: raise ValueError("Parameter 'credential' must not be None.") @@ -52,6 +57,7 @@ def __init__( self.credential = credential self.subscription_id = subscription_id self.base_url = base_url + self.cloud_setting = cloud_setting self.api_version = api_version self.credential_scopes = kwargs.pop("credential_scopes", ["https://management.azure.com/.default"]) kwargs.setdefault("sdk_moniker", "mgmt-edgezones/{}".format(VERSION)) diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_patch.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_patch.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/__init__.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/__init__.py new file mode 100644 index 000000000000..8026245c2abc --- /dev/null +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_model_base.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/model_base.py similarity index 57% rename from sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_model_base.py rename to sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/model_base.py index 3072ee252ed9..0f2c5bdfe70f 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_model_base.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/model_base.py @@ -1,9 +1,10 @@ -# pylint: disable=too-many-lines +# pylint: disable=line-too-long,useless-suppression,too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- # pylint: disable=protected-access, broad-except @@ -21,17 +22,19 @@ from datetime import datetime, date, time, timedelta, timezone from json import JSONEncoder import xml.etree.ElementTree as ET -from typing_extensions import Self +from collections.abc import MutableMapping import isodate from azure.core.exceptions import DeserializationError from azure.core import CaseInsensitiveEnumMeta from azure.core.pipeline import PipelineResponse from azure.core.serialization import _Null -if sys.version_info >= (3, 9): - from collections.abc import MutableMapping +from azure.core.rest import HttpResponse + +if sys.version_info >= (3, 11): + from typing import Self else: - from typing import MutableMapping + from typing_extensions import Self _LOGGER = logging.getLogger(__name__) @@ -39,6 +42,7 @@ TZ_UTC = timezone.utc _T = typing.TypeVar("_T") +_NONE_TYPE = type(None) def _timedelta_as_isostr(td: timedelta) -> str: @@ -105,6 +109,29 @@ def _serialize_bytes(o, format: typing.Optional[str] = None) -> str: return encoded +def _serialize_duration(td: timedelta, format: typing.Optional[str] = None): + """Serialize a timedelta to its wire representation. + + For the ``seconds``/``milliseconds`` encodings the value is converted to a + numeric value, otherwise it falls back to an ISO 8601 duration string. + + :param timedelta td: The timedelta to serialize. + :param str format: The duration encoding format. + :rtype: int or float or str + :return: serialized duration + """ + seconds = td.total_seconds() + if format == "duration-seconds-int": + return int(seconds) + if format == "duration-seconds-float": + return seconds + if format == "duration-milliseconds-int": + return int(seconds * 1000) + if format == "duration-milliseconds-float": + return seconds * 1000 + return _timedelta_as_isostr(td) + + def _serialize_datetime(o, format: typing.Optional[str] = None): if hasattr(o, "year") and hasattr(o, "hour"): if format == "rfc7231": @@ -173,6 +200,21 @@ def default(self, o): # pylint: disable=too-many-return-statements r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT" ) +_ARRAY_ENCODE_MAPPING = { + "pipeDelimited": "|", + "spaceDelimited": " ", + "commaDelimited": ",", + "newlineDelimited": "\n", +} + + +def _deserialize_array_encoded(delimit: str, attr): + if isinstance(attr, str): + if attr == "": + return [] + return attr.split(delimit) + return attr + def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: """Deserialize ISO-8601 formatted string into Datetime object. @@ -204,7 +246,7 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: test_utc = date_obj.utctimetuple() if test_utc.tm_year > 9999 or test_utc.tm_year < 1: raise OverflowError("Hit max or min date") - return date_obj + return date_obj # type: ignore[no-any-return] def _deserialize_datetime_rfc7231(attr: typing.Union[str, datetime]) -> datetime: @@ -258,7 +300,7 @@ def _deserialize_time(attr: typing.Union[str, time]) -> time: """ if isinstance(attr, time): return attr - return isodate.parse_time(attr) + return isodate.parse_time(attr) # type: ignore[no-any-return] def _deserialize_bytes(attr): @@ -282,6 +324,12 @@ def _deserialize_duration(attr): return isodate.parse_duration(attr) +def _deserialize_duration_numeric(attr, unit): + if isinstance(attr, timedelta): + return attr + return timedelta(**{unit: float(attr)}) + + def _deserialize_decimal(attr): if isinstance(attr, decimal.Decimal): return attr @@ -311,12 +359,18 @@ def _deserialize_int_as_str(attr): "unix-timestamp": _deserialize_datetime_unix_timestamp, "base64": _deserialize_bytes, "base64url": _deserialize_bytes_base64, + "duration-seconds-int": functools.partial(_deserialize_duration_numeric, unit="seconds"), + "duration-seconds-float": functools.partial(_deserialize_duration_numeric, unit="seconds"), + "duration-milliseconds-int": functools.partial(_deserialize_duration_numeric, unit="milliseconds"), + "duration-milliseconds-float": functools.partial(_deserialize_duration_numeric, unit="milliseconds"), } def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): if annotation is int and rf and rf._format == "str": return _deserialize_int_as_str + if annotation is str and rf and rf._format in _ARRAY_ENCODE_MAPPING: + return functools.partial(_deserialize_array_encoded, _ARRAY_ENCODE_MAPPING[rf._format]) if rf and rf._format: return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore @@ -347,17 +401,47 @@ def _get_model(module_name: str, model_name: str): _UNSET = object() -class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=unsubscriptable-object - def __init__(self, data: typing.Dict[str, typing.Any]) -> None: +class _MyMutableMapping(MutableMapping[str, typing.Any]): + def __init__(self, data: dict[str, typing.Any]) -> None: self._data = data def __contains__(self, key: typing.Any) -> bool: return key in self._data def __getitem__(self, key: str) -> typing.Any: + # If this key has been deserialized (for mutable types), we need to handle serialization + if hasattr(self, "_attr_to_rest_field"): + cache_attr = f"_deserialized_{key}" + if hasattr(self, cache_attr): + rf = _get_rest_field(getattr(self, "_attr_to_rest_field"), key) + if rf: + value = self._data.get(key) + if isinstance(value, (dict, list, set)): + # For mutable types, serialize and return + # But also update _data with serialized form and clear flag + # so mutations via this returned value affect _data + serialized = _serialize(value, rf._format) + # If serialized form is same type (no transformation needed), + # return _data directly so mutations work + if isinstance(serialized, type(value)) and serialized == value: + return self._data.get(key) + # Otherwise return serialized copy and clear flag + try: + object.__delattr__(self, cache_attr) + except AttributeError: + pass + # Store serialized form back + self._data[key] = serialized + return serialized return self._data.__getitem__(key) def __setitem__(self, key: str, value: typing.Any) -> None: + # Clear any cached deserialized value when setting through dictionary access + cache_attr = f"_deserialized_{key}" + try: + object.__delattr__(self, cache_attr) + except AttributeError: + pass self._data.__setitem__(key, value) def __delitem__(self, key: str) -> None: @@ -374,21 +458,21 @@ def __ne__(self, other: typing.Any) -> bool: def keys(self) -> typing.KeysView[str]: """ - :returns: a set-like object providing a view on D's keys + :returns: a set-like object providing a view on the mapping's keys :rtype: ~typing.KeysView """ return self._data.keys() def values(self) -> typing.ValuesView[typing.Any]: """ - :returns: an object providing a view on D's values + :returns: an object providing a view on the mapping's values :rtype: ~typing.ValuesView """ return self._data.values() def items(self) -> typing.ItemsView[str, typing.Any]: """ - :returns: set-like object providing a view on D's items + :returns: a set-like object providing a view on the mapping's items :rtype: ~typing.ItemsView """ return self._data.items() @@ -398,7 +482,7 @@ def get(self, key: str, default: typing.Any = None) -> typing.Any: Get the value for key if key is in the dictionary, else default. :param str key: The key to look up. :param any default: The value to return if key is not in the dictionary. Defaults to None - :returns: D[k] if k in D, else d. + :returns: The value for key if key is in the dictionary, else default. :rtype: any """ try: @@ -407,13 +491,13 @@ def get(self, key: str, default: typing.Any = None) -> typing.Any: return default @typing.overload - def pop(self, key: str) -> typing.Any: ... + def pop(self, key: str) -> typing.Any: ... # pylint: disable=arguments-differ @typing.overload - def pop(self, key: str, default: _T) -> _T: ... + def pop(self, key: str, default: _T) -> _T: ... # pylint: disable=signature-differs @typing.overload - def pop(self, key: str, default: typing.Any) -> typing.Any: ... + def pop(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any: """ @@ -428,24 +512,24 @@ def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any: return self._data.pop(key) return self._data.pop(key, default) - def popitem(self) -> typing.Tuple[str, typing.Any]: + def popitem(self) -> tuple[str, typing.Any]: """ Removes and returns some (key, value) pair :returns: The (key, value) pair. :rtype: tuple - :raises KeyError: if D is empty. + :raises KeyError: if the dictionary is empty. """ return self._data.popitem() def clear(self) -> None: """ - Remove all items from D. + Remove all items from the dictionary. """ self._data.clear() - def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: + def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: # pylint: disable=arguments-differ """ - Updates D from mapping/iterable E and F. + Update the dictionary from a mapping or an iterable of key-value pairs. :param any args: Either a mapping object or an iterable of key-value pairs. """ self._data.update(*args, **kwargs) @@ -454,14 +538,15 @@ def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: def setdefault(self, key: str, default: None = None) -> None: ... @typing.overload - def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... + def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: """ - Same as calling D.get(k, d), and setting D[k]=d if k not found + Return the value for key if key is in the dictionary; otherwise set the key to + default and return default. :param str key: The key to look up. :param any default: The value to set if key is not in the dictionary - :returns: D[k] if k in D, else d. + :returns: The value for key if key is in the dictionary, else default. :rtype: any """ if default is _UNSET: @@ -469,6 +554,8 @@ def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: return self._data.setdefault(key, default) def __eq__(self, other: typing.Any) -> bool: + if isinstance(other, _MyMutableMapping): + return self._data == other._data try: other_model = self.__class__(other) except Exception: @@ -485,6 +572,8 @@ def _is_model(obj: typing.Any) -> bool: def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements if isinstance(o, list): + if format in _ARRAY_ENCODE_MAPPING and all(isinstance(x, str) for x in o): + return _ARRAY_ENCODE_MAPPING[format].join(o) return [_serialize(x, format) for x in o] if isinstance(o, dict): return {k: _serialize(v, format) for k, v in o.items()} @@ -509,16 +598,14 @@ def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-m pass # Last, try datetime.timedelta try: - return _timedelta_as_isostr(o) + return _serialize_duration(o, format) except AttributeError: # This will be raised when it hits value.total_seconds in the method above pass return o -def _get_rest_field( - attr_to_rest_field: typing.Dict[str, "_RestField"], rest_name: str -) -> typing.Optional["_RestField"]: +def _get_rest_field(attr_to_rest_field: dict[str, "_RestField"], rest_name: str) -> typing.Optional["_RestField"]: try: return next(rf for rf in attr_to_rest_field.values() if rf._rest_name == rest_name) except StopIteration: @@ -537,69 +624,253 @@ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typin return _serialize(value, rf._format) +# ============================================================================ +# Fast-path scalar deserializer functions for rest_field(deserializer=...) +# These are referenced from rest_field declarations to bypass the generic +# _deserialize -> _deserialize_with_callable chain. +# Only simple/primitive types — no models or container types. +# ============================================================================ + + +def _xml_deser_str(value): + if isinstance(value, ET.Element): + return value.text or "" + return str(value) if value is not None else None + + +def _xml_deser_int(value): + if isinstance(value, ET.Element): + return int(value.text) if value.text else None + return int(value) if value is not None else None + + +def _xml_deser_float(value): + if isinstance(value, ET.Element): + return float(value.text) if value.text else None + return float(value) if value is not None else None + + +def _xml_deser_bool(value): + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + if text in (True, False): + return text + return text.lower() == "true" + + +# pylint: disable=docstring-missing-param +def _xml_deser_bytes(value): + """Deserialize bytes from XML (base64).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_bytes(text) + + +def _xml_deser_bytes_base64url(value): + """Deserialize bytes from XML (base64url).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_bytes_base64(text) + + +def _xml_deser_datetime(value): + """Deserialize a datetime from XML (ISO 8601 / rfc3339).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime(text) + + +def _xml_deser_datetime_rfc7231(value): + """Deserialize a datetime from XML (RFC7231 format).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime_rfc7231(text) + + +def _xml_deser_datetime_unix_timestamp(value): + """Deserialize a datetime from XML (Unix timestamp).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime_unix_timestamp(float(text)) + + +def _xml_deser_date(value): + """Deserialize a date from XML (ISO 8601).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_date(text) + + +def _xml_deser_time(value): + """Deserialize a time from XML (ISO 8601).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_time(text) + + +def _xml_deser_duration(value): + """Deserialize a timedelta from XML (ISO 8601 duration).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_duration(text) + + +def _xml_deser_decimal(value): + """Deserialize a Decimal from XML.""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_decimal(text) + + +def _xml_deser_enum_or_str(enum_cls, value): + """Deserialize a Union[EnumType, str] from XML.""" + text = value.text if isinstance(value, ET.Element) else value + if text is None: + return None + try: + return enum_cls(text) + except ValueError: + return text + + +def _extract_xml_model_type(rf_type): + """Extract the concrete Model class from a resolved rf._type partial chain. + + Unwraps ``Optional[Model]`` and ``_deserialize_model(Model, ...)`` + wrappers. Only handles Model and Optional[Model] — other composite + types (List, Dict, Union, etc.) return None and fall through to the + generic ``_deserialize`` path at runtime. + """ + if rf_type is None: + return None + if isinstance(rf_type, type) and _is_model(rf_type): + return rf_type + if not isinstance(rf_type, functools.partial): + return None + func = rf_type.func + args = rf_type.args + if func is _deserialize_with_optional and args: + return _extract_xml_model_type(args[0]) + if func is _deserialize_model and args: + cls = args[0] + return cls if isinstance(cls, type) and _is_model(cls) else None + return None + + +def _build_xml_field_plan( # pylint: disable=docstring-missing-return, docstring-missing-rtype, unused-variable + cls, attr_to_rest_field: dict +) -> list: + """Build a precomputed XML field plan for fast _init_from_xml iteration. + + Called once per model class in __new__. Returns a list of tuples: + (rest_name, xml_name, kind, deser, rf_type, is_optional, items_name) + + kind: 0=wrapped, 1=attribute, 2=unwrapped, 3=text + + For Model and Optional[Model] fields that lack a scalar + ``_deserializer``, this function precomputes the Model class as the + deserializer so ``_init_from_xml`` can call ``ModelClass(element)`` + directly instead of going through the expensive + ``_get_deserialize_callable_from_annotation`` chain at runtime. + """ + model_meta = getattr(cls, "_xml", {}) + model_ns = model_meta.get("ns") or model_meta.get("namespace") + plan = [] + + for rf in attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + deser = rf._deserializer + + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + is_optional = rf._is_optional + + # For Model / Optional[Model] fields without a scalar deserializer, + # precompute the Model class as the deserializer. + if deser is None and rf._type is not None: + model_cls = _extract_xml_model_type(rf._type) + if model_cls is not None: + deser = model_cls + + if prop_meta.get("attribute", False): + plan.append((rf._rest_name, xml_name, 1, deser, rf._type, is_optional, None)) + elif prop_meta.get("unwrapped", False): + items_name = prop_meta.get("itemsName") + if items_name: + items_ns = prop_meta.get("itemsNs") + if items_ns is not None: + xml_ns = items_ns + if xml_ns: + items_name = "{" + xml_ns + "}" + items_name + else: + items_name = xml_name + plan.append((rf._rest_name, xml_name, 2, deser, rf._type, is_optional, items_name)) + elif prop_meta.get("text", False): + plan.append((rf._rest_name, xml_name, 3, deser, rf._type, is_optional, None)) + else: + plan.append((rf._rest_name, xml_name, 0, deser, rf._type, is_optional, None)) + + return plan + + +# pylint: enable=docstring-missing-param class Model(_MyMutableMapping): _is_model = True # label whether current class's _attr_to_rest_field has been calculated # could not see _attr_to_rest_field directly because subclass inherits it from parent class - _calculated: typing.Set[str] = set() + _calculated: set[str] = set() def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: class_name = self.__class__.__name__ if len(args) > 1: raise TypeError(f"{class_name}.__init__() takes 2 positional arguments but {len(args) + 1} were given") - dict_to_pass = { - rest_field._rest_name: rest_field._default - for rest_field in self._attr_to_rest_field.values() - if rest_field._default is not _UNSET - } - if args: # pylint: disable=too-many-nested-blocks + dict_to_pass: dict[str, typing.Any] = {} + if args: if isinstance(args[0], ET.Element): - existed_attr_keys = [] - model_meta = getattr(self, "_xml", {}) - - for rf in self._attr_to_rest_field.values(): - prop_meta = getattr(rf, "_xml", {}) - xml_name = prop_meta.get("name", rf._rest_name) - xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) - if xml_ns: - xml_name = "{" + xml_ns + "}" + xml_name - - # attribute - if prop_meta.get("attribute", False) and args[0].get(xml_name) is not None: - existed_attr_keys.append(xml_name) - dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].get(xml_name)) - continue - - # unwrapped element is array - if prop_meta.get("unwrapped", False): - # unwrapped array could either use prop items meta/prop meta - if prop_meta.get("itemsName"): - xml_name = prop_meta.get("itemsName") - xml_ns = prop_meta.get("itemNs") - if xml_ns: - xml_name = "{" + xml_ns + "}" + xml_name - items = args[0].findall(xml_name) # pyright: ignore - if len(items) > 0: - existed_attr_keys.append(xml_name) - dict_to_pass[rf._rest_name] = _deserialize(rf._type, items) - continue - - # text element is primitive type - if prop_meta.get("text", False): - if args[0].text is not None: - dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].text) - continue - - # wrapped element could be normal property or array, it should only have one element - item = args[0].find(xml_name) - if item is not None: - existed_attr_keys.append(xml_name) - dict_to_pass[rf._rest_name] = _deserialize(rf._type, item) - - # rest thing is additional properties - for e in args[0]: - if e.tag not in existed_attr_keys: - dict_to_pass[e.tag] = _convert_element(e) + dict_to_pass.update(self._init_from_xml(args[0])) else: dict_to_pass.update( {k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()} @@ -616,8 +887,117 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: if v is not None } ) + # Apply client default values for fields the caller didn't set so that + # defaults are part of `_data` and therefore included during serialization. + for rf in self._attr_to_rest_field.values(): + if rf._default is _UNSET: + continue + if rf._rest_name in dict_to_pass: + continue + dict_to_pass[rf._rest_name] = _create_value(rf, rf._default) super().__init__(dict_to_pass) + def _init_from_xml( # pylint: disable=too-many-branches, too-many-statements + self, element: ET.Element + ) -> dict[str, typing.Any]: + """Deserialize an XML element into a dict mapping rest field names to values. + + :param ET.Element element: The XML element to deserialize from. + :returns: A dictionary of rest_name to deserialized value pairs. + :rtype: dict + """ + result: dict[str, typing.Any] = {} + existed_attr_keys: list[str] = [] + + field_plan = getattr(self, "_xml_field_plan", None) + if field_plan: + for rest_name, xml_name, kind, deser, rf_type, is_optional, items_name in field_plan: + if kind == 0: # wrapped element (most common) + item = element.find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + if deser: + result[rest_name] = deser(item) + else: + result[rest_name] = _deserialize(rf_type, item) + elif kind == 1: # attribute + attr_val = element.get(xml_name) + if attr_val is not None: + existed_attr_keys.append(xml_name) + if deser: + result[rest_name] = deser(attr_val) + else: + result[rest_name] = attr_val + elif kind == 2: # unwrapped array + items = element.findall(items_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(items_name) + if deser: + result[rest_name] = deser(items) + else: + result[rest_name] = _deserialize(rf_type, items) + elif not is_optional: + existed_attr_keys.append(items_name) + result[rest_name] = [] + elif kind == 3: # text + if element.text is not None: + if deser: + result[rest_name] = deser(element.text) + else: + result[rest_name] = element.text + else: + model_meta = getattr(self, "_xml", {}) + for rf in self._attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + # attribute + if prop_meta.get("attribute", False) and element.get(xml_name) is not None: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, element.get(xml_name)) + continue + + # unwrapped element is array + if prop_meta.get("unwrapped", False): + _items_name = prop_meta.get("itemsName") + if _items_name: + xml_name = _items_name + _items_ns = prop_meta.get("itemsNs") + if _items_ns is not None: + xml_ns = _items_ns + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + items = element.findall(xml_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, items) + elif not rf._is_optional: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = [] + continue + + # text element is primitive type + if prop_meta.get("text", False): + if element.text is not None: + result[rf._rest_name] = _deserialize(rf._type, element.text) + continue + + # wrapped element could be normal property or array + item = element.find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, item) + + # rest thing is additional properties + for e in element: + if e.tag not in existed_attr_keys: + result[e.tag] = _convert_element(e) + + return result + def copy(self) -> "Model": return Model(self.__dict__) @@ -626,7 +1006,7 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping', # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object' mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order - attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property + attr_to_rest_field: dict[str, _RestField] = { # map attribute name to rest_field property k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type") } annotations = { @@ -641,10 +1021,13 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None)) if not rf._rest_name_input: rf._rest_name_input = attr - cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items()) + cls._attr_to_rest_field: dict[str, _RestField] = dict(attr_to_rest_field.items()) + # Build XML field plan for fast _init_from_xml (only for XML models) + if getattr(cls, "_xml", None): + cls._xml_field_plan = _build_xml_field_plan(cls, attr_to_rest_field) cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}") - return super().__new__(cls) # pylint: disable=no-value-for-parameter + return super().__new__(cls) def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None: for base in cls.__bases__: @@ -670,7 +1053,7 @@ def _deserialize(cls, data, exist_discriminators): model_meta = getattr(cls, "_xml", {}) prop_meta = getattr(discriminator, "_xml", {}) xml_name = prop_meta.get("name", discriminator._rest_name) - xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) if xml_ns: xml_name = "{" + xml_ns + "}" + xml_name @@ -680,10 +1063,10 @@ def _deserialize(cls, data, exist_discriminators): discriminator_value = data.find(xml_name).text # pyright: ignore else: discriminator_value = data.get(discriminator._rest_name) - mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore + mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member return mapped_cls._deserialize(data, exist_discriminators) - def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]: + def as_dict(self, *, exclude_readonly: bool = False) -> dict[str, typing.Any]: """Return a dict that can be turned into json using json.dump. :keyword bool exclude_readonly: Whether to remove the readonly properties. @@ -743,7 +1126,7 @@ def _deserialize_with_union(deserializers, obj): def _deserialize_dict( value_deserializer: typing.Optional[typing.Callable], module: typing.Optional[str], - obj: typing.Dict[typing.Any, typing.Any], + obj: dict[typing.Any, typing.Any], ): if obj is None: return obj @@ -753,7 +1136,7 @@ def _deserialize_dict( def _deserialize_multiple_sequence( - entry_deserializers: typing.List[typing.Optional[typing.Callable]], + entry_deserializers: list[typing.Optional[typing.Callable]], module: typing.Optional[str], obj, ): @@ -762,6 +1145,14 @@ def _deserialize_multiple_sequence( return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers)) +def _is_array_encoded_deserializer(deserializer: functools.partial) -> bool: + return ( + isinstance(deserializer, functools.partial) + and isinstance(deserializer.args[0], functools.partial) + and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable + ) + + def _deserialize_sequence( deserializer: typing.Optional[typing.Callable], module: typing.Optional[str], @@ -771,17 +1162,30 @@ def _deserialize_sequence( return obj if isinstance(obj, ET.Element): obj = list(obj) + + # encoded string may be deserialized to sequence + if isinstance(obj, str) and isinstance(deserializer, functools.partial): + # for list[str] + if _is_array_encoded_deserializer(deserializer): + return deserializer(obj) + + # for list[Union[...]] + if isinstance(deserializer.args[0], list): + for sub_deserializer in deserializer.args[0]: + if _is_array_encoded_deserializer(sub_deserializer): + return sub_deserializer(obj) + return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) -def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]: +def _sorted_annotations(types: list[typing.Any]) -> list[typing.Any]: return sorted( types, key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"), ) -def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-branches +def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements, too-many-branches annotation: typing.Any, module: typing.Optional[str], rf: typing.Optional["_RestField"] = None, @@ -821,16 +1225,18 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur # is it optional? try: - if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore + if any(a is _NONE_TYPE for a in annotation.__args__): # pyright: ignore + if rf: + rf._is_optional = True if len(annotation.__args__) <= 2: # pyright: ignore if_obj_deserializer = _get_deserialize_callable_from_annotation( - next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore + next(a for a in annotation.__args__ if a is not _NONE_TYPE), module, rf # pyright: ignore ) return functools.partial(_deserialize_with_optional, if_obj_deserializer) # the type is Optional[Union[...]], we need to remove the None type from the Union annotation_copy = copy.copy(annotation) - annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore + annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a is not _NONE_TYPE] # pyright: ignore return _get_deserialize_callable_from_annotation(annotation_copy, module, rf) except AttributeError: pass @@ -846,7 +1252,10 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur return functools.partial(_deserialize_with_union, deserializers) try: - if annotation._name == "Dict": # pyright: ignore + annotation_name = ( + annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore + ) + if annotation_name.lower() == "dict": value_deserializer = _get_deserialize_callable_from_annotation( annotation.__args__[1], module, rf # pyright: ignore ) @@ -859,7 +1268,10 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur except (AttributeError, IndexError): pass try: - if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore + annotation_name = ( + annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore + ) + if annotation_name.lower() in ["list", "set", "tuple", "sequence"]: if len(annotation.__args__) > 1: # pyright: ignore entry_deserializers = [ _get_deserialize_callable_from_annotation(dt, module, rf) @@ -908,16 +1320,20 @@ def _deserialize_with_callable( return float(value.text) if value.text else None if deserializer is bool: return value.text == "true" if value.text else None + if deserializer and deserializer in _DESERIALIZE_MAPPING.values(): + return deserializer(value.text) if value.text else None + if deserializer and deserializer in _DESERIALIZE_MAPPING_WITHFORMAT.values(): + return deserializer(value.text) if value.text else None if deserializer is None: return value if deserializer in [int, float, bool]: return deserializer(value) if isinstance(deserializer, CaseInsensitiveEnumMeta): try: - return deserializer(value) + return deserializer(value.text if isinstance(value, ET.Element) else value) except ValueError: # for unknown value, return raw value - return value + return value.text if isinstance(value, ET.Element) else value if isinstance(deserializer, type) and issubclass(deserializer, Model): return deserializer._deserialize(value, []) return typing.cast(typing.Callable[[typing.Any], typing.Any], deserializer)(value) @@ -943,14 +1359,14 @@ def _deserialize( def _failsafe_deserialize( deserializer: typing.Any, - value: typing.Any, + response: HttpResponse, module: typing.Optional[str] = None, rf: typing.Optional["_RestField"] = None, format: typing.Optional[str] = None, ) -> typing.Any: try: - return _deserialize(deserializer, value, module, rf, format) - except DeserializationError: + return _deserialize(deserializer, response.json(), module, rf, format) + except Exception: # pylint: disable=broad-except _LOGGER.warning( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True ) @@ -959,17 +1375,18 @@ def _failsafe_deserialize( def _failsafe_deserialize_xml( deserializer: typing.Any, - value: typing.Any, + response: HttpResponse, ) -> typing.Any: try: - return _deserialize_xml(deserializer, value) - except DeserializationError: + return _deserialize_xml(deserializer, response.text()) + except Exception: # pylint: disable=broad-except _LOGGER.warning( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True ) return None +# pylint: disable=too-many-instance-attributes class _RestField: def __init__( self, @@ -977,11 +1394,12 @@ def __init__( name: typing.Optional[str] = None, type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin is_discriminator: bool = False, - visibility: typing.Optional[typing.List[str]] = None, + visibility: typing.Optional[list[str]] = None, default: typing.Any = _UNSET, format: typing.Optional[str] = None, is_multipart_file_input: bool = False, - xml: typing.Optional[typing.Dict[str, typing.Any]] = None, + xml: typing.Optional[dict[str, typing.Any]] = None, + deserializer: typing.Optional[typing.Callable] = None, ): self._type = type self._rest_name_input = name @@ -989,14 +1407,20 @@ def __init__( self._is_discriminator = is_discriminator self._visibility = visibility self._is_model = False + self._is_optional = False self._default = default self._format = format self._is_multipart_file_input = is_multipart_file_input self._xml = xml if xml is not None else {} + self._deserializer = deserializer @property def _class_type(self) -> typing.Any: - return getattr(self._type, "args", [None])[0] + result = getattr(self._type, "args", [None])[0] + # type may be wrapped by nested functools.partial so we need to check for that + if isinstance(result, functools.partial): + return getattr(result, "args", [None])[0] + return result @property def _rest_name(self) -> str: @@ -1007,14 +1431,44 @@ def _rest_name(self) -> str: def __get__(self, obj: Model, type=None): # pylint: disable=redefined-builtin # by this point, type and rest_name will have a value bc we default # them in __new__ of the Model class - item = obj.get(self._rest_name) + # Use _data.get() directly to avoid triggering __getitem__ which clears the cache + item = obj._data.get(self._rest_name, _UNSET) + if item is _UNSET: + # Field not set by user; return the client default if one exists, otherwise None + return self._default if self._default is not _UNSET else None if item is None: return item if self._is_model: return item - return _deserialize(self._type, _serialize(item, self._format), rf=self) + + # For mutable types, we want mutations to directly affect _data + # Check if we've already deserialized this value + cache_attr = f"_deserialized_{self._rest_name}" + if hasattr(obj, cache_attr): + # Return the value from _data directly (it's been deserialized in place) + return obj._data.get(self._rest_name) + + # Fast path: use _deserializer directly (avoids _serialize/_deserialize chain) + if self._deserializer: + deserialized = self._deserializer(item) + else: + deserialized = _deserialize(self._type, _serialize(item, self._format), rf=self) + + # For mutable types, store the deserialized value back in _data + # so mutations directly affect _data + if isinstance(deserialized, (dict, list, set)): + obj._data[self._rest_name] = deserialized + object.__setattr__(obj, cache_attr, True) # Mark as deserialized + return deserialized + + return deserialized def __set__(self, obj: Model, value) -> None: + # Clear the cached deserialized object when setting a new value + cache_attr = f"_deserialized_{self._rest_name}" + if hasattr(obj, cache_attr): + object.__delattr__(obj, cache_attr) + if value is None: # we want to wipe out entries if users set attr to None try: @@ -1039,11 +1493,12 @@ def rest_field( *, name: typing.Optional[str] = None, type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin - visibility: typing.Optional[typing.List[str]] = None, + visibility: typing.Optional[list[str]] = None, default: typing.Any = _UNSET, format: typing.Optional[str] = None, is_multipart_file_input: bool = False, - xml: typing.Optional[typing.Dict[str, typing.Any]] = None, + xml: typing.Optional[dict[str, typing.Any]] = None, + deserializer: typing.Optional[typing.Callable] = None, ) -> typing.Any: return _RestField( name=name, @@ -1053,6 +1508,7 @@ def rest_field( format=format, is_multipart_file_input=is_multipart_file_input, xml=xml, + deserializer=deserializer, ) @@ -1060,8 +1516,8 @@ def rest_discriminator( *, name: typing.Optional[str] = None, type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin - visibility: typing.Optional[typing.List[str]] = None, - xml: typing.Optional[typing.Dict[str, typing.Any]] = None, + visibility: typing.Optional[list[str]] = None, + xml: typing.Optional[dict[str, typing.Any]] = None, ) -> typing.Any: return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility, xml=xml) @@ -1077,21 +1533,77 @@ def serialize_xml(model: Model, exclude_readonly: bool = False) -> str: return ET.tostring(_get_element(model, exclude_readonly), encoding="unicode") # type: ignore +def _get_xml_ns(meta: dict[str, typing.Any]) -> typing.Optional[str]: + """Return the XML namespace from a metadata dict, checking both 'ns' (old-style) and 'namespace' (DPG) keys. + + :param dict meta: The metadata dictionary to extract namespace from. + :returns: The namespace string if 'ns' or 'namespace' key is present, None otherwise. + :rtype: str or None + """ + ns = meta.get("ns") + if ns is None: + ns = meta.get("namespace") + return ns + + +def _resolve_xml_ns( + prop_meta: dict[str, typing.Any], model_meta: typing.Optional[dict[str, typing.Any]] = None +) -> typing.Optional[str]: + """Resolve XML namespace for a property, falling back to model namespace when appropriate. + + Checks the property metadata first; if no namespace is found and the model does not declare + an explicit prefix, falls back to the model-level namespace. + + :param dict prop_meta: The property metadata dictionary. + :param dict model_meta: The model metadata dictionary, used as fallback. + :returns: The resolved namespace string, or None. + :rtype: str or None + """ + ns = _get_xml_ns(prop_meta) + if ns is None and model_meta is not None and not model_meta.get("prefix"): + ns = _get_xml_ns(model_meta) + return ns + + +def _set_xml_attribute(element: ET.Element, name: str, value: typing.Any, prop_meta: dict[str, typing.Any]) -> None: + """Set an XML attribute on an element, handling namespace prefix registration. + + :param ET.Element element: The element to set the attribute on. + :param str name: The default attribute name (wire name). + :param any value: The attribute value. + :param dict prop_meta: The property metadata dictionary. + """ + xml_name = prop_meta.get("name", name) + _attr_ns = _get_xml_ns(prop_meta) + if _attr_ns: + _attr_prefix = prop_meta.get("prefix") + if _attr_prefix: + _safe_register_namespace(_attr_prefix, _attr_ns) + xml_name = "{" + _attr_ns + "}" + xml_name + element.set(xml_name, _get_primitive_type_value(value)) + + def _get_element( o: typing.Any, exclude_readonly: bool = False, - parent_meta: typing.Optional[typing.Dict[str, typing.Any]] = None, + parent_meta: typing.Optional[dict[str, typing.Any]] = None, wrapped_element: typing.Optional[ET.Element] = None, -) -> typing.Union[ET.Element, typing.List[ET.Element]]: +) -> typing.Union[ET.Element, list[ET.Element]]: if _is_model(o): model_meta = getattr(o, "_xml", {}) # if prop is a model, then use the prop element directly, else generate a wrapper of model if wrapped_element is None: + # When serializing as an array item (parent_meta is set), check if the parent has an + # explicit itemsName. This ensures correct element names for unwrapped arrays (where + # the element tag is the property/items name, not the model type name). + _items_name = parent_meta.get("itemsName") if parent_meta is not None else None + element_name = _items_name if _items_name else (model_meta.get("name") or o.__class__.__name__) + _model_ns = _get_xml_ns(model_meta) wrapped_element = _create_xml_element( - model_meta.get("name", o.__class__.__name__), + element_name, model_meta.get("prefix"), - model_meta.get("ns"), + _model_ns, ) readonly_props = [] @@ -1113,7 +1625,9 @@ def _get_element( # additional properties will not have rest field, use the wire name as xml name prop_meta = {"name": k} - # if no ns for prop, use model's + # Propagate model namespace to properties only for old-style "ns"-keyed models. + # DPG-generated models use the "namespace" key and explicitly declare namespace on + # each property that needs it, so propagation is intentionally skipped for them. if prop_meta.get("ns") is None and model_meta.get("ns"): prop_meta["ns"] = model_meta.get("ns") prop_meta["prefix"] = model_meta.get("prefix") @@ -1125,12 +1639,7 @@ def _get_element( # text could only set on primitive type wrapped_element.text = _get_primitive_type_value(v) elif prop_meta.get("attribute", False): - xml_name = prop_meta.get("name", k) - if prop_meta.get("ns"): - ET.register_namespace(prop_meta.get("prefix"), prop_meta.get("ns")) # pyright: ignore - xml_name = "{" + prop_meta.get("ns") + "}" + xml_name # pyright: ignore - # attribute should be primitive type - wrapped_element.set(xml_name, _get_primitive_type_value(v)) + _set_xml_attribute(wrapped_element, k, v, prop_meta) else: # other wrapped prop element wrapped_element.append(_get_wrapped_element(v, exclude_readonly, prop_meta)) @@ -1139,6 +1648,7 @@ def _get_element( return [_get_element(x, exclude_readonly, parent_meta) for x in o] # type: ignore if isinstance(o, dict): result = [] + _dict_ns = _get_xml_ns(parent_meta) if parent_meta else None for k, v in o.items(): result.append( _get_wrapped_element( @@ -1146,7 +1656,7 @@ def _get_element( exclude_readonly, { "name": k, - "ns": parent_meta.get("ns") if parent_meta else None, + "ns": _dict_ns, "prefix": parent_meta.get("prefix") if parent_meta else None, }, ) @@ -1155,13 +1665,16 @@ def _get_element( # primitive case need to create element based on parent_meta if parent_meta: + _items_ns = parent_meta.get("itemsNs") + if _items_ns is None: + _items_ns = _get_xml_ns(parent_meta) return _get_wrapped_element( o, exclude_readonly, { "name": parent_meta.get("itemsName", parent_meta.get("name")), "prefix": parent_meta.get("itemsPrefix", parent_meta.get("prefix")), - "ns": parent_meta.get("itemsNs", parent_meta.get("ns")), + "ns": _items_ns, }, ) @@ -1171,10 +1684,11 @@ def _get_element( def _get_wrapped_element( v: typing.Any, exclude_readonly: bool, - meta: typing.Optional[typing.Dict[str, typing.Any]], + meta: typing.Optional[dict[str, typing.Any]], ) -> ET.Element: + _meta_ns = _get_xml_ns(meta) if meta else None wrapped_element = _create_xml_element( - meta.get("name") if meta else None, meta.get("prefix") if meta else None, meta.get("ns") if meta else None + meta.get("name") if meta else None, meta.get("prefix") if meta else None, _meta_ns ) if isinstance(v, (dict, list)): wrapped_element.extend(_get_element(v, exclude_readonly, meta)) @@ -1182,7 +1696,7 @@ def _get_wrapped_element( _get_element(v, exclude_readonly, meta, wrapped_element) else: wrapped_element.text = _get_primitive_type_value(v) - return wrapped_element + return wrapped_element # type: ignore[no-any-return] def _get_primitive_type_value(v) -> str: @@ -1195,9 +1709,29 @@ def _get_primitive_type_value(v) -> str: return str(v) -def _create_xml_element(tag, prefix=None, ns=None): - if prefix and ns: +def _safe_register_namespace(prefix: str, ns: str) -> None: + """Register an XML namespace prefix, handling reserved prefix patterns. + + Some prefixes (e.g. 'ns2') match Python's reserved 'ns\\d+' pattern used for + auto-generated prefixes, causing register_namespace to raise ValueError. + Falls back to directly registering in the internal namespace map. + + :param str prefix: The namespace prefix to register. + :param str ns: The namespace URI. + """ + try: ET.register_namespace(prefix, ns) + except ValueError: + _ns_map = getattr(ET, "_namespace_map", None) + if _ns_map is not None: + _ns_map[ns] = prefix + + +def _create_xml_element( + tag: typing.Any, prefix: typing.Optional[str] = None, ns: typing.Optional[str] = None +) -> ET.Element: + if prefix and ns: + _safe_register_namespace(prefix, ns) if ns: return ET.Element("{" + ns + "}" + tag) return ET.Element(tag) @@ -1208,13 +1742,15 @@ def _deserialize_xml( value: str, ) -> typing.Any: element = ET.fromstring(value) # nosec + if _is_model(deserializer): + return deserializer._deserialize(element, []) return _deserialize(deserializer, element) def _convert_element(e: ET.Element): # dict case if len(e.attrib) > 0 or len({child.tag for child in e}) > 1: - dict_result: typing.Dict[str, typing.Any] = {} + dict_result: dict[str, typing.Any] = {} for child in e: if dict_result.get(child.tag) is not None: if isinstance(dict_result[child.tag], list): @@ -1227,7 +1763,7 @@ def _convert_element(e: ET.Element): return dict_result # array case if len(e) > 0: - array_result: typing.List[typing.Any] = [] + array_result: list[typing.Any] = [] for child in e: array_result.append(_convert_element(child)) return array_result diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_serialization.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/serialization.py similarity index 91% rename from sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_serialization.py rename to sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/serialization.py index 7a0232de5ddc..75906e2eb77f 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_serialization.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_utils/serialization.py @@ -1,28 +1,10 @@ # pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 # -------------------------------------------------------------------------- -# # Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the ""Software""), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- # pyright: reportUnnecessaryTypeIgnoreComment=false @@ -39,7 +21,6 @@ import sys import codecs from typing import ( - Dict, Any, cast, Optional, @@ -49,7 +30,6 @@ Mapping, Callable, MutableMapping, - List, ) try: @@ -59,11 +39,15 @@ import xml.etree.ElementTree as ET import isodate # type: ignore -from typing_extensions import Self from azure.core.exceptions import DeserializationError, SerializationError from azure.core.serialization import NULL as CoreNull +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + _BOM = codecs.BOM_UTF8.decode(encoding="utf-8") JSON = MutableMapping[str, Any] @@ -247,12 +231,12 @@ class Model: serialization and deserialization. """ - _subtype_map: Dict[str, Dict[str, Any]] = {} - _attribute_map: Dict[str, Dict[str, Any]] = {} - _validation: Dict[str, Dict[str, Any]] = {} + _subtype_map: dict[str, dict[str, Any]] = {} + _attribute_map: dict[str, dict[str, Any]] = {} + _validation: dict[str, dict[str, Any]] = {} def __init__(self, **kwargs: Any) -> None: - self.additional_properties: Optional[Dict[str, Any]] = {} + self.additional_properties: Optional[dict[str, Any]] = {} for k in kwargs: # pylint: disable=consider-using-dict-items if k not in self._attribute_map: _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) @@ -329,7 +313,7 @@ def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: def as_dict( self, keep_readonly: bool = True, - key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + key_transformer: Callable[[str, dict[str, Any], Any], Any] = attribute_transformer, **kwargs: Any ) -> JSON: """Return a dict that can be serialized using json.dump. @@ -398,7 +382,7 @@ def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: def from_dict( cls, data: Any, - key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + key_extractors: Optional[Callable[[str, dict[str, Any], Any], Any]] = None, content_type: Optional[str] = None, ) -> Self: """Parse a dict using given key extractor return a model. @@ -432,7 +416,7 @@ def _flatten_subtype(cls, key, objects): return {} result = dict(cls._subtype_map[key]) for valuetype in cls._subtype_map[key].values(): - result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + result |= objects[valuetype]._flatten_subtype(key, objects) # pylint: disable=protected-access return result @classmethod @@ -536,6 +520,10 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: "rfc-1123": Serializer.serialize_rfc, "unix-time": Serializer.serialize_unix, "duration": Serializer.serialize_duration, + "duration-seconds-int": Serializer.serialize_duration_seconds_int, + "duration-seconds-float": Serializer.serialize_duration_seconds_float, + "duration-milliseconds-int": Serializer.serialize_duration_milliseconds_int, + "duration-milliseconds-float": Serializer.serialize_duration_milliseconds_float, "date": Serializer.serialize_date, "time": Serializer.serialize_time, "decimal": Serializer.serialize_decimal, @@ -546,7 +534,7 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: "[]": self.serialize_iter, "{}": self.serialize_dict, } - self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.dependencies: dict[str, type] = dict(classes) if classes else {} self.key_transformer = full_restapi_key_transformer self.client_side_validation = True @@ -597,7 +585,7 @@ def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, to if attr_name == "additional_properties" and attr_desc["key"] == "": if target_obj.additional_properties is not None: - serialized.update(target_obj.additional_properties) + serialized |= target_obj.additional_properties continue try: @@ -807,7 +795,7 @@ def serialize_data(self, data, data_type, **kwargs): # If dependencies is empty, try with current data class # It has to be a subclass of Enum anyway - enum_type = self.dependencies.get(data_type, data.__class__) + enum_type = self.dependencies.get(data_type, cast(type, data.__class__)) if issubclass(enum_type, Enum): return Serializer.serialize_enum(data, enum_obj=enum_type) @@ -841,13 +829,20 @@ def serialize_basic(cls, data, data_type, **kwargs): :param str data_type: Type of object in the iterable. :rtype: str, int, float, bool :return: serialized object + :raises TypeError: raise if data_type is not one of str, int, float, bool. """ custom_serializer = cls._get_custom_serializers(data_type, **kwargs) if custom_serializer: return custom_serializer(data) if data_type == "str": return cls.serialize_unicode(data) - return eval(data_type)(data) # nosec # pylint: disable=eval-used + if data_type == "int": + return int(data) + if data_type == "float": + return float(data) + if data_type == "bool": + return bool(data) + raise TypeError("Unknown basic data type: {}".format(data_type)) @classmethod def serialize_unicode(cls, data): @@ -1118,6 +1113,61 @@ def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument attr = isodate.parse_duration(attr) return isodate.duration_isoformat(attr) + @staticmethod + def _serialize_duration_numeric(attr, scale, as_int): + """Serialize a TimeDelta into a numeric value scaled to the wire unit. + + :param TimeDelta attr: Object to be serialized. + :param int scale: Multiplier applied to total seconds (1 for seconds, 1000 for milliseconds). + :param bool as_int: Whether to truncate the result to an int. + :rtype: int or float + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + value = attr.total_seconds() * scale if isinstance(attr, datetime.timedelta) else attr + return int(value) if as_int else float(value) + + @staticmethod + def serialize_duration_seconds_int(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into an integer number of seconds. + + :param TimeDelta attr: Object to be serialized. + :rtype: int + :return: serialized duration + """ + return Serializer._serialize_duration_numeric(attr, 1, True) + + @staticmethod + def serialize_duration_seconds_float(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into a floating point number of seconds. + + :param TimeDelta attr: Object to be serialized. + :rtype: float + :return: serialized duration + """ + return Serializer._serialize_duration_numeric(attr, 1, False) + + @staticmethod + def serialize_duration_milliseconds_int(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into an integer number of milliseconds. + + :param TimeDelta attr: Object to be serialized. + :rtype: int + :return: serialized duration + """ + return Serializer._serialize_duration_numeric(attr, 1000, True) + + @staticmethod + def serialize_duration_milliseconds_float(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into a floating point number of milliseconds. + + :param TimeDelta attr: Object to be serialized. + :rtype: float + :return: serialized duration + """ + return Serializer._serialize_duration_numeric(attr, 1000, False) + @staticmethod def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument """Serialize Datetime object into RFC-1123 formatted string. @@ -1202,7 +1252,7 @@ def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argumen while "." in key: # Need the cast, as for some reasons "split" is typed as list[str | Any] - dict_keys = cast(List[str], _FLATTEN.split(key)) + dict_keys = cast(list[str], _FLATTEN.split(key)) if len(dict_keys) == 1: key = _decode_attribute_map_key(dict_keys[0]) break @@ -1390,6 +1440,10 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: "rfc-1123": Deserializer.deserialize_rfc, "unix-time": Deserializer.deserialize_unix, "duration": Deserializer.deserialize_duration, + "duration-seconds-int": Deserializer.deserialize_duration_seconds, + "duration-seconds-float": Deserializer.deserialize_duration_seconds, + "duration-milliseconds-int": Deserializer.deserialize_duration_milliseconds, + "duration-milliseconds-float": Deserializer.deserialize_duration_milliseconds, "date": Deserializer.deserialize_date, "time": Deserializer.deserialize_time, "decimal": Deserializer.deserialize_decimal, @@ -1402,9 +1456,13 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: } self.deserialize_expected_types = { "duration": (isodate.Duration, datetime.timedelta), + "duration-seconds-int": (isodate.Duration, datetime.timedelta), + "duration-seconds-float": (isodate.Duration, datetime.timedelta), + "duration-milliseconds-int": (isodate.Duration, datetime.timedelta), + "duration-milliseconds-float": (isodate.Duration, datetime.timedelta), "iso-8601": (datetime.datetime), } - self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.dependencies: dict[str, type] = dict(classes) if classes else {} self.key_extractors = [rest_key_extractor, xml_key_extractor] # Additional properties only works if the "rest_key_extractor" is used to # extract the keys. Making it to work whatever the key extractor is too much @@ -1414,7 +1472,7 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: # Otherwise, result are unexpected self.additional_properties_detection = True - def __call__(self, target_obj, response_data, content_type=None): + def __call__(self, target_obj, response_data, content_type=None): # pylint: disable=too-many-return-statements """Call the deserializer to process a REST response. :param str target_obj: Target data type to deserialize to. @@ -1424,6 +1482,27 @@ def __call__(self, target_obj, response_data, content_type=None): :return: Deserialized object. :rtype: object """ + # Fast path for header deserialization: response_data is a plain str or None + # and target_obj is a simple scalar type. This avoids the expensive + # _unpack_content → _deserialize → _classify_target → deserialize_data chain. + if response_data is None: + return None + if target_obj == "str" and isinstance(response_data, str): + return response_data + if isinstance(response_data, str): + if target_obj == "int": + return int(response_data) + if target_obj == "bool": + if response_data in ("true", "1", "True"): + return True + if response_data in ("false", "0", "False"): + return False + return bool(response_data) + if target_obj == "rfc-1123": + return Deserializer.deserialize_rfc(response_data) + if target_obj == "bytearray": + return Deserializer.deserialize_bytearray(response_data) + data = self._unpack_content(response_data, content_type) return self._deserialize(target_obj, data) @@ -1777,7 +1856,7 @@ def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return :param str data_type: deserialization data type. :return: Deserialized basic type. :rtype: str, int, float or bool - :raises TypeError: if string format is not valid. + :raises TypeError: if string format is not valid or data_type is not one of str, int, float, bool. """ # If we're here, data is supposed to be a basic type. # If it's still an XML node, take the text @@ -1803,7 +1882,11 @@ def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return if data_type == "str": return self.deserialize_unicode(attr) - return eval(data_type)(attr) # nosec # pylint: disable=eval-used + if data_type == "int": + return int(attr) + if data_type == "float": + return float(attr) + raise TypeError("Unknown basic data type: {}".format(data_type)) @staticmethod def deserialize_unicode(data): @@ -1938,6 +2021,48 @@ def deserialize_duration(attr): raise DeserializationError(msg) from err return duration + @staticmethod + def _deserialize_duration_numeric(attr, unit): + """Deserialize a numeric duration value into a TimeDelta object. + + :param float attr: response value to be deserialized. + :param str unit: The wire unit, used as the ``timedelta`` keyword + (``"seconds"`` or ``"milliseconds"``). + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if value is invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = datetime.timedelta(**{unit: float(attr)}) # type: ignore + except (ValueError, OverflowError, TypeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_duration_seconds(attr): + """Deserialize a numeric number of seconds into a TimeDelta object. + + :param float attr: response value to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if value is invalid. + """ + return Deserializer._deserialize_duration_numeric(attr, "seconds") + + @staticmethod + def deserialize_duration_milliseconds(attr): + """Deserialize a numeric number of milliseconds into a TimeDelta object. + + :param float attr: response value to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if value is invalid. + """ + return Deserializer._deserialize_duration_numeric(attr, "milliseconds") + @staticmethod def deserialize_date(attr): """Deserialize ISO-8601 formatted string into Date object. diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_version.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_version.py index bbcd28b4aa67..0ec13ea52bbf 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_version.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/_version.py @@ -6,4 +6,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.0b2" +VERSION = "1.0.0" diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_client.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_client.py index f03bab8937aa..7a15ce6ac27f 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_client.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_client.py @@ -7,19 +7,27 @@ # -------------------------------------------------------------------------- from copy import deepcopy -from typing import Any, Awaitable, TYPE_CHECKING -from typing_extensions import Self +import sys +from typing import Any, Awaitable, Optional, TYPE_CHECKING, cast from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest +from azure.core.settings import settings from azure.mgmt.core import AsyncARMPipelineClient from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy +from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import EdgeZonesMgmtClientConfiguration from .operations import ExtendedZonesOperations, Operations +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # type: ignore + if TYPE_CHECKING: + from azure.core import AzureClouds from azure.core.credentials_async import AsyncTokenCredential @@ -34,11 +42,14 @@ class EdgeZonesMgmtClient: :type credential: ~azure.core.credentials_async.AsyncTokenCredential :param subscription_id: The ID of the target subscription. The value must be an UUID. Required. :type subscription_id: str - :param base_url: Service host. Default value is "https://management.azure.com". + :param base_url: Service host. Default value is None. :type base_url: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-04-01-preview". Note that overriding this default value may result in unsupported - behavior. + :keyword cloud_setting: The cloud setting for which to get the ARM endpoint. Default value is + None. + :paramtype cloud_setting: ~azure.core.AzureClouds + :keyword api_version: The API version to use for this operation. Known values are "2026-10-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -46,13 +57,26 @@ def __init__( self, credential: "AsyncTokenCredential", subscription_id: str, - base_url: str = "https://management.azure.com", + base_url: Optional[str] = None, + *, + cloud_setting: Optional["AzureClouds"] = None, **kwargs: Any ) -> None: _endpoint = "{endpoint}" + _cloud = cloud_setting or settings.current.azure_cloud # type: ignore + _endpoints = get_arm_endpoints(_cloud) + if not base_url: + base_url = _endpoints["resource_manager"] + credential_scopes = kwargs.pop("credential_scopes", _endpoints["credential_scopes"]) self._config = EdgeZonesMgmtClientConfiguration( - credential=credential, subscription_id=subscription_id, base_url=base_url, **kwargs + credential=credential, + subscription_id=subscription_id, + base_url=cast(str, base_url), + cloud_setting=cloud_setting, + credential_scopes=credential_scopes, + **kwargs ) + _policies = kwargs.pop("policies", None) if _policies is None: _policies = [ @@ -71,7 +95,9 @@ def __init__( policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, self._config.http_logging_policy, ] - self._client: AsyncARMPipelineClient = AsyncARMPipelineClient(base_url=_endpoint, policies=_policies, **kwargs) + self._client: AsyncARMPipelineClient = AsyncARMPipelineClient( + base_url=cast(str, _endpoint), policies=_policies, **kwargs + ) self._serialize = Serializer() self._deserialize = Deserializer() diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_configuration.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_configuration.py index 17beab4614d2..5d85310f7b77 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_configuration.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_configuration.py @@ -6,7 +6,7 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, TYPE_CHECKING +from typing import Any, Optional, TYPE_CHECKING from azure.core.pipeline import policies from azure.mgmt.core.policies import ARMHttpLoggingPolicy, AsyncARMChallengeAuthenticationPolicy @@ -14,6 +14,7 @@ from .._version import VERSION if TYPE_CHECKING: + from azure.core import AzureClouds from azure.core.credentials_async import AsyncTokenCredential @@ -29,9 +30,12 @@ class EdgeZonesMgmtClientConfiguration: # pylint: disable=too-many-instance-att :type subscription_id: str :param base_url: Service host. Default value is "https://management.azure.com". :type base_url: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-04-01-preview". Note that overriding this default value may result in unsupported - behavior. + :param cloud_setting: The cloud setting for which to get the ARM endpoint. Default value is + None. + :type cloud_setting: ~azure.core.AzureClouds + :keyword api_version: The API version to use for this operation. Known values are "2026-10-01" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -40,9 +44,10 @@ def __init__( credential: "AsyncTokenCredential", subscription_id: str, base_url: str = "https://management.azure.com", + cloud_setting: Optional["AzureClouds"] = None, **kwargs: Any ) -> None: - api_version: str = kwargs.pop("api_version", "2024-04-01-preview") + api_version: str = kwargs.pop("api_version", "2026-10-01") if credential is None: raise ValueError("Parameter 'credential' must not be None.") @@ -52,6 +57,7 @@ def __init__( self.credential = credential self.subscription_id = subscription_id self.base_url = base_url + self.cloud_setting = cloud_setting self.api_version = api_version self.credential_scopes = kwargs.pop("credential_scopes", ["https://management.azure.com/.default"]) kwargs.setdefault("sdk_moniker", "mgmt-edgezones/{}".format(VERSION)) diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_patch.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_patch.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_operations.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_operations.py index 16e7a16298ae..7cd573984fe6 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_operations.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_operations.py @@ -5,8 +5,8 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -import sys -from typing import Any, AsyncIterable, Callable, Dict, List, Optional, TypeVar +from collections.abc import MutableMapping +from typing import Any, Callable, Optional, TypeVar import urllib.parse from azure.core import AsyncPipelineClient @@ -29,8 +29,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ..._model_base import _deserialize, _failsafe_deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize, _failsafe_deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_extended_zones_get_request, build_extended_zones_list_by_subscription_request, @@ -40,12 +40,9 @@ ) from .._configuration import EdgeZonesMgmtClientConfiguration -if sys.version_info >= (3, 9): - from collections.abc import MutableMapping -else: - from typing import MutableMapping # type: ignore T = TypeVar("T") -ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, dict[str, Any]], Any]] +List = list class Operations: @@ -66,7 +63,7 @@ def __init__(self, *args, **kwargs) -> None: self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def list(self, **kwargs: Any) -> AsyncIterable["_models.Operation"]: + def list(self, **kwargs: Any) -> AsyncItemPaged["_models.Operation"]: """List the operations for the provider. :return: An iterator like instance of Operation @@ -112,7 +109,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -125,7 +125,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(List[_models.Operation], deserialized.get("value", [])) + list_of_elem = _deserialize( + List[_models.Operation], + deserialized.get("value", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -141,7 +144,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) return pipeline_response @@ -201,6 +207,7 @@ async def get(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZ } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -215,11 +222,14 @@ async def get(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZ except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ExtendedZone, response.json()) @@ -229,7 +239,7 @@ async def get(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZ return deserialized # type: ignore @distributed_trace - def list_by_subscription(self, **kwargs: Any) -> AsyncIterable["_models.ExtendedZone"]: + def list_by_subscription(self, **kwargs: Any) -> AsyncItemPaged["_models.ExtendedZone"]: """Lists the Azure Extended Zones available to a subscription. :return: An iterator like instance of ExtendedZone @@ -276,7 +286,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -289,7 +302,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(List[_models.ExtendedZone], deserialized.get("value", [])) + list_of_elem = _deserialize( + List[_models.ExtendedZone], + deserialized.get("value", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -305,7 +321,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) return pipeline_response @@ -347,6 +366,7 @@ async def register(self, extended_zone_name: str, **kwargs: Any) -> _models.Exte } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -361,11 +381,14 @@ async def register(self, extended_zone_name: str, **kwargs: Any) -> _models.Exte except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ExtendedZone, response.json()) @@ -409,6 +432,7 @@ async def unregister(self, extended_zone_name: str, **kwargs: Any) -> _models.Ex } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -423,11 +447,14 @@ async def unregister(self, extended_zone_name: str, **kwargs: Any) -> _models.Ex except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ExtendedZone, response.json()) diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_patch.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_patch.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/aio/operations/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_enums.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_enums.py index 3019dc518690..5f9af867f4c7 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_enums.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_enums.py @@ -55,23 +55,23 @@ class ProvisioningState(str, Enum, metaclass=CaseInsensitiveEnumMeta): CANCELED = "Canceled" """Resource creation was canceled.""" PROVISIONING = "Provisioning" - """Provisioning State""" + """Provisioning State.""" UPDATING = "Updating" - """Updating State""" + """Updating State.""" DELETING = "Deleting" - """Deleting State""" + """Deleting State.""" ACCEPTED = "Accepted" - """Accepted State""" + """Accepted State.""" class RegistrationState(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The Azure Extended Zone registration status for a subscription.""" NOT_REGISTERED = "NotRegistered" - """Subscription not registered for the Azure Extended Zone""" + """Subscription not registered for the Azure Extended Zone.""" PENDING_REGISTER = "PendingRegister" - """Subscription pending registration for the Azure Extended Zone""" + """Subscription pending registration for the Azure Extended Zone.""" REGISTERED = "Registered" - """Subscription is registered for the Azure Extended Zone""" + """Subscription is registered for the Azure Extended Zone.""" PENDING_UNREGISTER = "PendingUnregister" - """Subscription is pending unregistering for the Azure Extended Zone""" + """Subscription is pending unregistering for the Azure Extended Zone.""" diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_models.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_models.py index d051a8cf0195..018c703fdf69 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_models.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_models.py @@ -9,16 +9,15 @@ # pylint: disable=useless-super-delegation import datetime -from typing import Any, List, Mapping, Optional, TYPE_CHECKING, Union, overload +from typing import Any, Mapping, Optional, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ErrorAdditionalInfo(_model_base.Model): +class ErrorAdditionalInfo(_Model): """The resource management error additional info. :ivar type: The additional info type. @@ -33,7 +32,7 @@ class ErrorAdditionalInfo(_model_base.Model): """The additional info.""" -class ErrorDetail(_model_base.Model): +class ErrorDetail(_Model): """The error detail. :ivar code: The error code. @@ -54,17 +53,16 @@ class ErrorDetail(_model_base.Model): """The error message.""" target: Optional[str] = rest_field(visibility=["read"]) """The error target.""" - details: Optional[List["_models.ErrorDetail"]] = rest_field(visibility=["read"]) + details: Optional[list["_models.ErrorDetail"]] = rest_field(visibility=["read"]) """The error details.""" - additional_info: Optional[List["_models.ErrorAdditionalInfo"]] = rest_field( + additional_info: Optional[list["_models.ErrorAdditionalInfo"]] = rest_field( name="additionalInfo", visibility=["read"] ) """The error additional info.""" -class ErrorResponse(_model_base.Model): - """Common error response for all Azure Resource Manager APIs to return error details for failed - operations. +class ErrorResponse(_Model): + """Error response. :ivar error: The error object. :vartype error: ~azure.mgmt.edgezones.models.ErrorDetail @@ -91,8 +89,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Resource(_model_base.Model): - """Common fields that are returned in the response for all Azure Resource Manager resources. +class Resource(_Model): + """Resource. :ivar id: Fully qualified resource ID for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. @@ -120,8 +118,7 @@ class Resource(_model_base.Model): class ProxyResource(Resource): - """The resource model definition for a Azure Resource Manager proxy resource. It will not have - tags and a location. + """Proxy Resource. :ivar id: Fully qualified resource ID for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. @@ -179,7 +176,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendedZoneProperties(_model_base.Model): +class ExtendedZoneProperties(_Model): """The properties of an Extended Zone resource. :ivar provisioning_state: Status of the last operation performed by the subscription on the @@ -240,8 +237,8 @@ class ExtendedZoneProperties(_model_base.Model): """The Home Location of the Azure Extended Zone. Required.""" -class Operation(_model_base.Model): - """Details of a REST API operation, returned from the Resource Provider Operations API. +class Operation(_Model): + """REST API Operation. :ivar name: The name of the operation, as per Resource-Based Access Control (RBAC). Examples: "Microsoft.Compute/virtualMachines/write", "Microsoft.Compute/virtualMachines/capture/action". @@ -297,8 +294,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OperationDisplay(_model_base.Model): - """Localized display information for and operation. +class OperationDisplay(_Model): + """Localized display information for an operation. :ivar provider: The localized friendly form of the resource provider name, e.g. "Microsoft Monitoring Insights" or "Microsoft Compute". @@ -328,7 +325,7 @@ class OperationDisplay(_model_base.Model): views.""" -class SystemData(_model_base.Model): +class SystemData(_Model): """Metadata pertaining to creation and last modification of the resource. :ivar created_by: The identity that created the resource. diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_patch.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_patch.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/models/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_operations.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_operations.py index 9e6955730628..19c42298bb0e 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_operations.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_operations.py @@ -5,8 +5,8 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -import sys -from typing import Any, Callable, Dict, Iterable, List, Optional, TypeVar +from collections.abc import MutableMapping +from typing import Any, Callable, Optional, TypeVar import urllib.parse from azure.core import PipelineClient @@ -29,15 +29,12 @@ from .. import models as _models from .._configuration import EdgeZonesMgmtClientConfiguration -from .._model_base import _deserialize, _failsafe_deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import _deserialize, _failsafe_deserialize +from .._utils.serialization import Deserializer, Serializer -if sys.version_info >= (3, 9): - from collections.abc import MutableMapping -else: - from typing import MutableMapping # type: ignore T = TypeVar("T") -ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, dict[str, Any]], Any]] +List = list _SERIALIZER = Serializer() _SERIALIZER.client_side_validation = False @@ -47,7 +44,7 @@ def build_operations_list_request(**kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-04-01-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-10-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -66,7 +63,7 @@ def build_extended_zones_get_request(extended_zone_name: str, subscription_id: s _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-04-01-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-10-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -93,7 +90,7 @@ def build_extended_zones_list_by_subscription_request( # pylint: disable=name-t _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-04-01-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-10-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -117,7 +114,7 @@ def build_extended_zones_register_request(extended_zone_name: str, subscription_ _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-04-01-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-10-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -144,7 +141,7 @@ def build_extended_zones_unregister_request( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-04-01-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-10-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -175,7 +172,7 @@ class Operations: :attr:`operations` attribute. """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: input_args = list(args) self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") self._config: EdgeZonesMgmtClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") @@ -183,7 +180,7 @@ def __init__(self, *args, **kwargs): self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def list(self, **kwargs: Any) -> Iterable["_models.Operation"]: + def list(self, **kwargs: Any) -> ItemPaged["_models.Operation"]: """List the operations for the provider. :return: An iterator like instance of Operation @@ -229,7 +226,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -242,7 +242,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(List[_models.Operation], deserialized.get("value", [])) + list_of_elem = _deserialize( + List[_models.Operation], + deserialized.get("value", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -258,7 +261,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) return pipeline_response @@ -276,7 +282,7 @@ class ExtendedZonesOperations: :attr:`extended_zones` attribute. """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: input_args = list(args) self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") self._config: EdgeZonesMgmtClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") @@ -318,6 +324,7 @@ def get(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZone: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -332,11 +339,14 @@ def get(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZone: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ExtendedZone, response.json()) @@ -346,7 +356,7 @@ def get(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZone: return deserialized # type: ignore @distributed_trace - def list_by_subscription(self, **kwargs: Any) -> Iterable["_models.ExtendedZone"]: + def list_by_subscription(self, **kwargs: Any) -> ItemPaged["_models.ExtendedZone"]: """Lists the Azure Extended Zones available to a subscription. :return: An iterator like instance of ExtendedZone @@ -393,7 +403,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -406,7 +419,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(List[_models.ExtendedZone], deserialized.get("value", [])) + list_of_elem = _deserialize( + List[_models.ExtendedZone], + deserialized.get("value", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -422,7 +438,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) return pipeline_response @@ -464,6 +483,7 @@ def register(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZo } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -478,11 +498,14 @@ def register(self, extended_zone_name: str, **kwargs: Any) -> _models.ExtendedZo except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ExtendedZone, response.json()) @@ -526,6 +549,7 @@ def unregister(self, extended_zone_name: str, **kwargs: Any) -> _models.Extended } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -540,11 +564,14 @@ def unregister(self, extended_zone_name: str, **kwargs: Any) -> _models.Extended except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ErrorResponse, response.json()) + error = _failsafe_deserialize( + _models.ErrorResponse, + response, + ) raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ExtendedZone, response.json()) diff --git a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_patch.py b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_patch.py index f7dd32510333..87676c65a8f0 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_patch.py +++ b/sdk/edgezones/azure-mgmt-edgezones/azure/mgmt/edgezones/operations/_patch.py @@ -1,14 +1,15 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_get.py b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_get.py index eb9c01ad0dec..010fdeba3d7b 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_get.py +++ b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_get.py @@ -36,6 +36,6 @@ def main(): print(response) -# x-ms-original-file: 2024-04-01-preview/ExtendedZones_Get.json +# x-ms-original-file: 2026-10-01/ExtendedZones_Get.json if __name__ == "__main__": main() diff --git a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_list_by_subscription.py b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_list_by_subscription.py index 72540644230d..7d6f39e64f91 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_list_by_subscription.py +++ b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_list_by_subscription.py @@ -35,6 +35,6 @@ def main(): print(item) -# x-ms-original-file: 2024-04-01-preview/ExtendedZones_ListBySubscription.json +# x-ms-original-file: 2026-10-01/ExtendedZones_ListBySubscription.json if __name__ == "__main__": main() diff --git a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_register.py b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_register.py index 717c8e21b02f..fead738b7956 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_register.py +++ b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_register.py @@ -36,6 +36,6 @@ def main(): print(response) -# x-ms-original-file: 2024-04-01-preview/ExtendedZones_Register.json +# x-ms-original-file: 2026-10-01/ExtendedZones_Register.json if __name__ == "__main__": main() diff --git a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_unregister.py b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_unregister.py index 27de3fdc934d..be42489219c9 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_unregister.py +++ b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/extended_zones_unregister.py @@ -36,6 +36,6 @@ def main(): print(response) -# x-ms-original-file: 2024-04-01-preview/ExtendedZones_Unregister.json +# x-ms-original-file: 2026-10-01/ExtendedZones_Unregister.json if __name__ == "__main__": main() diff --git a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/operations_list.py b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/operations_list.py index b4d5669291fe..a0f954e48c98 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/generated_samples/operations_list.py +++ b/sdk/edgezones/azure-mgmt-edgezones/generated_samples/operations_list.py @@ -35,6 +35,6 @@ def main(): print(item) -# x-ms-original-file: 2024-04-01-preview/Operations_List.json +# x-ms-original-file: 2026-10-01/Operations_List.json if __name__ == "__main__": main() diff --git a/sdk/edgezones/azure-mgmt-edgezones/pyproject.toml b/sdk/edgezones/azure-mgmt-edgezones/pyproject.toml index 540da07d41af..b0e348714533 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/pyproject.toml +++ b/sdk/edgezones/azure-mgmt-edgezones/pyproject.toml @@ -1,6 +1,88 @@ +[build-system] +requires = [ + "setuptools>=77.0.3", + "wheel", +] +build-backend = "setuptools.build_meta" + +[project] +name = "azure-mgmt-edgezones" +authors = [ + { name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com" }, +] +description = "Microsoft Azure Edgezones Management Client Library for Python" +license = "MIT" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +requires-python = ">=3.10" +keywords = [ + "azure", + "azure sdk", +] +dependencies = [ + "isodate>=0.6.1", + "azure-mgmt-core>=1.6.0", + "typing-extensions>=4.6.0", +] +dynamic = [ + "version", + "readme", +] + +[project.urls] +repository = "https://github.com/Azure/azure-sdk-for-python" + +[tool.setuptools.dynamic.version] +attr = "azure.mgmt.edgezones._version.VERSION" + +[tool.setuptools.dynamic.readme] +file = [ + "README.md", + "CHANGELOG.md", +] +content-type = "text/markdown" + +[tool.setuptools.packages.find] +exclude = [ + "tests*", + "generated_tests*", + "samples*", + "generated_samples*", + "doc*", + "azure", + "azure.mgmt", +] + +[tool.setuptools.package-data] +pytyped = [ + "py.typed", +] + [tool.azure-sdk-build] breaking = false mypy = false pyright = false type_check_samples = false verifytypes = false + +[packaging] +package_name = "azure-mgmt-edgezones" +package_nspkg = "azure-mgmt-nspkg" +package_pprint_name = "Edgezones Management" +package_doc_id = "" +is_stable = true +is_arm = true +need_msrestazure = false +need_azuremgmtcore = true +sample_link = "" +exclude_folders = "" +title = "EdgeZonesMgmtClient" diff --git a/sdk/edgezones/azure-mgmt-edgezones/sdk_packaging.toml b/sdk/edgezones/azure-mgmt-edgezones/sdk_packaging.toml deleted file mode 100644 index 138d55a62e9b..000000000000 --- a/sdk/edgezones/azure-mgmt-edgezones/sdk_packaging.toml +++ /dev/null @@ -1,12 +0,0 @@ -[packaging] -package_name = "azure-mgmt-edgezones" -package_nspkg = "azure-mgmt-nspkg" -package_pprint_name = "Edgezones Management" -package_doc_id = "" -is_stable = false -is_arm = true -need_msrestazure = false -need_azuremgmtcore = true -sample_link = "" -exclude_folders = "" -title = "EdgeZonesMgmtClient" diff --git a/sdk/edgezones/azure-mgmt-edgezones/setup.py b/sdk/edgezones/azure-mgmt-edgezones/setup.py deleted file mode 100644 index 7e93515ed9c8..000000000000 --- a/sdk/edgezones/azure-mgmt-edgezones/setup.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import re -import os.path -from io import open -from setuptools import find_packages, setup - -# Change the PACKAGE_NAME only to change folder and different name -PACKAGE_NAME = "azure-mgmt-edgezones" -PACKAGE_PPRINT_NAME = "Edgezones Management" - -# a-b-c => a/b/c -package_folder_path = PACKAGE_NAME.replace("-", "/") -# a-b-c => a.b.c -namespace_name = PACKAGE_NAME.replace("-", ".") - -# Version extraction inspired from 'requests' -with open( - os.path.join(package_folder_path, "version.py") - if os.path.exists(os.path.join(package_folder_path, "version.py")) - else os.path.join(package_folder_path, "_version.py"), - "r", -) as fd: - version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) - -if not version: - raise RuntimeError("Cannot find version information") - -with open("README.md", encoding="utf-8") as f: - readme = f.read() -with open("CHANGELOG.md", encoding="utf-8") as f: - changelog = f.read() - -setup( - name=PACKAGE_NAME, - version=version, - description="Microsoft Azure {} Client Library for Python".format(PACKAGE_PPRINT_NAME), - long_description=readme + "\n\n" + changelog, - long_description_content_type="text/markdown", - license="MIT License", - author="Microsoft Corporation", - author_email="azpysdkhelp@microsoft.com", - url="https://github.com/Azure/azure-sdk-for-python", - keywords="azure, azure sdk", # update with search keywords relevant to the azure service / product - classifiers=[ - "Development Status :: 4 - Beta", - "Programming Language :: Python", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "License :: OSI Approved :: MIT License", - ], - zip_safe=False, - packages=find_packages( - exclude=[ - "tests", - # Exclude packages that will be covered by PEP420 or nspkg - "azure", - "azure.mgmt", - ] - ), - include_package_data=True, - package_data={ - "pytyped": ["py.typed"], - }, - install_requires=[ - "isodate>=0.6.1", - "typing-extensions>=4.6.0", - "azure-common>=1.1", - "azure-mgmt-core>=1.3.2", - ], - python_requires=">=3.8", -) diff --git a/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml b/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml index 0af57ca89d07..bb8c93042bcc 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml +++ b/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/edgezones/EdgeZones.Management -commit: 3db6867b8e524ea6d1bc7a3bbb989fe50dd2f184 +commit: b11c849d192da49ae3d359f8b16d422f65850666 repo: Azure/azure-rest-api-specs additionalDirectories: From d637c14377b4b751e140922426f8865c38d1311f Mon Sep 17 00:00:00 2001 From: ChenxiJiang333 Date: Thu, 30 Jul 2026 10:58:45 +0800 Subject: [PATCH 2/3] update Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 959ec833-f8bd-4471-9624-d74d90df8663 --- ...test_edge_zones_mgmt_extended_zones_operations_async_test.py | 2 +- .../test_edge_zones_mgmt_extended_zones_operations_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_async_test.py b/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_async_test.py index 7bdf575b8237..910b09ea776d 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_async_test.py +++ b/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_async_test.py @@ -24,4 +24,4 @@ def setup_method(self, method): async def test_extended_zones_list_by_subscription(self, resource_group): response = self.client.extended_zones.list_by_subscription() result = [r async for r in response] - assert response + assert len(result) diff --git a/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_test.py b/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_test.py index d3961198b5aa..b3b992fcab1d 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_test.py +++ b/sdk/edgezones/azure-mgmt-edgezones/tests/test_edge_zones_mgmt_extended_zones_operations_test.py @@ -23,4 +23,4 @@ def setup_method(self, method): def test_extended_zones_list_by_subscription(self, resource_group): response = self.client.extended_zones.list_by_subscription() result = [r for r in response] - assert response + assert len(result) From 41681d409905cfb88b4ffb7cc6208c02dcd098d9 Mon Sep 17 00:00:00 2001 From: azure-sdk Date: Thu, 30 Jul 2026 14:03:48 +0000 Subject: [PATCH 3/3] Configurations: 'specification/edgezones/resource-manager/Microsoft.EdgeZones/EdgeZones/tspconfig.yaml', API Version: 2026-10-01, SDK Release Type: stable, and CommitSHA: 'e3d848eb1635fe15a89663daa425dd1619df1f37' in SpecRepo: 'https://github.com/Azure/azure-rest-api-specs' Pipeline run: https://dev.azure.com/azure-sdk/internal/_build/results?buildId=6639987 Refer to https://eng.ms/docs/products/azure-developer-experience/develop/sdk-release/sdk-release-prerequisites to prepare for SDK release. --- sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md | 2 +- sdk/edgezones/azure-mgmt-edgezones/_metadata.json | 4 ++-- sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md b/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md index 104cf602ecd0..d251c165e9f2 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md +++ b/sdk/edgezones/azure-mgmt-edgezones/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 1.0.0 (2026-07-29) +## 1.0.0 (2026-07-30) ### Features Added diff --git a/sdk/edgezones/azure-mgmt-edgezones/_metadata.json b/sdk/edgezones/azure-mgmt-edgezones/_metadata.json index 026d5c6ddb34..3c80742abd61 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/_metadata.json +++ b/sdk/edgezones/azure-mgmt-edgezones/_metadata.json @@ -3,9 +3,9 @@ "apiVersions": { "Microsoft.EdgeZones": "2026-10-01" }, - "commit": "b11c849d192da49ae3d359f8b16d422f65850666", + "commit": "e3d848eb1635fe15a89663daa425dd1619df1f37", "repository_url": "https://github.com/Azure/azure-rest-api-specs", - "typespec_src": "specification/edgezones/EdgeZones.Management", + "typespec_src": "specification/edgezones/resource-manager/Microsoft.EdgeZones/EdgeZones", "emitterVersion": "0.63.3", "httpClientPythonVersion": "^0.34.2" } \ No newline at end of file diff --git a/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml b/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml index bb8c93042bcc..4dc36c706db7 100644 --- a/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml +++ b/sdk/edgezones/azure-mgmt-edgezones/tsp-location.yaml @@ -1,4 +1,4 @@ -directory: specification/edgezones/EdgeZones.Management -commit: b11c849d192da49ae3d359f8b16d422f65850666 +directory: specification/edgezones/resource-manager/Microsoft.EdgeZones/EdgeZones +commit: e3d848eb1635fe15a89663daa425dd1619df1f37 repo: Azure/azure-rest-api-specs additionalDirectories: