Skip to content

Commit 629a2ab

Browse files
authored
[ml][pipeline] Fix pipeline job outputs not load correctly when referring local component (#34026)
* Fix pipeline job outputs not load correctly when local component reference exists Signed-off-by: Brynn Yin <[email protected]> * Filter None value out from pipeline output Signed-off-by: Brynn Yin <[email protected]> --------- Signed-off-by: Brynn Yin <[email protected]>
1 parent 89e91d9 commit 629a2ab

File tree

5 files changed

+82
-3
lines changed

5 files changed

+82
-3
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Remove `experimental` tag for `ml_client.jobs.validate`.
77

88
### Bugs Fixed
9+
- Fix pipeline job `outputs` not load correctly when `component: <local-file>` exists in pipeline job yaml.
910

1011
### Breaking Changes
1112

sdk/ml/azure-ai-ml/azure/ai/ml/entities/_job/pipeline/pipeline_job.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,10 @@ def __init__(
140140
]:
141141
self._inputs = self._build_inputs_dict(inputs, input_definition_dict=component.inputs)
142142
# for pipeline component created pipeline jobs,
143-
# it's output should have same value with the component outputs
144-
self._outputs = self._build_pipeline_outputs_dict(component.outputs)
143+
# it's output should have same value with the component outputs,
144+
# then override it with given outputs (filter out None value)
145+
pipeline_outputs = {k: v for k, v in (outputs or {}).items() if v}
146+
self._outputs = self._build_pipeline_outputs_dict({**component.outputs, **pipeline_outputs})
145147
else:
146148
# Build inputs/outputs dict without meta when definition not available
147149
self._inputs = self._build_inputs_dict(inputs)
@@ -228,6 +230,11 @@ def settings(self) -> Optional[PipelineJobSettings]:
228230

229231
@settings.setter
230232
def settings(self, value: Union[Dict, PipelineJobSettings]) -> None:
233+
"""Set the pipeline job settings.
234+
235+
:param value: The pipeline job settings.
236+
:type value: Union[dict, ~azure.ai.ml.entities.PipelineJobSettings]
237+
"""
231238
if value is not None:
232239
if isinstance(value, PipelineJobSettings):
233240
# since PipelineJobSettings inherit _AttrDict, we need add this branch to distinguish with dict

sdk/ml/azure-ai-ml/tests/pipeline_job/unittests/test_pipeline_job_schema.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
from azure.ai.ml.entities._assets import Code
2929
from azure.ai.ml.entities._component.datatransfer_component import DataTransferComponent
3030
from azure.ai.ml.entities._component.parallel_component import ParallelComponent
31+
from azure.ai.ml.entities._credentials import UserIdentityConfiguration
3132
from azure.ai.ml.entities._inputs_outputs import Input, Output
3233
from azure.ai.ml.entities._job._input_output_helpers import (
3334
INPUT_MOUNT_MAPPING_FROM_REST,
3435
validate_pipeline_input_key_characters,
3536
)
36-
from azure.ai.ml.entities._credentials import UserIdentityConfiguration
3737
from azure.ai.ml.entities._job.automl.search_space_utils import _convert_sweep_dist_dict_to_str_dict
3838
from azure.ai.ml.entities._job.job_service import (
3939
JobService,
@@ -1841,6 +1841,25 @@ def test_pipeline_component_job(self):
18411841
assert "jobs" in job_dict
18421842
assert "component_a_job" in job_dict["jobs"]
18431843

1844+
test_path = "./tests/test_configs/pipeline_jobs/pipeline_component_job_with_overrides.yml"
1845+
job: PipelineJob = load_job(source=test_path)
1846+
assert job._validate().passed
1847+
job_dict = job._to_dict()
1848+
assert job_dict["outputs"] == {
1849+
"not_exists": {"path": "azureml://datastores/mock/paths/not_exists.txt", "type": "uri_file"},
1850+
"output_path": {"path": "azureml://datastores/mock/paths/my_output_file.txt", "type": "uri_file"},
1851+
}
1852+
1853+
# Assert the output_path:None not override original component output value
1854+
test_path = "./tests/test_configs/pipeline_jobs/pipeline_component_job_with_overrides2.yml"
1855+
job: PipelineJob = load_job(source=test_path)
1856+
assert job._validate().passed
1857+
job_dict = job._to_dict()
1858+
assert job_dict["outputs"] == {
1859+
"not_exists": {"path": "azureml://datastores/mock/paths/not_exists.txt", "type": "uri_file"},
1860+
"output_path": {"type": "uri_folder"}, # uri_folder from component output
1861+
}
1862+
18441863
def test_invalid_pipeline_component_job(self):
18451864
test_path = "./tests/test_configs/pipeline_jobs/invalid/invalid_pipeline_component_job.yml"
18461865
with pytest.raises(Exception) as e:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
type: pipeline
2+
3+
description: The hello world pipeline job
4+
tags:
5+
tag: tagvalue
6+
owner: sdkteam
7+
8+
settings:
9+
default_compute: azureml:cpu-cluster
10+
11+
inputs:
12+
# examples of inputs that take values such as int, string, etc.
13+
component_in_number: 20
14+
component_in_path:
15+
path: https://dprepdata.blob.core.windows.net/demo/Titanic.csv
16+
type: uri_file
17+
18+
19+
outputs:
20+
output_path:
21+
type: uri_file
22+
path: azureml://datastores/mock/paths/my_output_file.txt
23+
not_exists:
24+
type: uri_file
25+
path: azureml://datastores/mock/paths/not_exists.txt
26+
27+
component: ../components/helloworld_pipeline_component.yml
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
type: pipeline
2+
3+
description: The hello world pipeline job
4+
tags:
5+
tag: tagvalue
6+
owner: sdkteam
7+
8+
settings:
9+
default_compute: azureml:cpu-cluster
10+
11+
inputs:
12+
# examples of inputs that take values such as int, string, etc.
13+
component_in_number: 20
14+
component_in_path:
15+
path: https://dprepdata.blob.core.windows.net/demo/Titanic.csv
16+
type: uri_file
17+
18+
19+
outputs:
20+
output_path:
21+
not_exists:
22+
type: uri_file
23+
path: azureml://datastores/mock/paths/not_exists.txt
24+
25+
component: ../components/helloworld_pipeline_component.yml

0 commit comments

Comments
 (0)