Skip to content

chore: migrate analytics/calibration.py to Pydantic BaseModel — pilot (AC-489, AC-481)#593

Merged
jayscambler merged 2 commits intomainfrom
chore/pydantic-migration-analytics
Mar 31, 2026
Merged

chore: migrate analytics/calibration.py to Pydantic BaseModel — pilot (AC-489, AC-481)#593
jayscambler merged 2 commits intomainfrom
chore/pydantic-migration-analytics

Conversation

@jayscambler
Copy link
Copy Markdown
Contributor

Summary

Pilot migration of analytics dataclasses to Pydantic BaseModel, establishing the pattern for the remaining ~60 dataclasses with manual to_dict/from_dict.

Problem

295 dataclasses across the codebase implement manual to_dict() -> dict[str, Any] and from_dict(data) classmethods — boilerplate that Pydantic provides for free via model_dump() and model_validate().

Changes

Converted analytics/calibration.py (3 classes)

Class to_dict lines removed from_dict lines removed
CalibrationSample 15 → 1 15 → 1
CalibrationOutcome 11 → 1 11 → 1
CalibrationRound 8 → 1 10 → 1

Total: ~78 lines of boilerplate → 6 lines of aliases

Backward compatibility

to_dict() and from_dict() kept as thin aliases (self.model_dump() / cls.model_validate(data)) so existing callers (CalibrationStore, SpotCheckSampler) work unchanged.

Pattern for future migrations

# Before (dataclass)
@dataclass(slots=True)
class Foo:
    x: str
    y: int = 0
    
    def to_dict(self) -> dict[str, Any]:
        return {"x": self.x, "y": self.y}
    
    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Foo:
        return cls(x=data["x"], y=data.get("y", 0))

# After (Pydantic)
class Foo(BaseModel):
    x: str
    y: int = 0
    
    def to_dict(self) -> dict[str, Any]:
        return self.model_dump()
    
    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Foo:
        return cls.model_validate(data)

TDD

Added test_pydantic_migration.py with 5 tests:

  • model_dump roundtrip
  • JSON serialization
  • Nested model handling
  • Backward-compat to_dict alias

Verification

  • ruff check src — all checks passed
  • mypy src — zero errors
  • pytest tests/ — all tests pass

Issues

Partially resolves AC-489 and AC-481

…, AC-481)

Pilot migration: converted 3 dataclasses (CalibrationSample,
CalibrationOutcome, CalibrationRound) from @DataClass to Pydantic
BaseModel. Eliminates ~78 lines of hand-rolled to_dict/from_dict
boilerplate — Pydantic provides model_dump/model_validate natively.

Backward-compatible: to_dict() and from_dict() kept as thin aliases
so existing callers (CalibrationStore, SpotCheckSampler) don't break.

TDD: Added test_pydantic_migration.py with 5 tests verifying
model_dump roundtrip, JSON serialization, and nested model handling.

Pattern established for remaining ~60 analytics dataclasses.
@jayscambler jayscambler merged commit 4064e72 into main Mar 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant