328 lines
10 KiB
Python
328 lines
10 KiB
Python
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from mlflow.entities.assessment_source import AssessmentSourceType
|
|
from mlflow.evaluation import Assessment
|
|
from mlflow.evaluation.assessment import AssessmentSource
|
|
from mlflow.exceptions import MlflowException
|
|
|
|
|
|
def test_assessment_equality():
|
|
source_1 = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
source_2 = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
source_3 = AssessmentSource(source_type="AI_JUDGE", source_id="ai_1")
|
|
|
|
# Valid assessments
|
|
assessment_1 = Assessment(
|
|
name="relevance",
|
|
source=source_1,
|
|
value=0.9,
|
|
)
|
|
assessment_2 = Assessment(
|
|
name="relevance",
|
|
source=source_2,
|
|
value=0.9,
|
|
)
|
|
assessment_3 = Assessment(
|
|
name="relevance",
|
|
source=source_1,
|
|
value=0.8,
|
|
)
|
|
assessment_4 = Assessment(
|
|
name="relevance",
|
|
source=source_3,
|
|
value=0.9,
|
|
)
|
|
assessment_5 = Assessment(
|
|
name="relevance",
|
|
source=source_1,
|
|
error_code="E002",
|
|
error_message="A different error occurred.",
|
|
)
|
|
assessment_6 = Assessment(
|
|
name="relevance",
|
|
source=source_1,
|
|
error_code="E001",
|
|
error_message="Another error message.",
|
|
)
|
|
|
|
# Same name, source, and value
|
|
assert assessment_1 == assessment_2
|
|
assert assessment_1 != assessment_3 # Different value
|
|
assert assessment_1 != assessment_4 # Different source
|
|
assert assessment_1 != assessment_5 # One has value, other has error_code
|
|
assert assessment_5 != assessment_6 # Different error_code
|
|
|
|
|
|
def test_assessment_properties():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
rationale="Rationale text",
|
|
metadata={"key1": "value1"},
|
|
)
|
|
|
|
assert assessment.name == "relevance"
|
|
assert assessment.source == source
|
|
assert assessment.value == 0.9
|
|
assert assessment.rationale == "Rationale text"
|
|
assert assessment.metadata == {"key1": "value1"}
|
|
assert assessment.error_code is None
|
|
assert assessment.error_message is None
|
|
|
|
|
|
def test_assessment_to_from_dictionary():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
rationale="Rationale text",
|
|
metadata={"key1": "value1"},
|
|
)
|
|
assessment_dict = assessment.to_dictionary()
|
|
|
|
expected_dict = {
|
|
"name": "relevance",
|
|
"source": source.to_dictionary(),
|
|
"value": 0.9,
|
|
"rationale": "Rationale text",
|
|
"metadata": {"key1": "value1"},
|
|
"error_code": None,
|
|
"error_message": None,
|
|
}
|
|
assert assessment_dict == expected_dict
|
|
|
|
recreated_assessment = Assessment.from_dictionary(assessment_dict)
|
|
assert recreated_assessment == assessment
|
|
|
|
|
|
def test_assessment_value_validation():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
|
|
# Valid cases
|
|
try:
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=True,
|
|
)
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
)
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value="value",
|
|
)
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
error_code="E001",
|
|
error_message="Error",
|
|
)
|
|
except MlflowException:
|
|
pytest.fail("Valid value raised exception")
|
|
|
|
# Invalid case: more than one value type specified
|
|
with pytest.raises(
|
|
MlflowException,
|
|
match="Exactly one of value or error_code must be specified for an assessment.",
|
|
):
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=True,
|
|
error_code="E002",
|
|
)
|
|
|
|
# Invalid case: no value type specified
|
|
with pytest.raises(
|
|
MlflowException,
|
|
match="Exactly one of value or error_code must be specified for an assessment.",
|
|
):
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
)
|
|
|
|
# Invalid case: error_message specified with another value type
|
|
with pytest.raises(
|
|
MlflowException,
|
|
match="error_message cannot be specified when value is specified.",
|
|
):
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
error_message="An error occurred",
|
|
)
|
|
|
|
with pytest.raises(
|
|
MlflowException,
|
|
match="error_message cannot be specified when value is specified.",
|
|
):
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value="value",
|
|
error_message="An error occurred",
|
|
)
|
|
|
|
with pytest.raises(
|
|
MlflowException,
|
|
match="error_message cannot be specified when value is specified.",
|
|
):
|
|
Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=True,
|
|
error_message="An error occurred",
|
|
)
|
|
|
|
|
|
def test_assessment_to_entity():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
rationale="Rationale text",
|
|
metadata={"key1": "value1"},
|
|
)
|
|
|
|
evaluation_id = "evaluation_1"
|
|
with patch("time.time", return_value=1234567890):
|
|
assessment_entity = assessment._to_entity(evaluation_id)
|
|
|
|
assert assessment_entity.evaluation_id == evaluation_id
|
|
assert assessment_entity.name == assessment.name
|
|
assert assessment_entity.source == assessment.source
|
|
assert assessment_entity.boolean_value is None
|
|
assert assessment_entity.numeric_value == assessment.value
|
|
assert assessment_entity.string_value is None
|
|
assert assessment_entity.rationale == assessment.rationale
|
|
assert assessment_entity.metadata == assessment.metadata
|
|
assert assessment_entity.error_code is None
|
|
assert assessment_entity.error_message is None
|
|
assert assessment_entity.timestamp == 1234567890000 # Mocked timestamp
|
|
|
|
|
|
def test_assessment_to_entity_with_error():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
error_code="E001",
|
|
error_message="An error occurred",
|
|
)
|
|
|
|
evaluation_id = "evaluation_1"
|
|
with patch("time.time", return_value=1234567890):
|
|
assessment_entity = assessment._to_entity(evaluation_id)
|
|
|
|
assert assessment_entity.evaluation_id == evaluation_id
|
|
assert assessment_entity.name == assessment.name
|
|
assert assessment_entity.source == assessment.source
|
|
assert assessment_entity.boolean_value is None
|
|
assert assessment_entity.numeric_value is None
|
|
assert assessment_entity.string_value is None
|
|
assert assessment_entity.rationale == assessment.rationale
|
|
assert assessment_entity.metadata == assessment.metadata
|
|
assert assessment_entity.error_code == assessment.error_code
|
|
assert assessment_entity.error_message == assessment.error_message
|
|
assert assessment_entity.timestamp == 1234567890000 # Mocked timestamp
|
|
|
|
|
|
def test_assessment_to_entity_with_boolean_value():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=True,
|
|
)
|
|
|
|
evaluation_id = "evaluation_1"
|
|
with patch("time.time", return_value=1234567890):
|
|
assessment_entity = assessment._to_entity(evaluation_id)
|
|
|
|
assert assessment_entity.evaluation_id == evaluation_id
|
|
assert assessment_entity.name == assessment.name
|
|
assert assessment_entity.source == assessment.source
|
|
assert assessment_entity.boolean_value == assessment.value
|
|
assert assessment_entity.numeric_value is None
|
|
assert assessment_entity.string_value is None
|
|
assert assessment_entity.rationale == assessment.rationale
|
|
assert assessment_entity.metadata == assessment.metadata
|
|
assert assessment_entity.error_code is None
|
|
assert assessment_entity.error_message is None
|
|
assert assessment_entity.timestamp == 1234567890000 # Mocked timestamp
|
|
|
|
|
|
def test_assessment_to_entity_with_string_value():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value="string value",
|
|
)
|
|
|
|
evaluation_id = "evaluation_1"
|
|
with patch("time.time", return_value=1234567890):
|
|
assessment_entity = assessment._to_entity(evaluation_id)
|
|
|
|
assert assessment_entity.evaluation_id == evaluation_id
|
|
assert assessment_entity.name == assessment.name
|
|
assert assessment_entity.source == assessment.source
|
|
assert assessment_entity.boolean_value is None
|
|
assert assessment_entity.numeric_value is None
|
|
assert assessment_entity.string_value == assessment.value
|
|
assert assessment_entity.rationale == assessment.rationale
|
|
assert assessment_entity.metadata == assessment.metadata
|
|
assert assessment_entity.error_code is None
|
|
assert assessment_entity.error_message is None
|
|
assert assessment_entity.timestamp == 1234567890000 # Mocked timestamp
|
|
|
|
|
|
def test_assessment_with_full_metadata():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
rationale="Detailed rationale",
|
|
metadata={"key1": "value1", "key2": "value2"},
|
|
)
|
|
|
|
assert assessment.metadata == {"key1": "value1", "key2": "value2"}
|
|
assert assessment.rationale == "Detailed rationale"
|
|
|
|
|
|
def test_assessment_without_metadata():
|
|
source = AssessmentSource(source_type="HUMAN", source_id="user_1")
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
source=source,
|
|
value=0.9,
|
|
)
|
|
|
|
assert assessment.metadata == {}
|
|
assert assessment.rationale is None
|
|
|
|
|
|
def test_assessment_without_source():
|
|
assessment = Assessment(
|
|
name="relevance",
|
|
value=0.9,
|
|
)
|
|
|
|
assert assessment.source.source_type == AssessmentSourceType.SOURCE_TYPE_UNSPECIFIED
|
|
|
|
entity = assessment._to_entity("evaluation_1")
|
|
assert entity.source.source_type == AssessmentSourceType.SOURCE_TYPE_UNSPECIFIED
|