Files
vibrantlabsai--ragas/tests/unit/test_datatable_inheritance.py
2026-07-13 13:35:10 +08:00

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}")