Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/ml/azure-ai-ml/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand All @@ -24,4 +25,4 @@ class BatchEndpointsDefaultsSchema(metaclass=PatchedSchemaMeta):

@post_load
def make(self, data: Any, **kwargs: Any) -> Any:
return dict(data)
return BatchEndpointDefaults(**data)
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <name>`` after a get().
Comment thread
ayushhgarg-work marked this conversation as resolved.
# 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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading