Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/microsoft/promptflow into l…
Browse files Browse the repository at this point in the history
…oad_prompty
  • Loading branch information
lalala123123 committed Apr 25, 2024
2 parents b75d0fc + 9f2bc05 commit 0fb07dd
Show file tree
Hide file tree
Showing 33 changed files with 2,526 additions and 1,005 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/promptflow-evals-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
needs: build
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
python-version: ['3.8', '3.9', '3.10', '3.11']
fail-fast: false
# snok/install-poetry need this to support Windows
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/promptflow-evals-unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
needs: build
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
python-version: ['3.8', '3.9', '3.10', '3.11']
fail-fast: false
# snok/install-poetry need this to support Windows
Expand Down
41 changes: 23 additions & 18 deletions .github/workflows/promptflow-release-testing-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
pythonVersion: ['3.8', '3.9', '3.10', '3.11']
defaults:
run:
Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
pythonVersion: ['3.8', '3.9', '3.10', '3.11']
# snok/install-poetry need this to support Windows
defaults:
Expand Down Expand Up @@ -160,13 +160,11 @@ jobs:
run: |
poetry run pip install $(python -c "import glob; print(glob.glob('**/promptflow_tracing-*.whl', recursive=True)[0])")
poetry run pip install $(python -c "import glob; print(glob.glob('**/promptflow_core-*.whl', recursive=True)[0])")
poetry run pip install -e ../promptflow-recording
working-directory: ${{ env.WORKING_DIRECTORY }}
- name: install test dependency group
run: poetry install --only test
working-directory: ${{ env.WORKING_DIRECTORY }}
- name: install recording
run: poetry install
working-directory: ${{ env.RECORD_DIRECTORY }}
- name: run core tests
run: poetry run pytest ./tests/core
working-directory: ${{ env.WORKING_DIRECTORY }}
Expand All @@ -186,7 +184,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
pythonVersion: ['3.8', '3.9', '3.10', '3.11']
# snok/install-poetry need this to support Windows
defaults:
Expand All @@ -209,13 +207,11 @@ jobs:
run: |
poetry run pip install $(python -c "import glob; print(glob.glob('**/promptflow_tracing-*.whl', recursive=True)[0])")
poetry run pip install $(python -c "import glob; print(glob.glob('**/promptflow_core-*.whl', recursive=True)[0]+'[azureml-serving]')")
poetry run pip install -e ../promptflow-recording
working-directory: ${{ env.WORKING_DIRECTORY }}
- name: install test dependency group
run: poetry install --only test
working-directory: ${{ env.WORKING_DIRECTORY }}
- name: install recording
run: poetry install
working-directory: ${{ env.RECORD_DIRECTORY }}
- name: run azureml-serving tests
run: poetry run pytest ./tests/azureml-serving
working-directory: ${{ env.WORKING_DIRECTORY }}
Expand All @@ -236,7 +232,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
pythonVersion: ['3.8', '3.9', '3.10', '3.11']
# snok/install-poetry need this to support Windows
defaults:
Expand Down Expand Up @@ -274,9 +270,6 @@ jobs:
- name: install test dependency group
run: poetry install --only test
working-directory: ${{ env.WORKING_DIRECTORY }}
- name: install recording
run: poetry install
working-directory: ${{ env.RECORD_DIRECTORY }}
- name: run devkit tests
run: poetry run pytest ./tests/sdk_cli_test ./tests/sdk_pfs_test -n auto -m "unittest or e2etest"
working-directory: ${{ env.WORKING_DIRECTORY }}
Expand All @@ -293,7 +286,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
pythonVersion: ['3.8', '3.9', '3.10', '3.11']
env:
PROMPT_FLOW_TEST_MODE: "live"
Expand Down Expand Up @@ -356,7 +349,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
pythonVersion: ['3.8', '3.9', '3.10', '3.11']
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -401,18 +394,30 @@ jobs:
gci ./promptflow -Recurse | % {if ($_.Name.Contains('.whl')) {python -m pip install "$($_.FullName)[azure,executor-service]"}}
gci ./promptflow-tools -Recurse | % {if ($_.Name.Contains('.whl')) {python -m pip install "$($_.FullName)"}}
pip freeze
- name: Run Executor Test
- name: Run Executor Unit Test
shell: pwsh
working-directory: ${{ github.workspace }}
run: |
pip install langchain
pip install numexpr
python scripts/building/run_coverage_tests.py `
-p ${{ github.workspace }}/src/promptflow/promptflow `
-t ${{ github.workspace }}/src/promptflow/tests/executor/unittests `
-l eastus `
-m "all" `
-o "${{ github.workspace }}/test-results-executor-unit.xml"
- name: Run Executor E2E Test
shell: pwsh
working-directory: ${{ github.workspace }}
run: |
pip install langchain
pip install numexpr
python scripts/building/run_coverage_tests.py `
-p ${{ github.workspace }}/src/promptflow/promptflow `
-t ${{ github.workspace }}/src/promptflow/tests/executor/e2etests ${{ github.workspace }}/src/promptflow/tests/executor/unittests `
-t ${{ github.workspace }}/src/promptflow/tests/executor/e2etests `
-l eastus `
-m "all" `
-o "${{ github.workspace }}/test-results-executor.xml"
-o "${{ github.workspace }}/test-results-executor-e2e.xml"
- name: Upload pytest test results (Python ${{ matrix.pythonVersion }}) (OS ${{ matrix.os }})
if: ${{ always() }}
uses: actions/upload-artifact@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/promptflow-tracing-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
needs: build
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
python-version: ['3.8', '3.9', '3.10', '3.11']
fail-fast: false
# snok/install-poetry need this to support Windows
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/promptflow-tracing-unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
needs: build
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
python-version: ['3.8', '3.9', '3.10', '3.11']
fail-fast: false
# snok/install-poetry need this to support Windows
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sdk-cli-perf-monitor-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-13, windows-latest]
defaults:
run:
shell: bash
Expand Down
17 changes: 5 additions & 12 deletions src/promptflow-azure/promptflow/azure/_storage/blob/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import threading
import traceback
from typing import Optional, Tuple
from typing import Callable, Tuple

from azure.ai.ml import MLClient
from azure.ai.ml._azure_environments import _get_storage_endpoint_from_metadata
Expand All @@ -25,17 +25,10 @@ def get_datastore_container_client(
subscription_id: str,
resource_group_name: str,
workspace_name: str,
credential: Optional[object] = None,
get_credential: Callable,
) -> Tuple[ContainerClient, str]:
try:
if credential is None:
# in cloud scenario, runtime will pass in credential
# so this is local to cloud only code, happens in prompt flow service
# which should rely on Azure CLI credential only
from azure.identity import AzureCliCredential

credential = AzureCliCredential()

credential = get_credential()
datastore_definition, datastore_credential = _get_default_datastore(
subscription_id, resource_group_name, workspace_name, credential
)
Expand Down Expand Up @@ -68,7 +61,7 @@ def get_datastore_container_client(


def _get_default_datastore(
subscription_id: str, resource_group_name: str, workspace_name: str, credential: Optional[object]
subscription_id: str, resource_group_name: str, workspace_name: str, credential
) -> Tuple[Datastore, str]:

datastore_key = _get_datastore_client_key(subscription_id, resource_group_name, workspace_name)
Expand Down Expand Up @@ -103,7 +96,7 @@ def _get_datastore_client_key(subscription_id: str, resource_group_name: str, wo


def _get_aml_default_datastore(
subscription_id: str, resource_group_name: str, workspace_name: str, credential: Optional[object]
subscription_id: str, resource_group_name: str, workspace_name: str, credential
) -> Tuple[Datastore, str]:

ml_client = MLClient(
Expand Down
14 changes: 4 additions & 10 deletions src/promptflow-azure/promptflow/azure/_storage/cosmosdb/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import ast
import datetime
import threading
from typing import Optional
from typing import Callable

client_map = {}
_thread_lock = threading.Lock()
Expand All @@ -18,7 +18,7 @@ def get_client(
subscription_id: str,
resource_group_name: str,
workspace_name: str,
credential: Optional[object] = None,
get_credential: Callable,
):
client_key = _get_db_client_key(container_name, subscription_id, resource_group_name, workspace_name)
container_client = _get_client_from_map(client_key)
Expand All @@ -28,13 +28,7 @@ def get_client(
with container_lock:
container_client = _get_client_from_map(client_key)
if container_client is None:
if credential is None:
# in cloud scenario, runtime will pass in credential
# so this is local to cloud only code, happens in prompt flow service
# which should rely on Azure CLI credential only
from azure.identity import AzureCliCredential

credential = AzureCliCredential()
credential = get_credential()
token = _get_resource_token(
container_name, subscription_id, resource_group_name, workspace_name, credential
)
Expand Down Expand Up @@ -77,7 +71,7 @@ def _get_resource_token(
subscription_id: str,
resource_group_name: str,
workspace_name: str,
credential: Optional[object],
credential,
) -> object:
from promptflow.azure import PFClient

Expand Down
5 changes: 4 additions & 1 deletion src/promptflow-azure/tests/sdk_cli_azure_test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from mock import MagicMock, mock
from pytest_mock import MockerFixture

from promptflow._sdk._constants import FlowType, RunStatus
from promptflow._sdk._constants import FLOW_TOOLS_JSON, PROMPT_FLOW_DIR_NAME, FlowType, RunStatus
from promptflow._sdk.entities import Run
from promptflow._utils.user_agent_utils import ClientUserAgentUtil
from promptflow.azure import PFClient
Expand Down Expand Up @@ -450,6 +450,9 @@ def created_flow(pf: PFClient, randstr: Callable[[str], str], variable_recorder)
"""Create a flow for test."""
flow_display_name = randstr("flow_display_name")
flow_source = FLOWS_DIR / "simple_hello_world"
tool_json_path = f"{flow_source}/{PROMPT_FLOW_DIR_NAME}/{FLOW_TOOLS_JSON}"
if os.path.isfile(tool_json_path):
os.remove(tool_json_path)
description = "test flow description"
tags = {"owner": "sdk-test"}
result = pf.flows.create_or_update(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest
from sdk_cli_azure_test.conftest import FLOWS_DIR

from promptflow._sdk._constants import FLOW_TOOLS_JSON, PROMPT_FLOW_DIR_NAME
from promptflow.azure._entities._flow import Flow
from promptflow.exceptions import UserErrorException

Expand All @@ -24,6 +25,8 @@ class TestFlow:
def test_create_flow(self, created_flow: Flow):
# most of the assertions are in the fixture itself
assert isinstance(created_flow, Flow)
flow_tools_json_path = FLOWS_DIR / "simple_hello_world" / PROMPT_FLOW_DIR_NAME / FLOW_TOOLS_JSON
assert not flow_tools_json_path.exists()

def test_get_flow(self, pf, created_flow: Flow):
result = pf.flows.get(name=created_flow.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from sdk_cli_azure_test.conftest import DATAS_DIR, FLOWS_DIR

from promptflow._constants import FLOW_FLEX_YAML
from promptflow._sdk._constants import DownloadedRun, RunStatus
from promptflow._sdk._constants import FLOW_TOOLS_JSON, PROMPT_FLOW_DIR_NAME, DownloadedRun, RunStatus
from promptflow._sdk._errors import InvalidRunError, InvalidRunStatusError, RunNotFoundError
from promptflow._sdk._load_functions import load_run
from promptflow._sdk.entities import Run
Expand Down Expand Up @@ -79,6 +79,23 @@ def test_run_bulk(self, pf, runtime: str, randstr: Callable[[str], str]):
assert isinstance(run, Run)
assert run.name == name

@pytest.mark.skipif(not is_live(), reason="Recording issue.")
def test_run_without_generate_tools_json(self, pf, runtime: str, randstr: Callable[[str], str]):
name = randstr("name")
flow_dir = f"{FLOWS_DIR}/simple_hello_world"
tools_json_path = Path(flow_dir) / PROMPT_FLOW_DIR_NAME / FLOW_TOOLS_JSON
if tools_json_path.exists():
tools_json_path.unlink()
run = pf.run(
flow=flow_dir,
data=f"{DATAS_DIR}/simple_hello_world.jsonl",
column_mapping={"name": "${data.name}"},
name=name,
)
assert isinstance(run, Run)
assert run.name == name
assert not tools_json_path.exists()

def test_run_resume(self, pf: PFClient, randstr: Callable[[str], str]):
# Note: Use fixed run name here to ensure resume call has same body then can be recorded.
name = "resume_from_run_using_automatic_runtime"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from sdk_cli_azure_test.conftest import DATAS_DIR, EAGER_FLOWS_DIR, FLOWS_DIR

from promptflow._sdk._errors import RunOperationParameterError, UploadUserError, UserAuthenticationError
from promptflow._sdk._utils import parse_otel_span_status_code
from promptflow._sdk._utils.tracing import _parse_otel_span_status_code
from promptflow._sdk.entities import Run
from promptflow._sdk.operations._run_operations import RunOperations
from promptflow._utils.async_utils import async_run_allowing_running_loop
Expand Down Expand Up @@ -88,7 +88,7 @@ def test_flex_flow_with_imported_func(self, pf: PFClient):
# TODO(3017093): won't support this for now
with pytest.raises(UserErrorException) as e:
pf.run(
flow=parse_otel_span_status_code,
flow=_parse_otel_span_status_code,
data=f"{DATAS_DIR}/simple_eager_flow_data.jsonl",
# set code folder to avoid snapshot too big
code=f"{EAGER_FLOWS_DIR}/multiple_entries",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def prepare_metadata(
3) before flow upload.
For dag flow, it will generate flow.tools.json;
For python flex flow, it will do nothing;
For csharp flex flow, it will generate metadata based on a dotnet command.
For flex flow, it will generate metadata based on a dotnet command.
For python flow, we have a runtime to gather metadata in both local and cloud, so we don't prepare anything
"""
return
Loading

0 comments on commit 0fb07dd

Please sign in to comment.