|
7 | 7 |
|
8 | 8 | import pydash
|
9 | 9 | import pytest
|
10 |
| -from pipeline_job.e2etests.test_pipeline_job import assert_job_input_output_types |
11 |
| -from test_utilities.utils import _PYTEST_TIMEOUT_METHOD, omit_with_wildcard |
12 |
| - |
13 | 10 | from azure.ai.ml import (
|
14 | 11 | Input,
|
15 | 12 | MLClient,
|
|
25 | 22 | from azure.ai.ml.constants._common import AssetTypes, InputOutputModes
|
26 | 23 | from azure.ai.ml.constants._job.pipeline import PipelineConstants
|
27 | 24 | from azure.ai.ml.dsl._load_import import to_component
|
| 25 | +from azure.ai.ml.dsl._parameter_group_decorator import parameter_group |
28 | 26 | from azure.ai.ml.entities import CommandComponent, CommandJob
|
29 | 27 | from azure.ai.ml.entities import Component
|
30 | 28 | from azure.ai.ml.entities import Component as ComponentEntity
|
31 | 29 | from azure.ai.ml.entities import Data, PipelineJob
|
32 | 30 | from azure.ai.ml.exceptions import ValidationException
|
33 | 31 | from azure.ai.ml.parallel import ParallelJob, RunFunction, parallel_run_function
|
| 32 | +from azure.core.exceptions import HttpResponseError |
34 | 33 | from azure.core.polling import LROPoller
|
| 34 | +from devtools_testutils import AzureRecordedTestCase |
| 35 | +from pipeline_job.e2etests.test_pipeline_job import assert_job_input_output_types |
| 36 | +from test_utilities.utils import _PYTEST_TIMEOUT_METHOD, omit_with_wildcard |
35 | 37 |
|
36 | 38 | from .._util import _DSL_TIMEOUT_SECOND
|
37 | 39 |
|
38 |
| -from devtools_testutils import AzureRecordedTestCase |
39 |
| - |
40 | 40 | tests_root_dir = Path(__file__).parent.parent.parent
|
41 | 41 | components_dir = tests_root_dir / "test_configs/components/"
|
42 | 42 | job_input = Input(
|
|
57 | 57 | ]
|
58 | 58 |
|
59 | 59 |
|
| 60 | +def assert_job_cancel(pipeline, client: MLClient): |
| 61 | + job = client.jobs.create_or_update(pipeline) |
| 62 | + try: |
| 63 | + cancel_poller = client.jobs.begin_cancel(job.name) |
| 64 | + assert isinstance(cancel_poller, LROPoller) |
| 65 | + assert cancel_poller.result() is None |
| 66 | + except HttpResponseError: |
| 67 | + pass |
| 68 | + return job |
| 69 | + |
| 70 | + |
60 | 71 | @pytest.mark.usefixtures(
|
61 | 72 | "enable_environment_id_arm_expansion",
|
62 | 73 | "enable_pipeline_private_preview_features",
|
@@ -1058,7 +1069,6 @@ def valid_pipeline_func(
|
1058 | 1069 | required_input: Input,
|
1059 | 1070 | required_param: str,
|
1060 | 1071 | node_compute: str = "cpu-cluster",
|
1061 |
| - # node_compute: str = 'azureml:cpu-cluster', # both will be supported |
1062 | 1072 | ):
|
1063 | 1073 | default_optional_func(
|
1064 | 1074 | required_input=required_input,
|
@@ -1090,6 +1100,64 @@ def valid_pipeline_func(
|
1090 | 1100 | in caplog.messages
|
1091 | 1101 | )
|
1092 | 1102 |
|
| 1103 | + def test_create_pipeline_with_parameter_group(self, client: MLClient) -> None: |
| 1104 | + default_optional_func = load_component(source=str(components_dir / "default_optional_component.yml")) |
| 1105 | + |
| 1106 | + @parameter_group |
| 1107 | + class SubGroup: |
| 1108 | + required_param: str |
| 1109 | + |
| 1110 | + @parameter_group |
| 1111 | + class Group: |
| 1112 | + sub: SubGroup |
| 1113 | + node_compute: str = "cpu-cluster" |
| 1114 | + |
| 1115 | + @dsl.pipeline() |
| 1116 | + def sub_pipeline_func( |
| 1117 | + required_input: Input, |
| 1118 | + group: Group, |
| 1119 | + sub_group: SubGroup, |
| 1120 | + ): |
| 1121 | + default_optional_func( |
| 1122 | + required_input=required_input, |
| 1123 | + required_param=group.sub.required_param, |
| 1124 | + ) |
| 1125 | + node2 = default_optional_func( |
| 1126 | + required_input=required_input, |
| 1127 | + required_param=sub_group.required_param, |
| 1128 | + ) |
| 1129 | + node2.compute = group.node_compute |
| 1130 | + |
| 1131 | + @dsl.pipeline(default_compute="cpu-cluster") |
| 1132 | + def root_pipeline_with_group( |
| 1133 | + r_required_input: Input, |
| 1134 | + r_group: Group, |
| 1135 | + ): |
| 1136 | + sub_pipeline_func(required_input=r_required_input, group=r_group, sub_group=r_group.sub) |
| 1137 | + |
| 1138 | + job = root_pipeline_with_group( |
| 1139 | + r_required_input=Input(type="uri_file", path="https://dprepdata.blob.core.windows.net/demo/Titanic.csv"), |
| 1140 | + r_group=Group(sub=SubGroup(required_param="hello")), |
| 1141 | + ) |
| 1142 | + rest_job = assert_job_cancel(job, client) |
| 1143 | + assert len(rest_job.inputs) == 2 |
| 1144 | + rest_job_dict = rest_job._to_dict() |
| 1145 | + assert rest_job_dict["inputs"] == { |
| 1146 | + "r_required_input": { |
| 1147 | + "mode": "ro_mount", |
| 1148 | + "type": "uri_file", |
| 1149 | + "path": "azureml:https://dprepdata.blob.core.windows.net/demo/Titanic.csv", |
| 1150 | + }, |
| 1151 | + "r_group.sub.required_param": "hello", |
| 1152 | + "r_group.node_compute": "cpu-cluster", |
| 1153 | + } |
| 1154 | + assert rest_job_dict["jobs"]["sub_pipeline_func"]["inputs"] == { |
| 1155 | + "required_input": {"path": "${{parent.inputs.r_required_input}}"}, |
| 1156 | + "group.sub.required_param": {"path": "${{parent.inputs.r_group.sub.required_param}}"}, |
| 1157 | + "group.node_compute": {"path": "${{parent.inputs.r_group.node_compute}}"}, |
| 1158 | + "sub_group.required_param": {"path": "${{parent.inputs.r_group.sub.required_param}}"}, |
| 1159 | + } |
| 1160 | + |
1093 | 1161 | def test_pipeline_with_none_parameter_has_default_optional_true(self, client: MLClient) -> None:
|
1094 | 1162 | default_optional_func = load_component(source=str(components_dir / "default_optional_component.yml"))
|
1095 | 1163 |
|
@@ -1525,9 +1593,7 @@ def parallel_in_pipeline(job_data_path, score_model):
|
1525 | 1593 | assert_job_input_output_types(pipeline_job)
|
1526 | 1594 | assert pipeline_job.settings.default_compute == "cpu-cluster"
|
1527 | 1595 |
|
1528 |
| - @pytest.mark.skip( |
1529 |
| - "https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659" |
1530 |
| - ) |
| 1596 | + @pytest.mark.skip("https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659") |
1531 | 1597 | def test_parallel_components_with_file_input(self, client: MLClient) -> None:
|
1532 | 1598 | components_dir = tests_root_dir / "test_configs/dsl_pipeline/parallel_component_with_file_input"
|
1533 | 1599 |
|
@@ -1958,11 +2024,11 @@ def pipeline(job_in_number, job_in_other_number, job_in_path):
|
1958 | 2024 | client.jobs.get(child.name)
|
1959 | 2025 | client.jobs.get(child.name)._repr_html_()
|
1960 | 2026 |
|
1961 |
| - @pytest.mark.skip( |
1962 |
| - "https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659" |
1963 |
| - ) |
| 2027 | + @pytest.mark.skip("https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659") |
1964 | 2028 | def test_dsl_pipeline_without_setting_binding_node(self, client: MLClient) -> None:
|
1965 |
| - from test_configs.dsl_pipeline.pipeline_with_set_binding_output_input.pipeline import pipeline_without_setting_binding_node |
| 2029 | + from test_configs.dsl_pipeline.pipeline_with_set_binding_output_input.pipeline import ( |
| 2030 | + pipeline_without_setting_binding_node, |
| 2031 | + ) |
1966 | 2032 |
|
1967 | 2033 | pipeline = pipeline_without_setting_binding_node()
|
1968 | 2034 | pipeline_job = client.jobs.create_or_update(pipeline)
|
@@ -2011,9 +2077,7 @@ def test_dsl_pipeline_without_setting_binding_node(self, client: MLClient) -> No
|
2011 | 2077 | }
|
2012 | 2078 | assert expected_job == actual_job
|
2013 | 2079 |
|
2014 |
| - @pytest.mark.skip( |
2015 |
| - "https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659" |
2016 |
| - ) |
| 2080 | + @pytest.mark.skip("https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659") |
2017 | 2081 | def test_dsl_pipeline_with_only_setting_pipeline_level(self, client: MLClient) -> None:
|
2018 | 2082 | from test_configs.dsl_pipeline.pipeline_with_set_binding_output_input.pipeline import (
|
2019 | 2083 | pipeline_with_only_setting_pipeline_level,
|
@@ -2066,12 +2130,12 @@ def test_dsl_pipeline_with_only_setting_pipeline_level(self, client: MLClient) -
|
2066 | 2130 | }
|
2067 | 2131 | assert expected_job == actual_job
|
2068 | 2132 |
|
2069 |
| - @pytest.mark.skip( |
2070 |
| - "https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659" |
2071 |
| - ) |
| 2133 | + @pytest.mark.skip("https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659") |
2072 | 2134 | def test_dsl_pipeline_with_only_setting_binding_node(self, client: MLClient) -> None:
|
2073 | 2135 | # Todo: checkout run priority when backend is ready
|
2074 |
| - from test_configs.dsl_pipeline.pipeline_with_set_binding_output_input.pipeline import pipeline_with_only_setting_binding_node |
| 2136 | + from test_configs.dsl_pipeline.pipeline_with_set_binding_output_input.pipeline import ( |
| 2137 | + pipeline_with_only_setting_binding_node, |
| 2138 | + ) |
2075 | 2139 |
|
2076 | 2140 | pipeline = pipeline_with_only_setting_binding_node()
|
2077 | 2141 | pipeline_job = client.jobs.create_or_update(pipeline)
|
@@ -2130,9 +2194,7 @@ def test_dsl_pipeline_with_only_setting_binding_node(self, client: MLClient) ->
|
2130 | 2194 | }
|
2131 | 2195 | assert expected_job == actual_job
|
2132 | 2196 |
|
2133 |
| - @pytest.mark.skip( |
2134 |
| - "https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659" |
2135 |
| - ) |
| 2197 | + @pytest.mark.skip("https://dev.azure.com/msdata/Vienna/_workitems/edit/2009659") |
2136 | 2198 | def test_dsl_pipeline_with_setting_binding_node_and_pipeline_level(self, client: MLClient) -> None:
|
2137 | 2199 | from test_configs.dsl_pipeline.pipeline_with_set_binding_output_input.pipeline import (
|
2138 | 2200 | pipeline_with_setting_binding_node_and_pipeline_level,
|
|
0 commit comments