|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import json |
| 4 | +import re |
4 | 5 | import typing |
5 | 6 | from collections import Counter |
6 | 7 | from datetime import UTC, date, datetime |
@@ -273,7 +274,12 @@ class Iteration(BaseModel): |
273 | 274 | def parse_dates(cls, v: str | date) -> date: |
274 | 275 | if isinstance(v, date): |
275 | 276 | return v |
276 | | - return datetime.strptime(v, "%Y%m%d").date() # noqa: DTZ007 |
| 277 | + if not re.fullmatch(r"\d{8}", str(v)): |
| 278 | + raise ValueError(f"Invalid format: {v}. Must be YYYYMMDD with 8 digits.") |
| 279 | + try: |
| 280 | + return datetime.strptime(str(v), "%Y%m%d").date() # noqa: DTZ007 |
| 281 | + except ValueError: |
| 282 | + raise ValueError(f"Invalid date value: {v}. Must be a valid calendar date in YYYYMMDD format.") |
277 | 283 |
|
278 | 284 | @field_serializer("iteration_date", when_used="always") |
279 | 285 | @staticmethod |
@@ -316,7 +322,12 @@ class CampaignConfig(BaseModel): |
316 | 322 | def parse_dates(cls, v: str | date) -> date: |
317 | 323 | if isinstance(v, date): |
318 | 324 | return v |
319 | | - return datetime.strptime(v, "%Y%m%d").date() # noqa: DTZ007 |
| 325 | + if not re.fullmatch(r"\d{8}", str(v)): |
| 326 | + raise ValueError(f"Invalid format: {v}. Must be YYYYMMDD with 8 digits.") |
| 327 | + try: |
| 328 | + return datetime.strptime(str(v), "%Y%m%d").date() # noqa: DTZ007 |
| 329 | + except ValueError: |
| 330 | + raise ValueError(f"Invalid date value: {v}. Must be a valid calendar date in YYYYMMDD format.") |
320 | 331 |
|
321 | 332 | @field_serializer("start_date", "end_date", when_used="always") |
322 | 333 | @staticmethod |
|
0 commit comments