-
Notifications
You must be signed in to change notification settings - Fork 871
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add load function for flow run and node run (#1939)
# Description 1. In _local_storage_operations.py, maintain dicts of node run and flow run info to quickly get run info for certain line number. Split load_details into two functions to avoid repetition of calls. 2. In _run_storage, add class AbstractBatchRunStorage which inherits AbstractRunStorage. It has unique load functions. 3. Add test case for load functions. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: Min Shi <minshi@microsoft.com>
- Loading branch information
Showing
4 changed files
with
182 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/promptflow/tests/executor/unittests/storage/test_local_storage_operations.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import datetime | ||
import json | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from promptflow._sdk.entities._run import Run | ||
from promptflow._sdk.operations._local_storage_operations import LocalStorageOperations | ||
from promptflow.contracts.run_info import FlowRunInfo, RunInfo, Status | ||
|
||
|
||
@pytest.fixture | ||
def run_instance(): | ||
return Run(flow="flow", name="run_name") | ||
|
||
|
||
@pytest.fixture | ||
def local_storage(run_instance): | ||
return LocalStorageOperations(run_instance) | ||
|
||
|
||
@pytest.fixture | ||
def node_run_info(): | ||
return RunInfo( | ||
node="node1", | ||
flow_run_id="flow_run_id", | ||
run_id="run_id", | ||
status=Status.Completed, | ||
inputs={"image1": {"data:image/png;path": "test.png"}}, | ||
output={"output1": {"data:image/png;path": "test.png"}}, | ||
metrics={}, | ||
error={}, | ||
parent_run_id="parent_run_id", | ||
start_time=datetime.datetime.now(), | ||
end_time=datetime.datetime.now() + datetime.timedelta(seconds=5), | ||
index=1, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def flow_run_info(): | ||
return FlowRunInfo( | ||
run_id="run_id", | ||
status=Status.Completed, | ||
error=None, | ||
inputs={"image1": {"data:image/png;path": "test.png"}}, | ||
output={"output1": {"data:image/png;path": "test.png"}}, | ||
metrics={}, | ||
request="request", | ||
parent_run_id="parent_run_id", | ||
root_run_id="root_run_id", | ||
source_run_id="source_run_id", | ||
flow_id="flow_id", | ||
start_time=datetime.datetime.now(), | ||
end_time=datetime.datetime.now() + datetime.timedelta(seconds=5), | ||
index=1, | ||
) | ||
|
||
|
||
@pytest.mark.unittest | ||
class TestLocalStorageOperations: | ||
def test_persist_node_run(self, local_storage, node_run_info): | ||
local_storage.persist_node_run(node_run_info) | ||
expected_file_path = local_storage.path / "node_artifacts" / node_run_info.node / "000000001.jsonl" | ||
assert expected_file_path.exists() | ||
with open(expected_file_path, "r") as file: | ||
content = file.read() | ||
node_run_info_dict = json.loads(content) | ||
assert node_run_info_dict["NodeName"] == node_run_info.node | ||
assert node_run_info_dict["line_number"] == node_run_info.index | ||
|
||
def test_persist_flow_run(self, local_storage, flow_run_info): | ||
local_storage.persist_flow_run(flow_run_info) | ||
expected_file_path = local_storage.path / "flow_artifacts" / "000000001_000000001.jsonl" | ||
assert expected_file_path.exists() | ||
with open(expected_file_path, "r") as file: | ||
content = file.read() | ||
flow_run_info_dict = json.loads(content) | ||
assert flow_run_info_dict["run_info"]["run_id"] == flow_run_info.run_id | ||
assert flow_run_info_dict["line_number"] == flow_run_info.index | ||
|
||
def test_load_node_run_info(self, local_storage, node_run_info): | ||
local_storage.persist_node_run(node_run_info) | ||
loaded_node_run_info = local_storage._load_all_node_run_info() | ||
assert len(loaded_node_run_info) == 1 | ||
assert loaded_node_run_info[0]["node"] == node_run_info.node | ||
assert loaded_node_run_info[0]["index"] == node_run_info.index | ||
assert loaded_node_run_info[0]["inputs"]["image1"]["data:image/png;path"] == str( | ||
Path(local_storage._node_infos_folder, node_run_info.node, "test.png") | ||
) | ||
assert loaded_node_run_info[0]["output"]["output1"]["data:image/png;path"] == str( | ||
Path(local_storage._node_infos_folder, node_run_info.node, "test.png") | ||
) | ||
|
||
res = local_storage.load_node_run_info_for_line(1) | ||
assert isinstance(res, list) | ||
assert isinstance(res[0], RunInfo) | ||
assert res[0].node == node_run_info.node | ||
|
||
def test_load_flow_run_info(self, local_storage, flow_run_info): | ||
local_storage.persist_flow_run(flow_run_info) | ||
|
||
loaded_flow_run_info = local_storage._load_all_flow_run_info() | ||
assert len(loaded_flow_run_info) == 1 | ||
assert loaded_flow_run_info[0]["run_id"] == flow_run_info.run_id | ||
assert loaded_flow_run_info[0]["status"] == flow_run_info.status.value | ||
assert loaded_flow_run_info[0]["inputs"]["image1"]["data:image/png;path"] == str( | ||
Path(local_storage._run_infos_folder, "test.png") | ||
) | ||
assert loaded_flow_run_info[0]["output"]["output1"]["data:image/png;path"] == str( | ||
Path(local_storage._run_infos_folder, "test.png") | ||
) | ||
|
||
res = local_storage.load_flow_run_info(1) | ||
assert isinstance(res, FlowRunInfo) | ||
assert res.run_id == flow_run_info.run_id |