From bf66e52332650a1780e06d82b09b638143b3443b Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 15:15:33 +0800 Subject: [PATCH 1/8] Add some package and resource checks Signed-off-by: Brynn Yin --- .../azure/operations/_run_operations.py | 2 +- src/promptflow-core/promptflow/_constants.py | 1 + .../core/_connection_provider/_utils.py | 17 +++++++-- .../_workspace_connection_provider.py | 36 +++++++++++++++++-- .../promptflow/core/_errors.py | 12 +++++++ .../_serving/extension/azureml_extension.py | 2 +- .../promptflow/_sdk/entities/_run.py | 2 +- .../_local_azure_connection_operations.py | 8 +++++ 8 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/promptflow-azure/promptflow/azure/operations/_run_operations.py b/src/promptflow-azure/promptflow/azure/operations/_run_operations.py index f50d2a98449..a163b86af89 100644 --- a/src/promptflow-azure/promptflow/azure/operations/_run_operations.py +++ b/src/promptflow-azure/promptflow/azure/operations/_run_operations.py @@ -125,7 +125,7 @@ def _workspace_default_datastore(self): if kind not in [AzureWorkspaceKind.DEFAULT, AzureWorkspaceKind.PROJECT]: raise RunOperationParameterError( "Failed to get default workspace datastore. Please make sure you are using the right workspace which " - f"is either an azure machine learning studio workspace or an azure ai project. Got {kind!r} instead." + f"is either an azure machine learning workspace or an azure ai project. Got {kind!r} instead." ) return self._datastore_operations.get_default() diff --git a/src/promptflow-core/promptflow/_constants.py b/src/promptflow-core/promptflow/_constants.py index 78c2956e8c8..8e85666e470 100644 --- a/src/promptflow-core/promptflow/_constants.py +++ b/src/promptflow-core/promptflow/_constants.py @@ -277,6 +277,7 @@ class ConnectionProviderConfig: "(/providers/Microsoft.MachineLearningServices)?/workspaces/([^/]+)$" ) CONNECTION_DATA_CLASS_KEY = "DATA_CLASS" +AML_CONNECTION_PROVIDER_TEMPLATE = "azureml://subscriptions/{}/resourceGroups/{}/providers/Microsoft.MachineLearningServices/workspaces/{}" # noqa: E501 class AzureWorkspaceKind: diff --git a/src/promptflow-core/promptflow/core/_connection_provider/_utils.py b/src/promptflow-core/promptflow/core/_connection_provider/_utils.py index 4ac642e76a1..6594c2dd1d1 100644 --- a/src/promptflow-core/promptflow/core/_connection_provider/_utils.py +++ b/src/promptflow-core/promptflow/core/_connection_provider/_utils.py @@ -3,9 +3,9 @@ # --------------------------------------------------------- import os -from promptflow._constants import PF_NO_INTERACTIVE_LOGIN +from promptflow._constants import PF_NO_INTERACTIVE_LOGIN, AzureWorkspaceKind from promptflow._utils.user_agent_utils import ClientUserAgentUtil -from promptflow.core._errors import MissingRequiredPackage +from promptflow.core._errors import MissingRequiredPackage, UnsupportedWorkspaceKind from promptflow.exceptions import ValidationException @@ -15,7 +15,7 @@ def check_required_packages(): import azure.identity # noqa: F401 except ImportError as e: raise MissingRequiredPackage( - message="Please install 'promptflow-core[azureml-serving]' to use workspace related features." + message="Please install 'promptflow-core[azureml-serving]' to use Azure related features." ) from e @@ -67,3 +67,14 @@ def interactive_credential_disabled(): def is_from_cli(): """Check if the current execution is from promptflow-cli.""" return "promptflow-cli" in ClientUserAgentUtil.get_user_agent() + + +def check_connection_provider_resource(resource_id: str, credential, pkg_name): + from .._utils import get_workspace_from_resource_id + + workspace = get_workspace_from_resource_id(resource_id, credential, pkg_name) + if workspace._kind not in [AzureWorkspaceKind.DEFAULT, AzureWorkspaceKind.PROJECT]: + raise UnsupportedWorkspaceKind( + message=f"Workspace kind {workspace._kind!r} is not supported. " + f"Please use either an azure machine learning workspace or an azure ai project." + ) diff --git a/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py b/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py index f7edb5f9c4a..5d48f54e9f9 100644 --- a/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py +++ b/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py @@ -6,7 +6,7 @@ import requests -from promptflow._constants import ConnectionAuthMode +from promptflow._constants import AML_CONNECTION_PROVIDER_TEMPLATE, ConnectionAuthMode from promptflow._utils.retry_utils import http_retry_wrapper from promptflow.core._connection import CustomConnection, _Connection from promptflow.core._errors import ( @@ -16,6 +16,7 @@ MissingRequiredPackage, OpenURLFailed, OpenURLFailedUserError, + OpenURLNotFoundError, OpenURLUserAuthenticationError, UnknownConnectionType, UnsupportedConnectionAuthType, @@ -24,7 +25,12 @@ from ..._utils.credential_utils import get_default_azure_credential from ._connection_provider import ConnectionProvider -from ._utils import interactive_credential_disabled, is_from_cli, is_github_codespaces +from ._utils import ( + check_connection_provider_resource, + interactive_credential_disabled, + is_from_cli, + is_github_codespaces, +) GET_CONNECTION_URL = ( "/subscriptions/{sub}/resourcegroups/{rg}/providers/Microsoft.MachineLearningServices" @@ -76,6 +82,10 @@ def __init__( self.subscription_id = subscription_id self.resource_group_name = resource_group_name self.workspace_name = workspace_name + self.resource_id = AML_CONNECTION_PROVIDER_TEMPLATE.format( + self.subscription_id, self.resource_group_name, self.workspace_name + ) + self._workspace_checked = False @property def credential(self): @@ -131,7 +141,13 @@ def open_url(cls, token, url, action, host="management.azure.com", method="GET", f"Open url {{url}} failed with status code: {response.status_code}, action: {action}, reason: {{reason}}" ) if response.status_code == 403: - raise AccessDeniedError(operation=url, target=ErrorTarget.RUNTIME) + raise AccessDeniedError(operation=url, target=ErrorTarget.CORE) + elif response.status_code == 404: + raise OpenURLNotFoundError( + message_format=message_format, + url=url, + reason=response.reason, + ) elif 400 <= response.status_code < 500: raise OpenURLFailedUserError( message_format=message_format, @@ -404,6 +420,8 @@ def _build_list_connection_dict( raise OpenURLUserAuthenticationError(message=auth_error_message) except ClientAuthenticationError as e: raise UserErrorException(target=ErrorTarget.CORE, message=str(e), error=e) from e + except UserErrorException: + raise except Exception as e: raise SystemErrorException(target=ErrorTarget.CORE, message=str(e), error=e) from e @@ -417,6 +435,12 @@ def _build_list_connection_dict( return rest_list_connection_dict def list(self) -> List[_Connection]: + if not self._workspace_checked: + # Check workspace not 'hub' + check_connection_provider_resource( + resource_id=self.resource_id, credential=self.credential, pkg_name="promptflow-core[azureml-serving]" + ) + self._workspace_checked = True rest_list_connection_dict = self._build_list_connection_dict( subscription_id=self.subscription_id, resource_group_name=self.resource_group_name, @@ -432,6 +456,12 @@ def list(self) -> List[_Connection]: return connection_list def get(self, name: str, **kwargs) -> _Connection: + if not self._workspace_checked: + # Check workspace not 'hub' + check_connection_provider_resource( + resource_id=self.resource_id, credential=self.credential, pkg_name="promptflow-core[azureml-serving]" + ) + self._workspace_checked = True connection_dict = self._build_connection_dict( name, subscription_id=self.subscription_id, diff --git a/src/promptflow-core/promptflow/core/_errors.py b/src/promptflow-core/promptflow/core/_errors.py index 95380d0d689..c742de0afbd 100644 --- a/src/promptflow-core/promptflow/core/_errors.py +++ b/src/promptflow-core/promptflow/core/_errors.py @@ -100,6 +100,11 @@ def __init__(self, **kwargs): super().__init__(target=ErrorTarget.CORE, **kwargs) +class OpenURLNotFoundError(UserErrorException): + def __init__(self, **kwargs): + super().__init__(target=ErrorTarget.CORE, **kwargs) + + class UnknownConnectionType(UserErrorException): def __init__(self, **kwargs): super().__init__(target=ErrorTarget.CORE, **kwargs) @@ -127,6 +132,13 @@ def __init__(self, provider_config, **kwargs): super().__init__(target=ErrorTarget.CORE, message=message, **kwargs) +class UnsupportedWorkspaceKind(UserErrorException): + """Exception raised when workspace kind is not supported.""" + + def __init__(self, message, **kwargs): + super().__init__(target=ErrorTarget.CORE, message=message, **kwargs) + + class AccessDeniedError(UserErrorException): """Exception raised when run info can not be found in storage""" diff --git a/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py b/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py index c5ab797d0b9..78dd01d4fce 100644 --- a/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py +++ b/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py @@ -7,6 +7,7 @@ import re from typing import Any, Tuple +from promptflow._constants import AML_CONNECTION_PROVIDER_TEMPLATE from promptflow._utils.retry_utils import retry from promptflow.contracts.flow import Flow from promptflow.core._serving._errors import InvalidConnectionData, MissingConnectionProvider @@ -18,7 +19,6 @@ USER_AGENT = f"promptflow-cloud-serving/{__version__}" AML_DEPLOYMENT_RESOURCE_ID_REGEX = "/subscriptions/(.*)/resourceGroups/(.*)/providers/Microsoft.MachineLearningServices/workspaces/(.*)/onlineEndpoints/(.*)/deployments/(.*)" # noqa: E501 -AML_CONNECTION_PROVIDER_TEMPLATE = "azureml://subscriptions/{}/resourceGroups/{}/providers/Microsoft.MachineLearningServices/workspaces/{}" # noqa: E501 class AzureMLExtension(AppExtension): diff --git a/src/promptflow-devkit/promptflow/_sdk/entities/_run.py b/src/promptflow-devkit/promptflow/_sdk/entities/_run.py index 76415c3e003..1ce1da7b2ca 100644 --- a/src/promptflow-devkit/promptflow/_sdk/entities/_run.py +++ b/src/promptflow-devkit/promptflow/_sdk/entities/_run.py @@ -515,7 +515,7 @@ def _format_display_name(self) -> str: def _get_flow_dir(self) -> Path: if not self._use_remote_flow: - flow = Path(self.flow) + flow = Path(str(self.flow)).resolve().absolute() if flow.is_dir(): return flow return flow.parent diff --git a/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py b/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py index e23d66f9534..2537307c31e 100644 --- a/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py +++ b/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py @@ -15,6 +15,7 @@ is_from_cli, is_github_codespaces, ) +from promptflow.core._errors import MissingRequiredPackage from promptflow.core._utils import extract_workspace logger = get_cli_sdk_logger() @@ -22,6 +23,13 @@ class LocalAzureConnectionOperations(WorkspaceTelemetryMixin): def __init__(self, connection_provider, **kwargs): + try: + import promptflow.azure # noqa: F401 + except ImportError as e: + error_msg = ( + "Please install Azure extension (e.g. `pip install promptflow-azure`) to use Azure related features." + ) + raise MissingRequiredPackage(message=error_msg) from e self._subscription_id, self._resource_group, self._workspace_name = extract_workspace(connection_provider) self._credential = kwargs.pop("credential", None) or self._get_credential() super().__init__( From 1f32fb1b03959d0fc1fb51d1bb453de5565e88c9 Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 15:59:06 +0800 Subject: [PATCH 2/8] Refine name Signed-off-by: Brynn Yin --- src/promptflow-core/promptflow/_constants.py | 2 +- .../_connection_provider/_workspace_connection_provider.py | 4 ++-- .../promptflow/core/_serving/extension/azureml_extension.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/promptflow-core/promptflow/_constants.py b/src/promptflow-core/promptflow/_constants.py index 8e85666e470..ba6ab76fa08 100644 --- a/src/promptflow-core/promptflow/_constants.py +++ b/src/promptflow-core/promptflow/_constants.py @@ -277,7 +277,7 @@ class ConnectionProviderConfig: "(/providers/Microsoft.MachineLearningServices)?/workspaces/([^/]+)$" ) CONNECTION_DATA_CLASS_KEY = "DATA_CLASS" -AML_CONNECTION_PROVIDER_TEMPLATE = "azureml://subscriptions/{}/resourceGroups/{}/providers/Microsoft.MachineLearningServices/workspaces/{}" # noqa: E501 +AML_WORKSPACE_TEMPLATE = "azureml://subscriptions/{}/resourceGroups/{}/providers/Microsoft.MachineLearningServices/workspaces/{}" # noqa: E501 class AzureWorkspaceKind: diff --git a/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py b/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py index 5d48f54e9f9..e4fab554442 100644 --- a/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py +++ b/src/promptflow-core/promptflow/core/_connection_provider/_workspace_connection_provider.py @@ -6,7 +6,7 @@ import requests -from promptflow._constants import AML_CONNECTION_PROVIDER_TEMPLATE, ConnectionAuthMode +from promptflow._constants import AML_WORKSPACE_TEMPLATE, ConnectionAuthMode from promptflow._utils.retry_utils import http_retry_wrapper from promptflow.core._connection import CustomConnection, _Connection from promptflow.core._errors import ( @@ -82,7 +82,7 @@ def __init__( self.subscription_id = subscription_id self.resource_group_name = resource_group_name self.workspace_name = workspace_name - self.resource_id = AML_CONNECTION_PROVIDER_TEMPLATE.format( + self.resource_id = AML_WORKSPACE_TEMPLATE.format( self.subscription_id, self.resource_group_name, self.workspace_name ) self._workspace_checked = False diff --git a/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py b/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py index 78dd01d4fce..9170993cf69 100644 --- a/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py +++ b/src/promptflow-core/promptflow/core/_serving/extension/azureml_extension.py @@ -7,7 +7,7 @@ import re from typing import Any, Tuple -from promptflow._constants import AML_CONNECTION_PROVIDER_TEMPLATE +from promptflow._constants import AML_WORKSPACE_TEMPLATE from promptflow._utils.retry_utils import retry from promptflow.contracts.flow import Flow from promptflow.core._serving._errors import InvalidConnectionData, MissingConnectionProvider @@ -159,7 +159,7 @@ def _initialize_connection_provider(self): message="Missing connection provider, please check whether 'PROMPTFLOW_CONNECTION_PROVIDER' " "is in your environment variable list." ) # noqa: E501 - self.connection_provider = AML_CONNECTION_PROVIDER_TEMPLATE.format( + self.connection_provider = AML_WORKSPACE_TEMPLATE.format( self.subscription_id, self.resource_group, self.workspace_name ) # noqa: E501 From 5f09f16a555a8b0f38257748eb22df80b83e7e41 Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 16:03:39 +0800 Subject: [PATCH 3/8] Revert check Signed-off-by: Brynn Yin --- .../_sdk/operations/_local_azure_connection_operations.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py b/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py index 2537307c31e..e23d66f9534 100644 --- a/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py +++ b/src/promptflow-devkit/promptflow/_sdk/operations/_local_azure_connection_operations.py @@ -15,7 +15,6 @@ is_from_cli, is_github_codespaces, ) -from promptflow.core._errors import MissingRequiredPackage from promptflow.core._utils import extract_workspace logger = get_cli_sdk_logger() @@ -23,13 +22,6 @@ class LocalAzureConnectionOperations(WorkspaceTelemetryMixin): def __init__(self, connection_provider, **kwargs): - try: - import promptflow.azure # noqa: F401 - except ImportError as e: - error_msg = ( - "Please install Azure extension (e.g. `pip install promptflow-azure`) to use Azure related features." - ) - raise MissingRequiredPackage(message=error_msg) from e self._subscription_id, self._resource_group, self._workspace_name = extract_workspace(connection_provider) self._credential = kwargs.pop("credential", None) or self._get_credential() super().__init__( From 84e7f3dce68b3504a035bfca6f2c695aeccc8380 Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 16:20:14 +0800 Subject: [PATCH 4/8] Update recording Signed-off-by: Brynn Yin --- ...nectionOperations_test_get_connection.yaml | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml b/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml index 7ee0a697274..2db5eebca03 100644 --- a/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml +++ b/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml @@ -9,21 +9,21 @@ interactions: Connection: - keep-alive User-Agent: - - promptflow-sdk/0.0.1 promptflow/0.0.1 azure-ai-ml/1.12.1 azsdk-python-mgmt-machinelearningservices/0.1.0 - Python/3.10.13 (Windows-10-10.0.22631-SP0) + - promptflow-azure-sdk/0.1.0b1 azure-ai-ml/1.15.0 azsdk-python-mgmt-machinelearningservices/0.1.0 + Python/3.9.19 (Windows-10-10.0.22631-SP0) method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/api-version=2023-08-01-preview response: body: string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000", "name": "00000", "type": "Microsoft.MachineLearningServices/workspaces", "location": - "eastus", "tags": {}, "etag": null, "kind": "Default", "sku": {"name": "Basic", - "tier": "Basic"}, "properties": {"discoveryUrl": "https://eastus.api.azureml.ms/discovery"}}' + "eastus2euap", "tags": {}, "etag": null, "kind": "Default", "sku": {"name": + "Basic", "tier": "Basic"}, "properties": {"discoveryUrl": "https://eastus.api.azureml.ms/discovery"}}' headers: cache-control: - no-cache content-length: - - '3630' + - '3697' content-type: - application/json; charset=utf-8 expires: @@ -39,7 +39,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.017' + - '0.022' status: code: 200 message: OK @@ -53,29 +53,21 @@ interactions: Connection: - keep-alive User-Agent: - - promptflow-sdk/0.0.1 promptflow/0.0.1 azure-ai-ml/1.12.1 azsdk-python-mgmt-machinelearningservices/0.1.0 - Python/3.10.13 (Windows-10-10.0.22631-SP0) + - azure-ai-ml/1.15.0 azsdk-python-mgmt-machinelearningservices/0.1.0 Python/3.9.19 + (Windows-10-10.0.22631-SP0) method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/datastores?api-version=2023-04-01-preview&count=30&isDefault=true&orderByAsc=false + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/api-version=2023-08-01-preview response: body: - string: '{"value": [{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/datastores/workspaceblobstore", - "name": "workspaceblobstore", "type": "Microsoft.MachineLearningServices/workspaces/datastores", - "properties": {"description": null, "tags": null, "properties": null, "isDefault": - true, "credentials": {"credentialsType": "AccountKey"}, "intellectualProperty": - null, "subscriptionId": "00000000-0000-0000-0000-000000000000", "resourceGroup": - "00000", "datastoreType": "AzureBlob", "accountName": "fake_account_name", - "containerName": "fake-container-name", "endpoint": "core.windows.net", "protocol": - "https", "serviceDataAccessAuthIdentity": "WorkspaceSystemAssignedIdentity"}, - "systemData": {"createdAt": "2023-04-08T02:53:06.5886442+00:00", "createdBy": - "779301c0-18b2-4cdc-801b-a0a3368fee0a", "createdByType": "Application", "lastModifiedAt": - "2023-04-08T02:53:07.521127+00:00", "lastModifiedBy": "779301c0-18b2-4cdc-801b-a0a3368fee0a", - "lastModifiedByType": "Application"}}]}' + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000", + "name": "00000", "type": "Microsoft.MachineLearningServices/workspaces", "location": + "eastus2euap", "tags": {}, "etag": null, "kind": "Default", "sku": {"name": + "Basic", "tier": "Basic"}, "properties": {"discoveryUrl": "https://eastus.api.azureml.ms/discovery"}}' headers: cache-control: - no-cache content-length: - - '1372' + - '3697' content-type: - application/json; charset=utf-8 expires: @@ -91,7 +83,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.070' + - '0.017' status: code: 200 message: OK @@ -116,18 +108,20 @@ interactions: "name": "azure_open_ai_connection", "type": "Microsoft.MachineLearningServices/workspaces/connections", "properties": {"authType": "ApiKey", "credentials": {"key": "_"}, "group": "AzureAI", "category": "AzureOpenAI", "expiryTime": null, "target": "_", "createdByWorkspaceArmId": - null, "isSharedToAll": false, "sharedUserList": [], "metadata": {"azureml.flow.connection_type": - "AzureOpenAI", "azureml.flow.module": "promptflow.connections", "ApiType": - "azure", "ApiVersion": "2023-07-01-preview", "ResourceId": null, "DeploymentApiVersion": - "2023-10-01-preview"}}, "systemData": {"createdAt": "2023-08-22T10:15:34.5762053Z", - "createdBy": "username@microsoft.com", "createdByType": "User", "lastModifiedAt": - "2023-08-22T10:15:34.5762053Z", "lastModifiedBy": "username@microsoft.com", - "lastModifiedByType": "User"}}' + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/promptflow-eastus2euap", + "useWorkspaceManagedIdentity": false, "isSharedToAll": false, "sharedUserList": + [], "metadata": {"azureml.flow.connection_type": "AzureOpenAI", "azureml.flow.module": + "promptflow.connections", "ApiType": "azure", "ApiVersion": "2023-07-01-preview", + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.CognitiveServices/accounts/gpt-test-eus", + "DeploymentApiVersion": "2023-10-01-preview"}}, "systemData": {"createdAt": + "2024-03-22T14:56:56.0857069Z", "createdBy": "username@microsoft.com", "createdByType": + "User", "lastModifiedAt": "2024-03-22T14:56:56.0857069Z", "lastModifiedBy": + "username@microsoft.com", "lastModifiedByType": "User"}}' headers: cache-control: - no-cache content-length: - - '1246' + - '1579' content-type: - application/json; charset=utf-8 expires: @@ -143,7 +137,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.072' + - '0.649' status: code: 200 message: OK @@ -168,16 +162,18 @@ interactions: "name": "custom_connection", "type": "Microsoft.MachineLearningServices/workspaces/connections", "properties": {"authType": "CustomKeys", "credentials": {"keys": {}}, "group": "AzureAI", "category": "CustomKeys", "expiryTime": null, "target": "_", "createdByWorkspaceArmId": - null, "isSharedToAll": false, "sharedUserList": [], "metadata": {"azureml.flow.connection_type": - "Custom", "azureml.flow.module": "promptflow.connections"}}, "systemData": - {"createdAt": "2023-06-19T20:56:12.0353964Z", "createdBy": "username@microsoft.com", - "createdByType": "User", "lastModifiedAt": "2023-06-19T20:56:12.0353964Z", - "lastModifiedBy": "username@microsoft.com", "lastModifiedByType": "User"}}' + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/promptflow-eastus2euap", + "useWorkspaceManagedIdentity": false, "isSharedToAll": false, "sharedUserList": + [], "metadata": {"azureml.flow.connection_type": "Custom", "azureml.flow.module": + "promptflow.connections"}}, "systemData": {"createdAt": "2023-12-18T09:44:22.1118582Z", + "createdBy": "username@microsoft.com", "createdByType": "User", "lastModifiedAt": + "2023-12-18T09:44:22.1118582Z", "lastModifiedBy": "username@microsoft.com", + "lastModifiedByType": "User"}}' headers: cache-control: - no-cache content-length: - - '1275' + - '1254' content-type: - application/json; charset=utf-8 expires: @@ -193,7 +189,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.075' + - '0.094' status: code: 200 message: OK From 1437b35f5abff7603b63b646d4b60eec17130675 Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 18:11:25 +0800 Subject: [PATCH 5/8] Fix workspace url in recording Signed-off-by: Brynn Yin --- .../promptflow/recording/azure/utils.py | 6 +++--- ...tArmConnectionOperations_test_get_connection.yaml | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/promptflow-recording/promptflow/recording/azure/utils.py b/src/promptflow-recording/promptflow/recording/azure/utils.py index 42077d1b681..b558ab812b9 100644 --- a/src/promptflow-recording/promptflow/recording/azure/utils.py +++ b/src/promptflow-recording/promptflow/recording/azure/utils.py @@ -99,8 +99,8 @@ def sanitize_azure_workspace_triad(value: str) -> str: flags=re.IGNORECASE, ) sanitized_ws = re.sub( - r"/(workspaces)/[-\w\._\(\)]+[/?]", - r"/\1/{}/".format("00000"), + r"/(workspaces)/[-\w\._\(\)]+([/?][-\w\._\(\)]*)", + r"/\1/{}\2".format("00000"), sanitized_rg, flags=re.IGNORECASE, ) @@ -108,7 +108,7 @@ def sanitize_azure_workspace_triad(value: str) -> str: # workspace name can be the last part of the string # e.g. xxx/Microsoft.MachineLearningServices/workspaces/ # apply a special handle here to sanitize - if sanitized_ws.startswith("https://"): + if sanitized_ws == sanitized_rg and sanitized_ws.startswith("https://"): split1, split2 = sanitized_ws.split("/")[-2:] if split1 == "workspaces": sanitized_ws = sanitized_ws.replace(split2, SanitizedValues.WORKSPACE_NAME) diff --git a/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml b/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml index 2db5eebca03..4d071dde742 100644 --- a/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml +++ b/src/promptflow-recording/recordings/azure/test_arm_connection_operations_TestArmConnectionOperations_test_get_connection.yaml @@ -12,7 +12,7 @@ interactions: - promptflow-azure-sdk/0.1.0b1 azure-ai-ml/1.15.0 azsdk-python-mgmt-machinelearningservices/0.1.0 Python/3.9.19 (Windows-10-10.0.22631-SP0) method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/api-version=2023-08-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000?api-version=2023-08-01-preview response: body: string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000", @@ -39,7 +39,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.022' + - '0.019' status: code: 200 message: OK @@ -56,7 +56,7 @@ interactions: - azure-ai-ml/1.15.0 azsdk-python-mgmt-machinelearningservices/0.1.0 Python/3.9.19 (Windows-10-10.0.22631-SP0) method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/api-version=2023-08-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000?api-version=2023-08-01-preview response: body: string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000", @@ -83,7 +83,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.017' + - '0.020' status: code: 200 message: OK @@ -137,7 +137,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.649' + - '0.772' status: code: 200 message: OK @@ -189,7 +189,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.094' + - '0.090' status: code: 200 message: OK From c7c7e05b7f809164bda9d95cef14138dcb15021c Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 18:19:11 +0800 Subject: [PATCH 6/8] Update changelog Signed-off-by: Brynn Yin --- docs/reference/pf-command-reference.md | 4 ++-- src/promptflow-devkit/CHANGELOG.md | 9 +++++++++ src/promptflow/CHANGELOG.md | 5 ++++- 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 src/promptflow-devkit/CHANGELOG.md diff --git a/docs/reference/pf-command-reference.md b/docs/reference/pf-command-reference.md index 7eacf367ee1..539b2737e8a 100644 --- a/docs/reference/pf-command-reference.md +++ b/docs/reference/pf-command-reference.md @@ -903,6 +903,6 @@ pf upgrade --yes To activate autocomplete features for the pf CLI you need to add the following snippet to your ~/.bashrc or ~/.zshrc: -``` - source /pf.completion.sh +```bash +source /pf.completion.sh ``` diff --git a/src/promptflow-devkit/CHANGELOG.md b/src/promptflow-devkit/CHANGELOG.md new file mode 100644 index 00000000000..8c2594ab2cc --- /dev/null +++ b/src/promptflow-devkit/CHANGELOG.md @@ -0,0 +1,9 @@ +# Release History + +## 1.9.0 (Upcoming) + +### Features Added +- Added autocomplete feature, reach [here](https://microsoft.github.io/promptflow/reference/pf-command-reference.html#autocomplete) for more details. + +### Bugs Fixed +- Fix run name missing directory name in some scenario of `pf.run`. diff --git a/src/promptflow/CHANGELOG.md b/src/promptflow/CHANGELOG.md index bb0927bb648..1499553700e 100644 --- a/src/promptflow/CHANGELOG.md +++ b/src/promptflow/CHANGELOG.md @@ -3,7 +3,10 @@ ## 1.9.0 (Upcoming) ### Features Added -- [CLI]: Added autocomplete feature. +- [promptflow-devkit]: Added autocomplete feature, reach [here](https://microsoft.github.io/promptflow/reference/pf-command-reference.html#autocomplete) for more details. + +### Bugs Fixed +- [promptflow-devkit] Fix run name missing directory name in some scenario of `pf.run`. ### Others - [promptflow-core] Connection default api version changed: From d53c038174753597a50af048849aba3d4cdddbc5 Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 18:38:29 +0800 Subject: [PATCH 7/8] Fix recording Signed-off-by: Brynn Yin --- ...nectionProvider_test_list_connections.yaml | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/promptflow-recording/recordings/azure/test_workspace_connection_provider_TestWorkspaceConnectionProvider_test_list_connections.yaml b/src/promptflow-recording/recordings/azure/test_workspace_connection_provider_TestWorkspaceConnectionProvider_test_list_connections.yaml index 359dbc93463..5e1dbd617d2 100644 --- a/src/promptflow-recording/recordings/azure/test_workspace_connection_provider_TestWorkspaceConnectionProvider_test_list_connections.yaml +++ b/src/promptflow-recording/recordings/azure/test_workspace_connection_provider_TestWorkspaceConnectionProvider_test_list_connections.yaml @@ -10,9 +10,9 @@ interactions: - keep-alive User-Agent: - promptflow-azure-sdk/0.1.0b1 azure-ai-ml/1.15.0 azsdk-python-mgmt-machinelearningservices/0.1.0 - Python/3.9.7 (Windows-10-10.0.22631-SP0) + Python/3.9.19 (Windows-10-10.0.22631-SP0) method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000/api-version=2023-08-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000?api-version=2023-08-01-preview response: body: string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000", @@ -39,7 +39,51 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.021' + - '0.019' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azure-ai-ml/1.15.0 azsdk-python-mgmt-machinelearningservices/0.1.0 Python/3.9.19 + (Windows-10-10.0.22631-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000?api-version=2023-08-01-preview + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/00000/providers/Microsoft.MachineLearningServices/workspaces/00000", + "name": "00000", "type": "Microsoft.MachineLearningServices/workspaces", "location": + "eastus2euap", "tags": {}, "etag": null, "kind": "Default", "sku": {"name": + "Basic", "tier": "Basic"}, "properties": {"discoveryUrl": "https://eastus.api.azureml.ms/discovery"}}' + headers: + cache-control: + - no-cache + content-length: + - '3697' + content-type: + - application/json; charset=utf-8 + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-request-time: + - '0.019' status: code: 200 message: OK @@ -172,7 +216,7 @@ interactions: x-content-type-options: - nosniff x-request-time: - - '0.029' + - '0.018' status: code: 200 message: OK From 82fdfbbe9c2d0e7572413c396d0d8a3eafc1626e Mon Sep 17 00:00:00 2001 From: Brynn Yin Date: Thu, 11 Apr 2024 18:52:25 +0800 Subject: [PATCH 8/8] Update changelog Signed-off-by: Brynn Yin --- src/promptflow-devkit/CHANGELOG.md | 2 +- src/promptflow/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/promptflow-devkit/CHANGELOG.md b/src/promptflow-devkit/CHANGELOG.md index 8c2594ab2cc..baa72a7e2af 100644 --- a/src/promptflow-devkit/CHANGELOG.md +++ b/src/promptflow-devkit/CHANGELOG.md @@ -3,7 +3,7 @@ ## 1.9.0 (Upcoming) ### Features Added -- Added autocomplete feature, reach [here](https://microsoft.github.io/promptflow/reference/pf-command-reference.html#autocomplete) for more details. +- Added autocomplete feature for linux, reach [here](https://microsoft.github.io/promptflow/reference/pf-command-reference.html#autocomplete) for more details. ### Bugs Fixed - Fix run name missing directory name in some scenario of `pf.run`. diff --git a/src/promptflow/CHANGELOG.md b/src/promptflow/CHANGELOG.md index 1499553700e..b74e523a104 100644 --- a/src/promptflow/CHANGELOG.md +++ b/src/promptflow/CHANGELOG.md @@ -3,7 +3,7 @@ ## 1.9.0 (Upcoming) ### Features Added -- [promptflow-devkit]: Added autocomplete feature, reach [here](https://microsoft.github.io/promptflow/reference/pf-command-reference.html#autocomplete) for more details. +- [promptflow-devkit]: Added autocomplete feature for linux, reach [here](https://microsoft.github.io/promptflow/reference/pf-command-reference.html#autocomplete) for more details. ### Bugs Fixed - [promptflow-devkit] Fix run name missing directory name in some scenario of `pf.run`.