Skip to content

Commit dc2e258

Browse files
AzurePipelinesCredential | adding mlflow uri func (#36580)
* Bug 3323988: Regex fix and indices correction for model download * fixing test case * adding mlflow tracking uri func * passing service context to azureml mlflow * final flow APC complete * modify host_url * fixing unit test cases * changing mock for urlparse * fixing the log msg
1 parent cc41627 commit dc2e258

File tree

7 files changed

+64
-13
lines changed

7 files changed

+64
-13
lines changed

sdk/ml/azure-ai-ml/azure/ai/ml/entities/_feature_store/feature_store.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ def __init__(
165165
self.compute_runtime = compute_runtime
166166

167167
@classmethod
168-
def _from_rest_object(cls, rest_obj: RestWorkspace) -> Optional["FeatureStore"]:
168+
def _from_rest_object(
169+
cls, rest_obj: RestWorkspace, v2_service_context: Optional[object] = None
170+
) -> Optional["FeatureStore"]:
169171
if not rest_obj:
170172
return None
171173

sdk/ml/azure-ai-ml/azure/ai/ml/entities/_workspace/_ai_workspaces/hub.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,11 @@ def _get_schema_class(cls):
131131
return HubSchema
132132

133133
@classmethod
134-
def _from_rest_object(cls, rest_obj: RestWorkspace) -> Optional["Hub"]:
134+
def _from_rest_object(cls, rest_obj: RestWorkspace, v2_service_context: Optional[object] = None) -> Optional["Hub"]:
135135
if not rest_obj:
136136
return None
137137

138-
workspace_object = Workspace._from_rest_object(rest_obj)
138+
workspace_object = Workspace._from_rest_object(rest_obj, v2_service_context)
139139

140140
default_resource_group = None
141141

sdk/ml/azure-ai-ml/azure/ai/ml/entities/_workspace/workspace.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,10 @@ def _load(
314314
return result
315315

316316
@classmethod
317-
def _from_rest_object(cls, rest_obj: RestWorkspace) -> Optional["Workspace"]:
317+
def _from_rest_object(
318+
cls, rest_obj: RestWorkspace, v2_service_context: Optional[object] = None
319+
) -> Optional["Workspace"]:
320+
318321
if not rest_obj:
319322
return None
320323
customer_managed_key = (
@@ -329,8 +332,20 @@ def _from_rest_object(cls, rest_obj: RestWorkspace) -> Optional["Workspace"]:
329332

330333
# TODO: Remove attribute check once Oct API version is out
331334
mlflow_tracking_uri = None
335+
332336
if hasattr(rest_obj, "ml_flow_tracking_uri"):
333-
mlflow_tracking_uri = rest_obj.ml_flow_tracking_uri
337+
try:
338+
from azureml.mlflow import get_mlflow_tracking_uri_v2
339+
340+
mlflow_tracking_uri = get_mlflow_tracking_uri_v2(rest_obj, v2_service_context)
341+
except ImportError:
342+
mlflow_tracking_uri = rest_obj.ml_flow_tracking_uri
343+
error_msg = (
344+
"azureml.mlflow could not be imported. "
345+
"Please ensure that latest 'azureml-mlflow' has been installed in the current python environment"
346+
)
347+
print(error_msg)
348+
# warnings.warn(error_msg, UserWarning)
334349

335350
# TODO: Remove once Online Endpoints updates API version to at least 2023-08-01
336351
allow_roleassignment_on_rg = None

sdk/ml/azure-ai-ml/azure/ai/ml/operations/_workspace_operations_base.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,30 @@ def get(self, workspace_name: Optional[str] = None, **kwargs: Any) -> Optional[W
8686
workspace_name = self._check_workspace_name(workspace_name)
8787
resource_group = kwargs.get("resource_group") or self._resource_group_name
8888
obj = self._operation.get(resource_group, workspace_name)
89+
v2_service_context = {}
90+
91+
v2_service_context["subscription_id"] = self._subscription_id
92+
v2_service_context["workspace_name"] = workspace_name
93+
v2_service_context["resource_group_name"] = resource_group
94+
v2_service_context["auth"] = self._credentials # type: ignore
95+
96+
from urllib.parse import urlparse
97+
98+
if obj is not None and obj.ml_flow_tracking_uri:
99+
parsed_url = urlparse(obj.ml_flow_tracking_uri)
100+
host_url = "https://{}".format(parsed_url.netloc)
101+
v2_service_context["host_url"] = host_url
102+
else:
103+
v2_service_context["host_url"] = ""
104+
105+
# host_url=service_context._get_mlflow_url(),
106+
# cloud=_get_cloud_or_default(
107+
# service_context.get_auth()._cloud_type.name
89108
if obj is not None and obj.kind is not None and obj.kind.lower() == WorkspaceKind.HUB:
90-
return Hub._from_rest_object(obj)
109+
return Hub._from_rest_object(obj, v2_service_context)
91110
if obj is not None and obj.kind is not None and obj.kind.lower() == WorkspaceKind.PROJECT:
92-
return Project._from_rest_object(obj)
93-
return Workspace._from_rest_object(obj)
111+
return Project._from_rest_object(obj, v2_service_context)
112+
return Workspace._from_rest_object(obj, v2_service_context)
94113

95114
def begin_create(
96115
self,

sdk/ml/azure-ai-ml/tests/workspace/ai_workspaces/unittests/test_mocked_operations.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ def test_list(self, arg: str, mock_hub_operation: WorkspaceOperations) -> None:
4242
else:
4343
mock_hub_operation._operation.list_by_resource_group.assert_called_once()
4444

45-
def test_get(self, mock_hub_operation: WorkspaceOperations) -> None:
45+
def test_get(self, mock_hub_operation: WorkspaceOperations, mocker: MockFixture) -> None:
46+
mocker.patch("urllib.parse.urlparse")
4647
mock_hub_operation.get(name="random_name")
4748
mock_hub_operation._operation.get.assert_called_once()
4849

sdk/ml/azure-ai-ml/tests/workspace/unittests/test_workspace_operations.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import Optional
2-
from unittest.mock import ANY, DEFAULT, MagicMock, Mock
2+
from unittest.mock import ANY, DEFAULT, MagicMock, Mock, patch
33
from uuid import UUID, uuid4
44

55
import pytest
@@ -20,6 +20,7 @@
2020
)
2121
from azure.ai.ml.operations import WorkspaceOperations
2222
from azure.core.polling import LROPoller
23+
import urllib.parse
2324

2425

2526
@pytest.fixture
@@ -87,7 +88,8 @@ def test_list(self, arg: str, mock_workspace_operation: WorkspaceOperations) ->
8788
else:
8889
mock_workspace_operation._operation.list_by_resource_group.assert_called_once()
8990

90-
def test_get(self, mock_workspace_operation: WorkspaceOperations) -> None:
91+
def test_get(self, mock_workspace_operation: WorkspaceOperations, mocker: MockFixture) -> None:
92+
mocker.patch("urllib.parse.urlparse")
9193
mock_workspace_operation.get("random_name")
9294
mock_workspace_operation._operation.get.assert_called_once()
9395

@@ -114,7 +116,8 @@ def test_begin_create(
114116
mocker.patch("azure.ai.ml._arm_deployments.ArmDeploymentExecutor.deploy_resource", return_value=LROPoller)
115117
mock_workspace_operation.begin_create(workspace=Workspace(name="name"))
116118

117-
def test_update(self, mock_workspace_operation: WorkspaceOperations) -> None:
119+
def test_update(self, mock_workspace_operation: WorkspaceOperations, mocker: MockFixture) -> None:
120+
mocker.patch("urllib.parse.urlparse")
118121
ws = Workspace(
119122
name="name",
120123
description="description",
@@ -135,6 +138,7 @@ def outgoing_call(rg, name, params, polling, cls):
135138
def test_update_with_role_assignemnt(
136139
self, mock_workspace_operation: WorkspaceOperations, mocker: MockFixture
137140
) -> None:
141+
mocker.patch("urllib.parse.urlparse")
138142
mocker.patch(
139143
"azure.ai.ml.operations.WorkspaceOperations._populate_feature_store_role_assignment_parameters",
140144
return_value=({}, {}, {}),
@@ -163,6 +167,7 @@ def outgoing_call(rg, name, params, polling, cls):
163167
mock_workspace_operation._operation.begin_update.assert_called()
164168

165169
def test_delete(self, mock_workspace_operation: WorkspaceOperations, mocker: MockFixture) -> None:
170+
mocker.patch("urllib.parse.urlparse")
166171
mocker.patch("azure.ai.ml.operations._workspace_operations_base.delete_resource_by_arm_id", return_value=None)
167172
mocker.patch(
168173
"azure.ai.ml.operations._workspace_operations_base.get_generic_arm_resource_by_arm_id", return_value=None
@@ -171,6 +176,7 @@ def test_delete(self, mock_workspace_operation: WorkspaceOperations, mocker: Moc
171176
mock_workspace_operation._operation.begin_delete.assert_called_once()
172177

173178
def test_purge(self, mock_workspace_operation: WorkspaceOperations, mocker: MockFixture) -> None:
179+
mocker.patch("urllib.parse.urlparse")
174180
mocker.patch("azure.ai.ml.operations._workspace_operations_base.delete_resource_by_arm_id", return_value=None)
175181
mocker.patch(
176182
"azure.ai.ml.operations._workspace_operations_base.get_generic_arm_resource_by_arm_id", return_value=None

sdk/ml/azure-ai-ml/tests/workspace/unittests/test_workspace_operations_base.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
)
3232
from azure.ai.ml.operations._workspace_operations_base import WorkspaceOperationsBase
3333
from azure.core.polling import LROPoller
34+
import urllib.parse
3435

3536

3637
@pytest.fixture
@@ -178,6 +179,8 @@ def test_create_get_exception_swallow(
178179
def test_begin_create_existing_ws(
179180
self, mock_workspace_operation_base: WorkspaceOperationsBase, mocker: MockFixture
180181
):
182+
mocker.patch("urllib.parse.urlparse")
183+
181184
def outgoing_call(rg, name, params, polling, cls):
182185
assert name == "name"
183186
return DEFAULT
@@ -187,7 +190,8 @@ def outgoing_call(rg, name, params, polling, cls):
187190
mock_workspace_operation_base.begin_create(workspace=Workspace(name="name"))
188191
mock_workspace_operation_base._operation.begin_update.assert_called()
189192

190-
def test_update(self, mock_workspace_operation_base: WorkspaceOperationsBase) -> None:
193+
def test_update(self, mock_workspace_operation_base: WorkspaceOperationsBase, mocker: MockFixture) -> None:
194+
mocker.patch("urllib.parse.urlparse")
191195
ws = Workspace(
192196
name="name",
193197
tags={"key": "value"},
@@ -244,6 +248,7 @@ def outgoing_call(rg, name, params, polling, cls):
244248
def test_update_with_empty_property_values(
245249
self, mock_workspace_operation_base: WorkspaceOperationsBase, mocker: MockFixture
246250
) -> None:
251+
mocker.patch("urllib.parse.urlparse")
247252
ws = Workspace(name="name", description="", display_name="", image_build_compute="")
248253
mocker.patch("azure.ai.ml.operations.WorkspaceOperations.get", return_value=ws)
249254

@@ -267,6 +272,7 @@ def outgoing_call(rg, name, params, polling, cls):
267272
mock_workspace_operation_base._operation.begin_update.assert_called()
268273

269274
def test_delete_no_wait(self, mock_workspace_operation_base: WorkspaceOperationsBase, mocker: MockFixture) -> None:
275+
mocker.patch("urllib.parse.urlparse")
270276
mocker.patch("azure.ai.ml.operations._workspace_operations_base.delete_resource_by_arm_id", return_value=None)
271277
mocker.patch(
272278
"azure.ai.ml.operations._workspace_operations_base.get_generic_arm_resource_by_arm_id", return_value=None
@@ -275,6 +281,7 @@ def test_delete_no_wait(self, mock_workspace_operation_base: WorkspaceOperations
275281
mock_workspace_operation_base._operation.begin_delete.assert_called_once()
276282

277283
def test_delete_wait(self, mock_workspace_operation_base: WorkspaceOperationsBase, mocker: MockFixture) -> None:
284+
mocker.patch("urllib.parse.urlparse")
278285
mocker.patch("azure.ai.ml.operations._workspace_operations_base.delete_resource_by_arm_id", return_value=None)
279286
mocker.patch(
280287
"azure.ai.ml.operations._workspace_operations_base.get_generic_arm_resource_by_arm_id", return_value=None
@@ -600,6 +607,7 @@ def test_update_workspace_with_serverless_custom_vnet(
600607
mock_workspace_operation_base: WorkspaceOperationsBase,
601608
mocker: MockFixture,
602609
) -> None:
610+
mocker.patch("urllib.parse.urlparse")
603611
ws = Workspace(name="name", location="test", serverless_compute=serverless_compute_settings)
604612
spy = mocker.spy(mock_workspace_operation_base._operation, "begin_update")
605613
mock_workspace_operation_base.begin_update(ws)

0 commit comments

Comments
 (0)