Skip to content

Commit bd89710

Browse files
DT operation fixes (#47284)
* Fix DT operations: URL path, API version, create URL, endpoint resolution, LRO handling, and Index compatibility - Restclient: use /genericasset/v2.0/ path and 2026-05-01-preview API version (required by DT service) - Fix create URL: add missing 'deploymenttemplates' segment in request builder - Fix _get_registry_endpoint: remove recursive self._service_client call, use self._credential directly - Fix create_or_update: use polling=False to avoid LRO hang, fetch result via get() - Index operations: override base URL to /genericasset/ and pin api_version=2024-04-01-preview (Index service doesn't support v2.0 path) * Fix DT type field: always use 'deploymenttemplates' in REST body to match service route validation * Fix pylint: line-too-long and unused-variable in _deployment_template_operations.py * Fix black formatting in _index_operations.py
1 parent 4e42858 commit bd89710

8 files changed

Lines changed: 36 additions & 22 deletions

File tree

sdk/ml/azure-ai-ml/azure/ai/ml/_restclient/azure_ai_assets_v2024_04_01/azureaiassetsv20240401/_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(
5959
credential: "TokenCredential",
6060
**kwargs: Any
6161
) -> None:
62-
_endpoint = "{endpoint}/genericasset/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MachineLearningServices"
62+
_endpoint = "{endpoint}/genericasset/v2.0/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MachineLearningServices"
6363
self._config = MachineLearningServicesClientConfiguration(
6464
endpoint=endpoint,
6565
subscription_id=subscription_id,

sdk/ml/azure-ai-ml/azure/ai/ml/_restclient/azure_ai_assets_v2024_04_01/azureaiassetsv20240401/_configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(
4444
credential: "TokenCredential",
4545
**kwargs: Any
4646
) -> None:
47-
api_version: str = kwargs.pop("api_version", "2024-04-01-preview")
47+
api_version: str = kwargs.pop("api_version", "2026-05-01-preview")
4848

4949
if endpoint is None:
5050
raise ValueError("Parameter 'endpoint' must not be None.")

sdk/ml/azure-ai-ml/azure/ai/ml/_restclient/azure_ai_assets_v2024_04_01/azureaiassetsv20240401/aio/_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(
5959
credential: "AsyncTokenCredential",
6060
**kwargs: Any
6161
) -> None:
62-
_endpoint = "{endpoint}/genericasset/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MachineLearningServices"
62+
_endpoint = "{endpoint}/genericasset/v2.0/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MachineLearningServices"
6363
self._config = MachineLearningServicesClientConfiguration(
6464
endpoint=endpoint,
6565
subscription_id=subscription_id,

sdk/ml/azure-ai-ml/azure/ai/ml/_restclient/azure_ai_assets_v2024_04_01/azureaiassetsv20240401/aio/_configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(
4444
credential: "AsyncTokenCredential",
4545
**kwargs: Any
4646
) -> None:
47-
api_version: str = kwargs.pop("api_version", "2024-04-01-preview")
47+
api_version: str = kwargs.pop("api_version", "2026-05-01-preview")
4848

4949
if endpoint is None:
5050
raise ValueError("Parameter 'endpoint' must not be None.")

sdk/ml/azure-ai-ml/azure/ai/ml/_restclient/azure_ai_assets_v2024_04_01/azureaiassetsv20240401/operations/_operations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def build_deployment_templates_create_request( # pylint: disable=name-too-long
8989
accept = _headers.pop("Accept", "application/json")
9090

9191
# Construct URL
92-
_url = "/registries/{registryName}/{name}/versions/{version}"
92+
_url = "/registries/{registryName}/deploymenttemplates/{name}/versions/{version}"
9393
path_format_arguments = {
9494
"registryName": _SERIALIZER.url("registry_name", registry_name, "str"),
9595
"name": _SERIALIZER.url("name", name, "str"),

sdk/ml/azure-ai-ml/azure/ai/ml/entities/_deployment/deployment_template.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,10 @@ def _to_rest_object(self) -> dict:
564564
"version": self.version,
565565
}
566566

567-
# Always include type field
568-
if hasattr(self, "type") and self.type:
569-
result["type"] = self.type
570-
else:
571-
result["type"] = "deploymenttemplates" # Default type if not specified
567+
# Always use "deploymenttemplates" as the type value for the API wire format.
568+
# YAML schema uses "deployment_template" as the entity type identifier, but the
569+
# service validates that the type in the body matches the route ("deploymenttemplates").
570+
result["type"] = "deploymenttemplates"
572571

573572
# Add optional basic fields
574573
if self.display_name:

sdk/ml/azure-ai-ml/azure/ai/ml/operations/_deployment_template_operations.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,18 @@ def _service_client(self) -> AzureAiAssetsClient:
5656
"""
5757
if self.__service_client is None:
5858
endpoint = self._get_registry_endpoint()
59+
# Only pass through kwargs that the TypeSpec-generated AzureAiAssetsClient
60+
# can handle. MLClient injects kwargs like 'cloud', 'credential_scopes',
61+
# 'client_request_id', 'request_id' which break the client's HTTP pipeline
62+
# when passed through to its policies.
63+
_allowed_kwargs = ("user_agent", "logging_enable")
64+
client_kwargs = {k: v for k, v in self._service_client_kwargs.items() if k in _allowed_kwargs}
5965
self.__service_client = AzureAiAssetsClient(
6066
endpoint=endpoint,
6167
subscription_id=self._operation_scope.subscription_id,
6268
resource_group_name=self._operation_scope.resource_group_name,
6369
credential=self._credential,
64-
**self._service_client_kwargs,
70+
**client_kwargs,
6571
)
6672
return self.__service_client
6773

@@ -84,17 +90,12 @@ def _get_registry_endpoint(self) -> str:
8490
RegistryDiscoveryClient as ServiceClientRegistryDiscovery,
8591
)
8692

87-
# Try to get credential from service client or operation config
88-
credential = None
89-
if hasattr(self._service_client, "_config") and hasattr(self._service_client._config, "credential"):
90-
credential = self._service_client._config.credential
91-
elif hasattr(self._operation_config, "credential"):
92-
credential = self._operation_config.credential
93-
94-
if credential and self._operation_scope.registry_name:
93+
if self._credential and self._operation_scope.registry_name:
9594
# Use registry discovery API to get the primary region
9695
discovery_base_url = _get_registry_discovery_endpoint_from_metadata(_get_default_cloud_name())
97-
discovery_client = ServiceClientRegistryDiscovery(credential=credential, base_url=discovery_base_url)
96+
discovery_client = ServiceClientRegistryDiscovery(
97+
credential=self._credential, base_url=discovery_base_url
98+
)
9899
response = discovery_client.registry_management_non_workspace.get_registry_management_non_workspace(
99100
self._operation_scope.registry_name
100101
)
@@ -106,7 +107,7 @@ def _get_registry_endpoint(self) -> str:
106107
module_logger.debug("Could not determine registry region dynamically: %s. Using default.", e)
107108

108109
# Fallback to default region if unable to determine dynamically
109-
return "https://int.experiments.azureml-test.net"
110+
return "https://eastus.api.azureml.ms"
110111

111112
def _convert_dict_to_deployment_template(self, dict_data: Dict[str, Any]) -> DeploymentTemplate:
112113
"""Convert dictionary format to DeploymentTemplate object.
@@ -367,9 +368,15 @@ def create_or_update(self, deployment_template: DeploymentTemplate, **kwargs: An
367368
name=deployment_template.name,
368369
version=deployment_template.version,
369370
body=rest_object,
371+
polling=False,
370372
**kwargs,
371373
)
372-
return deployment_template
374+
# Fire the LRO but don't wait for polling — the asset is available immediately.
375+
# Fetch the created/updated resource to return the server-side state.
376+
try:
377+
return self.get(deployment_template.name, deployment_template.version)
378+
except Exception:
379+
return deployment_template
373380

374381
@distributed_trace
375382
@monitor_with_telemetry_mixin(ops_logger, "DeploymentTemplate.Delete", ActivityType.PUBLICAPI)

sdk/ml/azure-ai-ml/azure/ai/ml/operations/_index_operations.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,17 @@ def _azure_ai_assets(self) -> AzureAiAssetsClient042024:
117117
resource_group_name=self._operation_scope.resource_group_name,
118118
workspace_name=self._operation_scope.workspace_name,
119119
credential=self._credential,
120+
api_version="2024-04-01-preview",
120121
**self._service_client_kwargs,
121122
)
122123

124+
# Index operations require the legacy /genericasset/ path (without v2.0).
125+
# The TypeSpec-generated client defaults to /genericasset/v2.0/ which is needed
126+
# for DeploymentTemplate operations, but the Index service returns HTTP 500 on
127+
# the v2.0 path for write operations. Override the base URL to use the legacy path.
128+
base_url = self.__azure_ai_assets_client._client._base_url
129+
self.__azure_ai_assets_client._client._base_url = base_url.replace("/genericasset/v2.0/", "/genericasset/")
130+
123131
return self.__azure_ai_assets_client
124132

125133
@monitor_with_activity(ops_logger, "Index.CreateOrUpdate", ActivityType.PUBLICAPI)

0 commit comments

Comments
 (0)