Coverage for health / models / manual_log.py: 0%

43 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-02 17:44 +0800

1""" 

2Manual health log models for user-entered data. 

3 

4Tracks diet, alcohol, supplements, and body feelings. 

5""" 

6 

7from __future__ import annotations 

8 

9from datetime import date, datetime 

10from typing import Optional, List 

11from pydantic import BaseModel, Field, ConfigDict 

12 

13 

14class DietEntry(BaseModel): 

15 """Single diet entry for a meal or snack.""" 

16 

17 time: str = Field(..., description="Time of meal (HH:MM format)") 

18 description: str = Field(..., description="What was eaten") 

19 meal_type: Optional[str] = Field(None, description="breakfast/lunch/dinner/snack") 

20 estimated_calories: Optional[int] = Field(None, description="Estimated calories") 

21 carbs: Optional[str] = Field(None, description="Low/Medium/High carb content") 

22 notes: Optional[str] = Field(None, description="Additional notes") 

23 

24 

25class AlcoholEntry(BaseModel): 

26 """Alcohol consumption entry.""" 

27 

28 time: str = Field(..., description="Time of consumption (HH:MM format)") 

29 drink_type: str = Field(..., description="Type of alcohol (wine/spirits/beer/cocktail)") 

30 amount: str = Field(..., description="Amount consumed (e.g., '2 glasses', '3 shots')") 

31 food_with_alcohol: Optional[str] = Field(None, description="What food was eaten") 

32 nac_taken: bool = Field(False, description="Whether NAC was taken pre-drinking") 

33 notes: Optional[str] = Field(None, description="Additional notes") 

34 

35 

36class SupplementEntry(BaseModel): 

37 """Supplement intake entry.""" 

38 

39 time: str = Field(..., description="Time taken (HH:MM format)") 

40 supplement_name: str = Field(..., description="Name of supplement") 

41 dosage: Optional[str] = Field(None, description="Dosage taken") 

42 timing: Optional[str] = Field(None, description="morning/afternoon/evening/before_bed") 

43 notes: Optional[str] = Field(None, description="Additional notes") 

44 

45 

46class BodyFeelingEntry(BaseModel): 

47 """Body feeling and symptom entry.""" 

48 

49 time: str = Field(..., description="Time recorded (HH:MM format)") 

50 feeling_type: str = Field( 

51 ..., 

52 description="Type of feeling (chest_tightness/fatigue/pain/energy/other)" 

53 ) 

54 severity: Optional[int] = Field( 

55 None, 

56 ge=1, 

57 le=10, 

58 description="Severity 1-10" 

59 ) 

60 location: Optional[str] = Field(None, description="Body location if applicable") 

61 description: str = Field(..., description="Detailed description") 

62 triggers: Optional[str] = Field(None, description="Possible triggers") 

63 notes: Optional[str] = Field(None, description="Additional notes") 

64 

65 

66class DailyManualLog(BaseModel): 

67 """Complete manual log for a single day.""" 

68 

69 log_date: date = Field(..., description="Date of the log") 

70 fasting_mode: Optional[str] = Field( 

71 None, 

72 description="PSMF/OMAD/Water Fast/Normal" 

73 ) 

74 diet_entries: List[DietEntry] = Field(default_factory=list) 

75 alcohol_entries: List[AlcoholEntry] = Field(default_factory=list) 

76 supplement_entries: List[SupplementEntry] = Field(default_factory=list) 

77 feeling_entries: List[BodyFeelingEntry] = Field(default_factory=list) 

78 

79 daily_summary: Optional[str] = Field( 

80 None, 

81 description="Overall summary of the day" 

82 ) 

83 created_at: datetime = Field(default_factory=datetime.now) 

84 updated_at: datetime = Field(default_factory=datetime.now) 

85 

86 model_config = ConfigDict( 

87 json_encoders={ 

88 date: lambda v: v.isoformat(), 

89 datetime: lambda v: v.isoformat(), 

90 } 

91 )