Skip to content

Commit f31ab9a

Browse files
Make batch deployment subclasses GA (Azure#40619)
* make batch deployment subclasses inherited * fix mypy issue * avoid checking instance_count population * bypass mypy signature mismatch error * fix tests * keep resources and instance_count condition same for backwards compatibility * add new line * Update optional tags for docstrings * remove unnecessary check * add more tests * handle CLI passed type param * handle type in model batch deployment * fix warning showing up in model deployment rest to python object creation * add changelog
1 parent 5c9de2a commit f31ab9a

File tree

11 files changed

+310
-207
lines changed

11 files changed

+310
-207
lines changed

sdk/ml/azure-ai-ml/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
### Other Changes
1111
- Hub and Project are officially GA'd and no longer experimental.
12+
- PipelineComponentBatchDeployment, ModelBatchDeployment, ModelBatchDeploymentSettings are GA
1213

1314
## 1.26.4 (2025-04-23)
1415

sdk/ml/azure-ai-ml/azure/ai/ml/_schema/_deployment/batch/model_batch_deployment.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99

1010
from marshmallow import fields, post_load
1111

12+
from azure.ai.ml._schema._deployment.deployment import DeploymentSchema
1213
from azure.ai.ml._schema.core.fields import ComputeField, NestedField, StringTransformedEnum
1314
from azure.ai.ml._schema.job_resource_configuration import JobResourceConfigurationSchema
14-
from azure.ai.ml._schema._deployment.deployment import DeploymentSchema
1515
from azure.ai.ml.constants._common import BASE_PATH_CONTEXT_KEY
1616
from azure.ai.ml.constants._deployment import BatchDeploymentType
17-
from azure.ai.ml._schema import ExperimentalField
18-
from .model_batch_deployment_settings import ModelBatchDeploymentSettingsSchema
1917

18+
from .model_batch_deployment_settings import ModelBatchDeploymentSettingsSchema
2019

2120
module_logger = logging.getLogger(__name__)
2221

@@ -37,7 +36,7 @@ class ModelBatchDeploymentSchema(DeploymentSchema):
3736
allowed_values=[BatchDeploymentType.PIPELINE, BatchDeploymentType.MODEL], required=False
3837
)
3938

40-
settings = ExperimentalField(NestedField(ModelBatchDeploymentSettingsSchema))
39+
settings = NestedField(ModelBatchDeploymentSettingsSchema)
4140

4241
@post_load
4342
def make(self, data: Any, **kwargs: Any) -> Any:

sdk/ml/azure-ai-ml/azure/ai/ml/_schema/_deployment/batch/pipeline_component_batch_deployment_schema.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88

99
from marshmallow import INCLUDE, fields, post_load
1010

11-
from azure.ai.ml._schema import (
12-
ArmVersionedStr,
13-
ArmStr,
14-
UnionField,
15-
RegistryStr,
16-
NestedField,
11+
from azure.ai.ml._schema import ArmStr, ArmVersionedStr, NestedField, RegistryStr, UnionField
12+
from azure.ai.ml._schema.core.fields import (
13+
PathAwareSchema,
14+
PipelineNodeNameStr,
15+
StringTransformedEnum,
16+
TypeSensitiveUnionField,
1717
)
18-
from azure.ai.ml._schema.core.fields import PipelineNodeNameStr, TypeSensitiveUnionField, PathAwareSchema
1918
from azure.ai.ml._schema.pipeline.pipeline_component import PipelineComponentFileRefField
2019
from azure.ai.ml.constants._common import AzureMLResourceType
2120
from azure.ai.ml.constants._component import NodeType
21+
from azure.ai.ml.constants._deployment import BatchDeploymentType
2222

2323
module_logger = logging.getLogger(__name__)
2424

@@ -35,7 +35,9 @@ class PipelineComponentBatchDeploymentSchema(PathAwareSchema):
3535
)
3636
settings = fields.Dict()
3737
name = fields.Str()
38-
type = fields.Str()
38+
type = StringTransformedEnum(
39+
allowed_values=[BatchDeploymentType.PIPELINE, BatchDeploymentType.MODEL], required=False
40+
)
3941
job_definition = UnionField(
4042
[
4143
ArmStr(azureml_type=AzureMLResourceType.JOB),

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

Lines changed: 98 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# pylint: disable=protected-access
66

77
import logging
8+
import warnings
89
from os import PathLike
910
from pathlib import Path
1011
from typing import Any, Dict, Optional, Union
@@ -27,13 +28,29 @@
2728

2829
from .code_configuration import CodeConfiguration
2930
from .deployment import Deployment
31+
from .model_batch_deployment_settings import ModelBatchDeploymentSettings as BatchDeploymentSettings
3032

3133
module_logger = logging.getLogger(__name__)
3234

35+
SETTINGS_ATTRIBUTES = [
36+
"output_action",
37+
"output_file_name",
38+
"error_threshold",
39+
"retry_settings",
40+
"logging_level",
41+
"mini_batch_size",
42+
"max_concurrency_per_instance",
43+
"environment_variables",
44+
]
45+
3346

3447
class BatchDeployment(Deployment):
3548
"""Batch endpoint deployment entity.
3649
50+
**Warning** This class should not be used directly.
51+
Please use one of the child implementations, :class:`~azure.ai.ml.entities.ModelBatchDeployment` or
52+
:class:`azure.ai.ml.entities.PipelineComponentBatchDeployment`.
53+
3754
:param name: the name of the batch deployment
3855
:type name: str
3956
:param description: Description of the resource.
@@ -112,34 +129,61 @@ def __init__(
112129
instance_count: Optional[int] = None, # promoted property from resources.instance_count
113130
**kwargs: Any,
114131
) -> None:
132+
_type = kwargs.pop("_type", None)
133+
134+
# Suppresses deprecation warning when object is created from REST responses
135+
# This is needed to avoid false deprecation warning on model batch deployment
136+
if _type is None and not kwargs.pop("_from_rest", False):
137+
warnings.warn(
138+
"This class is intended as a base class and it's direct usage is deprecated. "
139+
"Use one of the concrete implementations instead:\n"
140+
"* ModelBatchDeployment - For model-based batch deployments\n"
141+
"* PipelineComponentBatchDeployment - For pipeline component-based batch deployments"
142+
)
115143
self._provisioning_state: Optional[str] = kwargs.pop("provisioning_state", None)
116144

145+
settings = kwargs.pop("settings", None)
117146
super(BatchDeployment, self).__init__(
118147
name=name,
148+
type=_type,
119149
endpoint_name=endpoint_name,
120150
properties=properties,
121151
tags=tags,
122152
description=description,
123153
model=model,
124154
code_configuration=code_configuration,
125155
environment=environment,
126-
environment_variables=environment_variables,
156+
environment_variables=environment_variables, # needed, otherwise Deployment.__init__() will set it to {}
127157
code_path=code_path,
128158
scoring_script=scoring_script,
129159
**kwargs,
130160
)
131161

132162
self.compute = compute
133163
self.resources = resources
134-
self.output_action = output_action
135-
self.output_file_name = output_file_name
136-
self.error_threshold = error_threshold
137-
self.retry_settings = retry_settings
138-
self.logging_level = logging_level
139-
self.mini_batch_size = mini_batch_size
140-
self.max_concurrency_per_instance = max_concurrency_per_instance
141-
142-
if self.resources and instance_count:
164+
165+
self._settings = (
166+
settings
167+
if settings
168+
else BatchDeploymentSettings(
169+
mini_batch_size=mini_batch_size,
170+
instance_count=instance_count,
171+
max_concurrency_per_instance=max_concurrency_per_instance,
172+
output_action=output_action,
173+
output_file_name=output_file_name,
174+
retry_settings=retry_settings,
175+
environment_variables=environment_variables,
176+
error_threshold=error_threshold,
177+
logging_level=logging_level,
178+
)
179+
)
180+
181+
self._setup_instance_count()
182+
183+
def _setup_instance_count(
184+
self,
185+
) -> None: # No need to check instance_count here as it's already set in self._settings during initialization
186+
if self.resources and self._settings.instance_count:
143187
msg = "Can't set instance_count when resources is provided."
144188
raise ValidationException(
145189
message=msg,
@@ -149,8 +193,26 @@ def __init__(
149193
error_type=ValidationErrorType.INVALID_VALUE,
150194
)
151195

152-
if not self.resources and instance_count:
153-
self.resources = ResourceConfiguration(instance_count=instance_count)
196+
if not self.resources and self._settings.instance_count:
197+
self.resources = ResourceConfiguration(instance_count=self._settings.instance_count)
198+
199+
def __getattr__(self, name: str) -> Optional[Any]:
200+
# Support backwards compatibility with old BatchDeployment properties.
201+
if name in SETTINGS_ATTRIBUTES:
202+
try:
203+
return getattr(self._settings, name)
204+
except AttributeError:
205+
pass
206+
return super().__getattribute__(name)
207+
208+
def __setattr__(self, name, value):
209+
# Support backwards compatibility with old BatchDeployment properties.
210+
if name in SETTINGS_ATTRIBUTES:
211+
try:
212+
setattr(self._settings, name, value)
213+
except AttributeError:
214+
pass
215+
super().__setattr__(name, value)
154216

155217
@property
156218
def instance_count(self) -> Optional[int]:
@@ -195,7 +257,7 @@ def _yaml_output_action_to_rest_output_action(cls, yaml_output_action: Any) -> s
195257
return output_switcher.get(yaml_output_action, yaml_output_action)
196258

197259
# pylint: disable=arguments-differ
198-
def _to_rest_object(self, location: str) -> BatchDeploymentData: # type: ignore
260+
def _to_rest_object(self, location: str) -> BatchDeploymentData: # type: ignore[override]
199261
self._validate()
200262
code_config = (
201263
RestCodeConfiguration(
@@ -209,42 +271,28 @@ def _to_rest_object(self, location: str) -> BatchDeploymentData: # type: ignore
209271
environment = self.environment
210272

211273
batch_deployment: RestBatchDeployment = None
212-
if isinstance(self.output_action, str):
213-
batch_deployment = RestBatchDeployment(
214-
compute=self.compute,
215-
description=self.description,
216-
resources=self.resources._to_rest_object() if self.resources else None,
217-
code_configuration=code_config,
218-
environment_id=environment,
219-
model=model,
220-
output_file_name=self.output_file_name,
221-
output_action=BatchDeployment._yaml_output_action_to_rest_output_action(self.output_action),
222-
error_threshold=self.error_threshold,
223-
retry_settings=self.retry_settings._to_rest_object() if self.retry_settings else None,
224-
logging_level=self.logging_level,
225-
mini_batch_size=self.mini_batch_size,
226-
max_concurrency_per_instance=self.max_concurrency_per_instance,
227-
environment_variables=self.environment_variables,
228-
properties=self.properties,
229-
)
230-
else:
231-
batch_deployment = RestBatchDeployment(
232-
compute=self.compute,
233-
description=self.description,
234-
resources=self.resources._to_rest_object() if self.resources else None,
235-
code_configuration=code_config,
236-
environment_id=environment,
237-
model=model,
238-
output_file_name=self.output_file_name,
239-
output_action=None,
240-
error_threshold=self.error_threshold,
241-
retry_settings=self.retry_settings._to_rest_object() if self.retry_settings else None,
242-
logging_level=self.logging_level,
243-
mini_batch_size=self.mini_batch_size,
244-
max_concurrency_per_instance=self.max_concurrency_per_instance,
245-
environment_variables=self.environment_variables,
246-
properties=self.properties,
247-
)
274+
# Create base RestBatchDeployment object with common properties
275+
batch_deployment = RestBatchDeployment(
276+
compute=self.compute,
277+
description=self.description,
278+
resources=self.resources._to_rest_object() if self.resources else None,
279+
code_configuration=code_config,
280+
environment_id=environment,
281+
model=model,
282+
output_file_name=self.output_file_name,
283+
output_action=(
284+
BatchDeployment._yaml_output_action_to_rest_output_action(self.output_action)
285+
if isinstance(self.output_action, str)
286+
else None
287+
),
288+
error_threshold=self.error_threshold,
289+
retry_settings=self.retry_settings._to_rest_object() if self.retry_settings else None,
290+
logging_level=self.logging_level,
291+
mini_batch_size=self.mini_batch_size,
292+
max_concurrency_per_instance=self.max_concurrency_per_instance,
293+
environment_variables=self.environment_variables,
294+
properties=self.properties,
295+
)
248296

249297
return BatchDeploymentData(location=location, properties=batch_deployment, tags=self.tags)
250298

@@ -306,6 +354,7 @@ def _from_rest_object( # pylint: disable=arguments-renamed
306354
properties=properties,
307355
creation_context=SystemData._from_rest_object(deployment.system_data),
308356
provisioning_state=deployment.properties.provisioning_state,
357+
_from_rest=True,
309358
)
310359

311360
return deployment

0 commit comments

Comments
 (0)