287 lines
10 KiB
Python
287 lines
10 KiB
Python
"""Tests for DataTable inheritance and return type correctness."""
|
|
|
|
import tempfile
|
|
import typing as t
|
|
|
|
import pytest
|
|
from pydantic import BaseModel
|
|
|
|
from ragas import Experiment
|
|
from ragas.backends.local_csv import LocalCSVBackend
|
|
from ragas.dataset import Dataset, DataTable
|
|
|
|
|
|
# Test BaseModel classes
|
|
class SimpleTestModel(BaseModel):
|
|
name: str
|
|
age: int
|
|
score: float
|
|
|
|
|
|
class ComplexTestModel(BaseModel):
|
|
id: int
|
|
metadata: t.Dict[str, t.Any]
|
|
tags: t.List[str]
|
|
|
|
|
|
# Test fixtures
|
|
@pytest.fixture
|
|
def temp_dir():
|
|
"""Create a temporary directory for testing."""
|
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
yield tmp_dir
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_backend(temp_dir):
|
|
"""Create a mock backend for testing."""
|
|
return LocalCSVBackend(temp_dir)
|
|
|
|
|
|
@pytest.fixture
|
|
def simple_test_data():
|
|
"""Simple test data for testing."""
|
|
return [
|
|
{"name": "Alice", "age": 30, "score": 85.5},
|
|
{"name": "Bob", "age": 25, "score": 92.0},
|
|
{"name": "Charlie", "age": 35, "score": 78.5},
|
|
]
|
|
|
|
|
|
@pytest.fixture
|
|
def complex_test_data():
|
|
"""Complex test data for testing."""
|
|
return [
|
|
{
|
|
"id": 1,
|
|
"metadata": {"score": 0.85, "tags": ["test", "important"]},
|
|
"tags": ["evaluation", "metrics"],
|
|
},
|
|
{
|
|
"id": 2,
|
|
"metadata": {"score": 0.92, "tags": ["production"]},
|
|
"tags": ["benchmark", "validation"],
|
|
},
|
|
]
|
|
|
|
|
|
class TestDataTableInheritance:
|
|
"""Test that DataTable subclasses preserve their type in method returns."""
|
|
|
|
def test_dataset_load_returns_dataset(self, mock_backend, simple_test_data):
|
|
"""Test that Dataset.load() returns a Dataset instance, not DataTable."""
|
|
# Save data first
|
|
mock_backend.save_dataset("test_dataset", simple_test_data)
|
|
|
|
# Load using Dataset.load()
|
|
result = Dataset.load("test_dataset", mock_backend)
|
|
|
|
# This should be a Dataset instance, not just DataTable
|
|
assert isinstance(result, Dataset), f"Expected Dataset, got {type(result)}"
|
|
assert not isinstance(result, DataTable) or isinstance(result, Dataset), (
|
|
"Dataset.load() should return Dataset, not DataTable"
|
|
)
|
|
|
|
def test_dataset_load_with_model_returns_dataset(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Dataset.load() with model returns a Dataset instance."""
|
|
# Save data first
|
|
mock_backend.save_dataset("test_dataset", simple_test_data)
|
|
|
|
# Load using Dataset.load() with model
|
|
result = Dataset.load("test_dataset", mock_backend, SimpleTestModel)
|
|
|
|
# This should be a Dataset instance
|
|
assert isinstance(result, Dataset), f"Expected Dataset, got {type(result)}"
|
|
assert result.data_model == SimpleTestModel
|
|
|
|
def test_dataset_validate_with_returns_dataset(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Dataset.validate_with() returns a Dataset instance."""
|
|
# Create unvalidated dataset
|
|
dataset = Dataset("test_dataset", mock_backend, data=simple_test_data)
|
|
|
|
# Validate with model
|
|
result = dataset.validate_with(SimpleTestModel)
|
|
|
|
# This should be a Dataset instance, not just DataTable
|
|
assert isinstance(result, Dataset), f"Expected Dataset, got {type(result)}"
|
|
assert result.data_model == SimpleTestModel
|
|
|
|
def test_experiment_load_returns_experiment(self, mock_backend, simple_test_data):
|
|
"""Test that Experiment.load() returns an Experiment instance."""
|
|
# Save data first
|
|
mock_backend.save_experiment("test_experiment", simple_test_data)
|
|
|
|
# Load using Experiment.load()
|
|
result = Experiment.load("test_experiment", mock_backend)
|
|
|
|
# This should be an Experiment instance, not just DataTable
|
|
assert isinstance(result, Experiment), (
|
|
f"Expected Experiment, got {type(result)}"
|
|
)
|
|
|
|
def test_experiment_load_with_model_returns_experiment(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Experiment.load() with model returns an Experiment instance."""
|
|
# Save data first
|
|
mock_backend.save_experiment("test_experiment", simple_test_data)
|
|
|
|
# Load using Experiment.load() with model
|
|
result = Experiment.load("test_experiment", mock_backend, SimpleTestModel)
|
|
|
|
# This should be an Experiment instance
|
|
assert isinstance(result, Experiment), (
|
|
f"Expected Experiment, got {type(result)}"
|
|
)
|
|
assert result.data_model == SimpleTestModel
|
|
|
|
def test_experiment_validate_with_returns_experiment(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Experiment.validate_with() returns an Experiment instance."""
|
|
# Create unvalidated experiment
|
|
experiment = Experiment("test_experiment", mock_backend, data=simple_test_data)
|
|
|
|
# Validate with model
|
|
result = experiment.validate_with(SimpleTestModel)
|
|
|
|
# This should be an Experiment instance, not just DataTable
|
|
assert isinstance(result, Experiment), (
|
|
f"Expected Experiment, got {type(result)}"
|
|
)
|
|
assert result.data_model == SimpleTestModel
|
|
|
|
|
|
class TestDatasetMethods:
|
|
"""Test Dataset-specific behavior."""
|
|
|
|
def test_dataset_type_preservation_through_operations(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Dataset type is preserved through multiple operations."""
|
|
# Save data first
|
|
mock_backend.save_dataset("test_dataset", simple_test_data)
|
|
|
|
# Load -> validate -> should still be Dataset
|
|
loaded = Dataset.load("test_dataset", mock_backend)
|
|
validated = loaded.validate_with(SimpleTestModel)
|
|
|
|
assert isinstance(loaded, Dataset)
|
|
assert isinstance(validated, Dataset)
|
|
assert validated.data_model == SimpleTestModel
|
|
|
|
def test_dataset_str_representation(self, mock_backend, simple_test_data):
|
|
"""Test that Dataset shows correct type in string representation."""
|
|
dataset = Dataset("test_dataset", mock_backend, data=simple_test_data)
|
|
str_repr = str(dataset)
|
|
|
|
# Should show "Dataset" not "DataTable"
|
|
assert "Dataset" in str_repr
|
|
assert "DataTable" not in str_repr or "Dataset" in str_repr
|
|
|
|
|
|
class TestExperimentMethods:
|
|
"""Test Experiment-specific behavior."""
|
|
|
|
def test_experiment_type_preservation_through_operations(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Experiment type is preserved through multiple operations."""
|
|
# Save data first
|
|
mock_backend.save_experiment("test_experiment", simple_test_data)
|
|
|
|
# Load -> validate -> should still be Experiment
|
|
loaded = Experiment.load("test_experiment", mock_backend)
|
|
validated = loaded.validate_with(SimpleTestModel)
|
|
|
|
assert isinstance(loaded, Experiment)
|
|
assert isinstance(validated, Experiment)
|
|
assert validated.data_model == SimpleTestModel
|
|
|
|
def test_experiment_str_representation(self, mock_backend, simple_test_data):
|
|
"""Test that Experiment shows correct type in string representation."""
|
|
experiment = Experiment("test_experiment", mock_backend, data=simple_test_data)
|
|
str_repr = str(experiment)
|
|
|
|
# Should show "Experiment" not "DataTable"
|
|
assert "Experiment" in str_repr
|
|
assert "DataTable" not in str_repr or "Experiment" in str_repr
|
|
|
|
|
|
class TestTypeAnnotations:
|
|
"""Test that type annotations are correct for static type checking."""
|
|
|
|
def test_dataset_load_type_annotation(self, mock_backend, simple_test_data):
|
|
"""Test that Dataset.load() has correct type annotation."""
|
|
# Save data first
|
|
mock_backend.save_dataset("test_dataset", simple_test_data)
|
|
|
|
# This should type-check correctly
|
|
result: Dataset = Dataset.load("test_dataset", mock_backend)
|
|
assert isinstance(result, Dataset)
|
|
|
|
def test_dataset_validate_with_type_annotation(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Dataset.validate_with() has correct type annotation."""
|
|
dataset = Dataset("test_dataset", mock_backend, data=simple_test_data)
|
|
|
|
# This should type-check correctly
|
|
result: Dataset = dataset.validate_with(SimpleTestModel)
|
|
assert isinstance(result, Dataset)
|
|
|
|
def test_experiment_load_type_annotation(self, mock_backend, simple_test_data):
|
|
"""Test that Experiment.load() has correct type annotation."""
|
|
# Save data first
|
|
mock_backend.save_experiment("test_experiment", simple_test_data)
|
|
|
|
# This should type-check correctly
|
|
result: Experiment = Experiment.load("test_experiment", mock_backend)
|
|
assert isinstance(result, Experiment)
|
|
|
|
def test_experiment_validate_with_type_annotation(
|
|
self, mock_backend, simple_test_data
|
|
):
|
|
"""Test that Experiment.validate_with() has correct type annotation."""
|
|
experiment = Experiment("test_experiment", mock_backend, data=simple_test_data)
|
|
|
|
# This should type-check correctly
|
|
result: Experiment = experiment.validate_with(SimpleTestModel)
|
|
assert isinstance(result, Experiment)
|
|
|
|
|
|
class TestComplexDataHandling:
|
|
"""Test that inheritance works correctly with complex data."""
|
|
|
|
def test_dataset_complex_data_preservation(self, mock_backend, complex_test_data):
|
|
"""Test Dataset with complex data maintains type."""
|
|
# Note: This test focuses on type preservation, not CSV serialization issues
|
|
dataset = Dataset("test_dataset", mock_backend, data=complex_test_data)
|
|
|
|
# Validate should return Dataset
|
|
try:
|
|
validated = dataset.validate_with(ComplexTestModel)
|
|
assert isinstance(validated, Dataset)
|
|
except Exception as e:
|
|
# If validation fails due to CSV serialization, that's a separate issue
|
|
# The important thing is that the return type would be Dataset
|
|
pytest.skip(f"Validation failed due to serialization: {e}")
|
|
|
|
def test_experiment_complex_data_preservation(
|
|
self, mock_backend, complex_test_data
|
|
):
|
|
"""Test Experiment with complex data maintains type."""
|
|
experiment = Experiment("test_experiment", mock_backend, data=complex_test_data)
|
|
|
|
# Validate should return Experiment
|
|
try:
|
|
validated = experiment.validate_with(ComplexTestModel)
|
|
assert isinstance(validated, Experiment)
|
|
except Exception as e:
|
|
# If validation fails due to CSV serialization, that's a separate issue
|
|
pytest.skip(f"Validation failed due to serialization: {e}")
|