Files
2026-07-13 13:22:34 +08:00

155 lines
4.7 KiB
Python

import json
import pytest
from mlflow.entities import (
Dataset,
DatasetInput,
LifecycleStage,
LoggedModelOutput,
Metric,
Run,
RunData,
RunInfo,
RunInputs,
RunOutputs,
RunStatus,
)
from mlflow.exceptions import MlflowException
from tests.entities.test_run_data import _check as run_data_check
from tests.entities.test_run_info import _check as run_info_check
from tests.entities.test_run_inputs import _check as run_inputs_check
def _check_run(run, ri, rd_metrics, rd_params, rd_tags, datasets):
run_info_check(
run.info,
ri.run_id,
ri.experiment_id,
ri.user_id,
ri.status,
ri.start_time,
ri.end_time,
ri.lifecycle_stage,
ri.artifact_uri,
)
run_data_check(run.data, rd_metrics, rd_params, rd_tags)
run_inputs_check(run.inputs, datasets)
def test_creation_and_hydration(run_data, run_info, run_inputs):
run_data, metrics, params, tags = run_data
(
run_info,
run_id,
run_name,
experiment_id,
user_id,
status,
start_time,
end_time,
lifecycle_stage,
artifact_uri,
) = run_info
run_inputs, datasets = run_inputs
run_outputs = RunOutputs(model_outputs=[LoggedModelOutput(model_id="model-id-1", step=3)])
run1 = Run(run_info, run_data, run_inputs, run_outputs)
_check_run(run1, run_info, metrics, params, tags, datasets)
expected_info_dict = {
"run_id": run_id,
"run_name": run_name,
"experiment_id": experiment_id,
"user_id": user_id,
"status": status,
"start_time": start_time,
"end_time": end_time,
"lifecycle_stage": lifecycle_stage,
"artifact_uri": artifact_uri,
}
assert run1.to_dictionary() == {
"info": expected_info_dict,
"data": {
"metrics": {m.key: m.value for m in metrics},
"params": {p.key: p.value for p in params},
"tags": {t.key: t.value for t in tags},
},
"inputs": {
"dataset_inputs": [
{
"dataset": {
"digest": "digest1",
"name": "name1",
"profile": None,
"schema": None,
"source": "source",
"source_type": "my_source_type",
},
"tags": {"key": "value"},
}
],
"model_inputs": [],
},
"outputs": {
"model_outputs": [{"model_id": "model-id-1", "step": 3}],
},
}
# Run must be json serializable
json.dumps(run1.to_dictionary())
proto = run1.to_proto()
run2 = Run.from_proto(proto)
_check_run(run2, run_info, metrics, params, tags, datasets)
assert run2.outputs.model_outputs == [LoggedModelOutput(model_id="model-id-1", step=3)]
assert run2.outputs.to_dictionary() == {
"model_outputs": [{"model_id": "model-id-1", "step": 3}],
}
run3 = Run(run_info, None, None)
assert run3.to_dictionary() == {"info": expected_info_dict}
run4 = Run(run_info, None)
assert run4.to_dictionary() == {"info": expected_info_dict}
def test_string_repr():
run_info = RunInfo(
run_id="hi",
run_name="name",
experiment_id=0,
user_id="user-id",
status=RunStatus.FAILED,
start_time=0,
end_time=1,
lifecycle_stage=LifecycleStage.ACTIVE,
)
metrics = [Metric(key=f"key-{i}", value=i, timestamp=0, step=i) for i in range(3)]
run_data = RunData(metrics=metrics, params=[], tags=[])
dataset_inputs = DatasetInput(
dataset=Dataset(
name="name1", digest="digest1", source_type="my_source_type", source="source"
),
tags=[],
)
run_inputs = RunInputs(dataset_inputs=dataset_inputs)
run1 = Run(run_info, run_data, run_inputs)
expected = (
"<Run: data=<RunData: metrics={'key-0': 0, 'key-1': 1, 'key-2': 2}, "
"params={}, tags={}>, info=<RunInfo: artifact_uri=None, end_time=1, "
"experiment_id=0, lifecycle_stage='active', run_id='hi', run_name='name', "
"start_time=0, status=4, user_id='user-id'>, inputs=<RunInputs: "
"dataset_inputs=<DatasetInput: dataset=<Dataset: digest='digest1', "
"name='name1', profile=None, schema=None, source='source', "
"source_type='my_source_type'>, tags=[]>, model_inputs=[]>, outputs=None>"
)
assert str(run1) == expected
def test_creating_run_with_absent_info_throws_exception(run_data, run_inputs):
run_data = run_data[0]
with pytest.raises(MlflowException, match="run_info cannot be None"):
Run(None, run_data, run_inputs)