From 3ac1b4c1580a5cccba99004a09b21bcbc0527ce9 Mon Sep 17 00:00:00 2001 From: Ayushh Garg Date: Thu, 2 Jul 2026 15:17:25 +0530 Subject: [PATCH 1/3] Fix BatchEndpoint.defaults regression: restore attribute-access object from get() --- sdk/ml/azure-ai-ml/CHANGELOG.md | 2 +- .../batch/batch_endpoint_defaults.py | 3 ++- .../ml/entities/_endpoint/batch_endpoint.py | 16 ++++++------- .../unittests/test_endpoint_entity.py | 23 ++++++++++++++++--- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/sdk/ml/azure-ai-ml/CHANGELOG.md b/sdk/ml/azure-ai-ml/CHANGELOG.md index bc3df33c6c49..ccf329d785ff 100644 --- a/sdk/ml/azure-ai-ml/CHANGELOG.md +++ b/sdk/ml/azure-ai-ml/CHANGELOG.md @@ -11,7 +11,7 @@ ## 1.34.1 (unreleased) ### Bugs Fixed -- Fixed `BatchEndpoint` defaults serialization regression where `deployment_name` was sent to the service as snake_case instead of camelCase (`deploymentName`), causing `begin_create_or_update` to fail with "Could not find member 'deployment_name' on object of type 'BatchEndpointDefaults'". `BatchEndpoint.defaults` is now consistently exposed as a snake_case dict to users and converted to the correct wire format on serialization. +- Fixed `BatchEndpoint` defaults serialization regression where `deployment_name` was sent to the service as snake_case instead of camelCase (`deploymentName`), causing `begin_create_or_update` to fail with "Could not find member 'deployment_name' on object of type 'BatchEndpointDefaults'". Serialization now emits the correct camelCase wire format, while `BatchEndpoint.defaults` returned from `get()` continues to expose an object that supports attribute access (e.g. `endpoint.defaults.deployment_name`), preserving backward compatibility with existing code and samples. ## 1.34.0 (2026-06-11) diff --git a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/_endpoint/batch/batch_endpoint_defaults.py b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/_endpoint/batch/batch_endpoint_defaults.py index ef6cd6ff24b5..c4d7e8372773 100644 --- a/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/_endpoint/batch/batch_endpoint_defaults.py +++ b/sdk/ml/azure-ai-ml/azure/ai/ml/_schema/_endpoint/batch/batch_endpoint_defaults.py @@ -9,6 +9,7 @@ from marshmallow import fields, post_load +from azure.ai.ml._restclient.arm_ml_service.models import BatchEndpointDefaults from azure.ai.ml._schema.core.schema import PatchedSchemaMeta module_logger = logging.getLogger(__name__) @@ -24,4 +25,4 @@ class BatchEndpointsDefaultsSchema(metaclass=PatchedSchemaMeta): @post_load def make(self, data: Any, **kwargs: Any) -> Any: - return dict(data) + return BatchEndpointDefaults(**data) diff --git a/sdk/ml/azure-ai-ml/azure/ai/ml/entities/_endpoint/batch_endpoint.py b/sdk/ml/azure-ai-ml/azure/ai/ml/entities/_endpoint/batch_endpoint.py index c638a5d6bb54..466e19131344 100644 --- a/sdk/ml/azure-ai-ml/azure/ai/ml/entities/_endpoint/batch_endpoint.py +++ b/sdk/ml/azure-ai-ml/azure/ai/ml/entities/_endpoint/batch_endpoint.py @@ -97,14 +97,12 @@ def _to_rest_batch_endpoint(self, location: str) -> BatchEndpointData: @classmethod def _from_rest_object(cls, obj: BatchEndpointData) -> "BatchEndpoint": - defaults: Optional[Dict[str, str]] = None - rest_defaults = obj.properties.defaults - if isinstance(rest_defaults, RestBatchEndpointDefaults): - if rest_defaults.deployment_name is not None: - defaults = {"deployment_name": rest_defaults.deployment_name} - elif isinstance(rest_defaults, dict): - defaults = dict(rest_defaults) if rest_defaults else None - + # Pass the REST ``BatchEndpointDefaults`` object through unchanged so that + # ``endpoint.defaults.deployment_name`` remains gettable/settable. Callers + # (including the published batch-endpoint sample notebooks) rely on being + # able to do ``endpoint.defaults.deployment_name = `` after a get(). + # Serialization back to camelCase wire format is handled in + # ``_to_rest_batch_endpoint`` via the ``RestBatchEndpointDefaults`` branch. return BatchEndpoint( id=obj.id, name=obj.name, @@ -113,7 +111,7 @@ def _from_rest_object(cls, obj: BatchEndpointData) -> "BatchEndpoint": auth_mode=camel_to_snake(obj.properties.auth_mode), description=obj.properties.description, location=obj.location, - defaults=defaults, + defaults=obj.properties.defaults, provisioning_state=obj.properties.provisioning_state, scoring_uri=obj.properties.scoring_uri, openapi_uri=obj.properties.swagger_uri, diff --git a/sdk/ml/azure-ai-ml/tests/batch_online_common/unittests/test_endpoint_entity.py b/sdk/ml/azure-ai-ml/tests/batch_online_common/unittests/test_endpoint_entity.py index 4b7b0d530385..e52adbf28037 100644 --- a/sdk/ml/azure-ai-ml/tests/batch_online_common/unittests/test_endpoint_entity.py +++ b/sdk/ml/azure-ai-ml/tests/batch_online_common/unittests/test_endpoint_entity.py @@ -205,14 +205,31 @@ def test_to_rest_batch_endpoint_with_no_defaults_passes_none(self) -> None: assert rest_batch_endpoint.properties.defaults is None - def test_from_rest_object_defaults_returned_as_snake_case_dict(self) -> None: + def test_from_rest_object_defaults_supports_attribute_access(self) -> None: with open(TestBatchEndpointYAML.BATCH_ENDPOINT_REST, "r") as f: batch_endpoint_rest = _deserialize(BatchEndpointData, json.load(f)) batch_endpoint = BatchEndpoint._from_rest_object(batch_endpoint_rest) - assert batch_endpoint.defaults == {"deployment_name": "hello-world-1"} - assert batch_endpoint.defaults["deployment_name"] == "hello-world-1" + # ``endpoint.defaults`` must remain an object that supports attribute + # get/set so the published sample pattern keeps working: + # endpoint.defaults.deployment_name = deployment.name + assert batch_endpoint.defaults.deployment_name == "hello-world-1" + + def test_from_rest_object_defaults_roundtrips_to_camel_case(self) -> None: + with open(TestBatchEndpointYAML.BATCH_ENDPOINT_REST, "r") as f: + batch_endpoint_rest = _deserialize(BatchEndpointData, json.load(f)) + + batch_endpoint = BatchEndpoint._from_rest_object(batch_endpoint_rest) + + # Emulate the sample notebook flow: mutate the default deployment on the + # object returned by get() and serialize it back to the wire format. + batch_endpoint.defaults.deployment_name = "hello-world-2" + rest_batch_endpoint = batch_endpoint._to_rest_batch_endpoint("eastus") + + rest_defaults = rest_batch_endpoint.properties.defaults + assert rest_defaults.deployment_name == "hello-world-2" + assert rest_defaults.as_dict() == {"deploymentName": "hello-world-2"} class TestKubernetesOnlineEndopint: From 831242044575e4a11c3cf8434e1605c76c3533db Mon Sep 17 00:00:00 2001 From: lavakumarrepala Date: Thu, 2 Jul 2026 16:13:55 -0700 Subject: [PATCH 2/3] Change PROwner from Azure to azure-sdk --- eng/pipelines/trigger-ml-sample-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/trigger-ml-sample-pipeline.yml b/eng/pipelines/trigger-ml-sample-pipeline.yml index 8187cda0644c..70e9f20ecdb5 100644 --- a/eng/pipelines/trigger-ml-sample-pipeline.yml +++ b/eng/pipelines/trigger-ml-sample-pipeline.yml @@ -86,7 +86,7 @@ jobs: RepoName: azureml-examples RepoOwner: Azure PRBranchName: test-ml-sdk-version-${{ parameters.ServiceDirectory }}-$(Build.BuildId) - PROwner: Azure + PROwner: azure-sdk BaseBranchName: main CommitMsg: "Update sdk/python/setup.sh to target fresh built azure-ai-ml wheel." PRTitle: "SDK Samples Run generated from $(Build.BuildId)" From 83b829ec80df58a0b2ae9f9e944bf007adcea205 Mon Sep 17 00:00:00 2001 From: lavakumarrepala Date: Thu, 2 Jul 2026 18:51:27 -0700 Subject: [PATCH 3/3] Change PROwner from 'azure-sdk' to 'Azure' --- eng/pipelines/trigger-ml-sample-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/trigger-ml-sample-pipeline.yml b/eng/pipelines/trigger-ml-sample-pipeline.yml index 70e9f20ecdb5..8187cda0644c 100644 --- a/eng/pipelines/trigger-ml-sample-pipeline.yml +++ b/eng/pipelines/trigger-ml-sample-pipeline.yml @@ -86,7 +86,7 @@ jobs: RepoName: azureml-examples RepoOwner: Azure PRBranchName: test-ml-sdk-version-${{ parameters.ServiceDirectory }}-$(Build.BuildId) - PROwner: azure-sdk + PROwner: Azure BaseBranchName: main CommitMsg: "Update sdk/python/setup.sh to target fresh built azure-ai-ml wheel." PRTitle: "SDK Samples Run generated from $(Build.BuildId)"