Coverage for src / rendercv / schema / models / cv / entries / bases / entry_with_date.py: 100%

16 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-25 13:49 +0000

1import re 

2from datetime import date as Date 

3from typing import Annotated 

4 

5import pydantic 

6 

7from .entry import BaseEntry 

8 

9 

10def validate_arbitrary_date(date: int | str) -> int | str: 

11 """Validate date format while allowing flexible user input. 

12 

13 Why: 

14 Users enter dates like "Fall 2023" or "2020-09" for events. Strict 

15 dates (YYYY-MM-DD/YYYY-MM/YYYY) get validated via ISO parsing, while 

16 custom text passes through for template rendering. ValueError from 

17 fromisoformat() propagates to Pydantic, which converts it into a 

18 specific user-friendly message (e.g., "The month must be between 

19 1 and 12."). 

20 

21 Args: 

22 date: Date value to validate. 

23 

24 Returns: 

25 Original date if valid. 

26 """ 

27 date_str = str(date) 

28 

29 if re.fullmatch(r"\d{4}-\d{2}-\d{2}", date_str): 

30 Date.fromisoformat(date_str) 

31 elif re.fullmatch(r"\d{4}-\d{2}", date_str): 

32 Date.fromisoformat(f"{date_str}-01") 

33 

34 return date 

35 

36 

37type ArbitraryDate = Annotated[ 

38 int | str, pydantic.AfterValidator(validate_arbitrary_date) 

39] 

40 

41 

42class BaseEntryWithDate(BaseEntry): 

43 model_config = pydantic.ConfigDict(json_schema_extra={"description": None}) 

44 

45 date: ArbitraryDate | None = pydantic.Field( 

46 default=None, 

47 description=( 

48 "The date of this event in YYYY-MM-DD, YYYY-MM, or YYYY format, or any" 

49 " custom text like 'Fall 2023'. Use this for single-day or imprecise dates." 

50 " For date ranges, use `start_date` and `end_date` instead." 

51 ), 

52 examples=["2020-09-24", "2020-09", "2020", "Fall 2023", "Summer 2020"], 

53 )