Coverage for health / cli / manual.py: 0%

102 statements  

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

1""" 

2CLI tool for manual health data entry. 

3""" 

4 

5import sys 

6from datetime import date 

7from typing import Optional 

8 

9import click 

10 

11from health.services.manual_log_storage import ManualLogStorage 

12from health.models.manual_log import ( 

13 DietEntry, 

14 AlcoholEntry, 

15 SupplementEntry, 

16 BodyFeelingEntry, 

17) 

18from health.utils.date_utils import parse_date 

19from health.utils.logging_config import setup_logger 

20 

21logger = setup_logger(__name__) 

22 

23 

24@click.group() 

25def cli() -> None: 

26 """Manual Health Data Entry CLI.""" 

27 pass 

28 

29 

30def _get_date(date_str: Optional[str]) -> date: 

31 """Parse date string or return today.""" 

32 if date_str: 

33 return parse_date(date_str) 

34 return date.today() 

35 

36 

37@cli.command() 

38@click.option("--time", required=True, help="Time of meal (HH:MM)") 

39@click.option("--desc", required=True, help="Description of what was eaten") 

40@click.option("--type", "meal_type", help="Meal type (breakfast/lunch/dinner/snack)") 

41@click.option("--cals", type=int, help="Estimated calories") 

42@click.option("--carbs", help="Carb content (Low/Medium/High)") 

43@click.option("--notes", help="Additional notes") 

44@click.option("--date", "date_str", help="Date of entry (YYYY-MM-DD)") 

45def diet( 

46 time: str, 

47 desc: str, 

48 meal_type: Optional[str], 

49 cals: Optional[int], 

50 carbs: Optional[str], 

51 notes: Optional[str], 

52 date_str: Optional[str], 

53) -> None: 

54 """Add a diet entry.""" 

55 try: 

56 storage = ManualLogStorage() 

57 target_date = _get_date(date_str) 

58 

59 entry = DietEntry( 

60 time=time, 

61 description=desc, 

62 meal_type=meal_type, 

63 estimated_calories=cals, 

64 carbs=carbs, 

65 notes=notes, 

66 ) 

67 

68 storage.add_diet_entry(target_date, entry) 

69 click.echo(f"✅ Added diet entry for {target_date}: {desc}") 

70 

71 except Exception as e: 

72 click.echo(f"❌ Failed to add diet entry: {e}", err=True) 

73 sys.exit(1) 

74 

75 

76@cli.command() 

77@click.option("--time", required=True, help="Time of consumption (HH:MM)") 

78@click.option("--type", "drink_type", required=True, help="Type of alcohol") 

79@click.option("--amount", required=True, help="Amount consumed") 

80@click.option("--food", help="Food eaten with alcohol") 

81@click.option("--nac", is_flag=True, help="NAC taken?") 

82@click.option("--notes", help="Additional notes") 

83@click.option("--date", "date_str", help="Date of entry (YYYY-MM-DD)") 

84def alcohol( 

85 time: str, 

86 drink_type: str, 

87 amount: str, 

88 food: Optional[str], 

89 nac: bool, 

90 notes: Optional[str], 

91 date_str: Optional[str], 

92) -> None: 

93 """Add an alcohol entry.""" 

94 try: 

95 storage = ManualLogStorage() 

96 target_date = _get_date(date_str) 

97 

98 entry = AlcoholEntry( 

99 time=time, 

100 drink_type=drink_type, 

101 amount=amount, 

102 food_with_alcohol=food, 

103 nac_taken=nac, 

104 notes=notes, 

105 ) 

106 

107 storage.add_alcohol_entry(target_date, entry) 

108 click.echo(f"✅ Added alcohol entry for {target_date}: {drink_type}") 

109 

110 except Exception as e: 

111 click.echo(f"❌ Failed to add alcohol entry: {e}", err=True) 

112 sys.exit(1) 

113 

114 

115@cli.command() 

116@click.option("--time", required=True, help="Time taken (HH:MM)") 

117@click.option("--name", required=True, help="Supplement name") 

118@click.option("--dosage", help="Dosage") 

119@click.option("--timing", help="Timing (morning/evening used for sorting)") 

120@click.option("--notes", help="Additional notes") 

121@click.option("--date", "date_str", help="Date of entry (YYYY-MM-DD)") 

122def supp( 

123 time: str, 

124 name: str, 

125 dosage: Optional[str], 

126 timing: Optional[str], 

127 notes: Optional[str], 

128 date_str: Optional[str], 

129) -> None: 

130 """Add a supplement entry.""" 

131 try: 

132 storage = ManualLogStorage() 

133 target_date = _get_date(date_str) 

134 

135 entry = SupplementEntry( 

136 time=time, 

137 supplement_name=name, 

138 dosage=dosage, 

139 timing=timing, 

140 notes=notes, 

141 ) 

142 

143 storage.add_supplement_entry(target_date, entry) 

144 click.echo(f"✅ Added supplement entry for {target_date}: {name}") 

145 

146 except Exception as e: 

147 click.echo(f"❌ Failed to add supplement entry: {e}", err=True) 

148 sys.exit(1) 

149 

150 

151@cli.command() 

152@click.option("--time", required=True, help="Time of feeling (HH:MM)") 

153@click.option("--type", "feeling_type", required=True, help="Type of feeling") 

154@click.option("--desc", required=True, help="Description") 

155@click.option("--severity", type=int, help="Severity (1-10)") 

156@click.option("--loc", "location", help="Body location") 

157@click.option("--triggers", help="Possible triggers") 

158@click.option("--notes", help="Additional notes") 

159@click.option("--date", "date_str", help="Date of entry (YYYY-MM-DD)") 

160def feeling( 

161 time: str, 

162 feeling_type: str, 

163 desc: str, 

164 severity: Optional[int], 

165 location: Optional[str], 

166 triggers: Optional[str], 

167 notes: Optional[str], 

168 date_str: Optional[str], 

169) -> None: 

170 """Add a body feeling/symptom entry.""" 

171 try: 

172 storage = ManualLogStorage() 

173 target_date = _get_date(date_str) 

174 

175 entry = BodyFeelingEntry( 

176 time=time, 

177 feeling_type=feeling_type, 

178 description=desc, 

179 severity=severity, 

180 location=location, 

181 triggers=triggers, 

182 notes=notes, 

183 ) 

184 

185 storage.add_feeling_entry(target_date, entry) 

186 click.echo(f"✅ Added feeling entry for {target_date}: {feeling_type}") 

187 

188 except Exception as e: 

189 click.echo(f"❌ Failed to add feeling entry: {e}", err=True) 

190 sys.exit(1) 

191 

192 

193@cli.command() 

194@click.option("--mode", required=True, help="Fasting mode (OMAD/PSMF/etc)") 

195@click.option("--date", "date_str", help="Date of entry (YYYY-MM-DD)") 

196def fasting(mode: str, date_str: Optional[str]) -> None: 

197 """Set fasting mode for a day.""" 

198 try: 

199 storage = ManualLogStorage() 

200 target_date = _get_date(date_str) 

201 

202 storage.set_fasting_mode(target_date, mode) 

203 click.echo(f"✅ Set fasting mode for {target_date}: {mode}") 

204 

205 except Exception as e: 

206 click.echo(f"❌ Failed to set fasting mode: {e}", err=True) 

207 sys.exit(1) 

208 

209 

210if __name__ == "__main__": 

211 cli()