1.8 KiB
1.8 KiB
| id | type | title | tags | importance | confidence | created | updated | relations | |||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 530bfb6f-841c-4381-b8a4-d0b6fbc02878 | fix | Fix: Pydantic bare default evaluated at class definition time (paper-dynasty-database) |
|
0.65 | 0.8 | 2026-03-03T20:06:06.122074+00:00 | 2026-03-03T20:06:06.763300+00:00 |
|
Problem
PlayerModel.offense_col in app/routers_v2/mlbplayers.py used a bare random.randint(1, 3) as the Pydantic field default. Python evaluates this expression once at class definition time (module import), so every instance shared the same random integer for the entire process lifetime.
Root Cause
Pydantic field defaults that are not wrapped in Field(default_factory=...) are evaluated eagerly at class body execution time — identical to how Python function default argument values work. This is a common footgun with mutable or randomised defaults.
Solution
# Before (broken)
offense_col: int = random.randint(1, 3)
# After (correct)
offense_col: int = pydantic.Field(default_factory=lambda: random.randint(1, 3))
default_factory is called on each model instantiation, producing a fresh value per request.
Files Changed
app/routers_v2/mlbplayers.pyline 40
References
- Issue #24, PR #38 in cal/paper-dynasty-database