T2: Pydantic v2 — replace @dataclass with BaseModel

- All domain models now use pydantic.BaseModel
- Removed manual to_dict()/from_dict() — use model_dump(mode='json')/model_validate()
- Added field validators:
  - Account.balance >= 0
  - Transaction.amount != 0
  - RecurringCashflow.amount != 0, frequency in {daily, weekly, monthly, yearly}
  - Liability.interest, payment >= 0
  - ExchangeRate.rate > 0
  - ForecastScenario.multipliers >= 0
- pydantic v2 native UUID handling (auto str in JSON)
- Updated excel_sync.py to use model_validate()
- Updated tests/test_model.py and tests/test_currency.py
- Added pydantic>=2.0 to pyproject.toml

Tests: 63/63 pass.
This commit is contained in:
2026-10-08 16:42:04 +03:00
parent feb77ef217
commit c765f3672a
12 changed files with 112 additions and 187 deletions
+7 -16
View File
@@ -1,4 +1,4 @@
from dataclasses import dataclass
from pydantic import BaseModel, Field, field_validator
CURRENCY_SYMBOLS = {
"RUB": "₽",
@@ -12,26 +12,17 @@ CURRENCY_SYMBOLS = {
}
@dataclass
class ExchangeRate:
class ExchangeRate(BaseModel):
from_currency: str = "USD"
to_currency: str = "RUB"
rate: float = 80.0
def to_dict(self) -> dict:
return {
"from_currency": self.from_currency,
"to_currency": self.to_currency,
"rate": self.rate,
}
@field_validator("rate")
@classmethod
def from_dict(cls, data: dict) -> "ExchangeRate":
return cls(
from_currency=data.get("from_currency", "USD"),
to_currency=data.get("to_currency", "RUB"),
rate=data.get("rate", 80.0),
)
def _rate_positive(cls, v: float) -> float:
if v <= 0:
raise ValueError("rate must be positive")
return v
DEFAULT_RATES: list[ExchangeRate] = [