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
« 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.
4Tracks diet, alcohol, supplements, and body feelings.
5"""
7from __future__ import annotations
9from datetime import date, datetime
10from typing import Optional, List
11from pydantic import BaseModel, Field, ConfigDict
14class DietEntry(BaseModel):
15 """Single diet entry for a meal or snack."""
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")
25class AlcoholEntry(BaseModel):
26 """Alcohol consumption entry."""
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")
36class SupplementEntry(BaseModel):
37 """Supplement intake entry."""
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")
46class BodyFeelingEntry(BaseModel):
47 """Body feeling and symptom entry."""
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")
66class DailyManualLog(BaseModel):
67 """Complete manual log for a single day."""
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)
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)
86 model_config = ConfigDict(
87 json_encoders={
88 date: lambda v: v.isoformat(),
89 datetime: lambda v: v.isoformat(),
90 }
91 )