Coverage for tasks/distressthermometer.py: 52%

56 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-08 23:14 +0000

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/distressthermometer.py 

5 

6=============================================================================== 

7 

8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry. 

9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk). 

10 

11 This file is part of CamCOPS. 

12 

13 CamCOPS is free software: you can redistribute it and/or modify 

14 it under the terms of the GNU General Public License as published by 

15 the Free Software Foundation, either version 3 of the License, or 

16 (at your option) any later version. 

17 

18 CamCOPS is distributed in the hope that it will be useful, 

19 but WITHOUT ANY WARRANTY; without even the implied warranty of 

20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

21 GNU General Public License for more details. 

22 

23 You should have received a copy of the GNU General Public License 

24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

25 

26=============================================================================== 

27 

28""" 

29 

30from typing import Any, Dict, List, Tuple, Type 

31 

32from cardinal_pythonlib.stringfunc import strseq 

33from sqlalchemy.ext.declarative import DeclarativeMeta 

34from sqlalchemy.sql.schema import Column 

35from sqlalchemy.sql.sqltypes import Integer, UnicodeText 

36 

37from camcops_server.cc_modules.cc_constants import CssClass, PV 

38from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo 

39from camcops_server.cc_modules.cc_db import add_multiple_columns 

40from camcops_server.cc_modules.cc_html import ( 

41 get_yes_no_none, 

42 subheading_spanning_two_columns, 

43 tr_qa, 

44) 

45from camcops_server.cc_modules.cc_request import CamcopsRequest 

46from camcops_server.cc_modules.cc_sqla_coltypes import ( 

47 CamcopsColumn, 

48 PermittedValueChecker, 

49) 

50from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin 

51 

52 

53# ============================================================================= 

54# Distress Thermometer 

55# ============================================================================= 

56 

57 

58class DistressThermometerMetaclass(DeclarativeMeta): 

59 # noinspection PyInitNewSignature 

60 def __init__( 

61 cls: Type["DistressThermometer"], 

62 name: str, 

63 bases: Tuple[Type, ...], 

64 classdict: Dict[str, Any], 

65 ) -> None: 

66 add_multiple_columns( 

67 cls, 

68 "q", 

69 1, 

70 cls.NQUESTIONS, 

71 pv=PV.BIT, 

72 comment_fmt="{n}. {s} (0 no, 1 yes)", 

73 comment_strings=[ 

74 "child care", 

75 "housing", 

76 "insurance/financial", 

77 "transportation", 

78 "work/school", 

79 "children", 

80 "partner", 

81 "close friend/relative", 

82 "depression", 

83 "fears", 

84 "nervousness", 

85 "sadness", 

86 "worry", 

87 "loss of interest", 

88 "spiritual/religious", 

89 "appearance", 

90 "bathing/dressing", 

91 "breathing", 

92 "urination", 

93 "constipation", 

94 "diarrhoea", 

95 "eating", 

96 "fatigue", 

97 "feeling swollen", 

98 "fevers", 

99 "getting around", 

100 "indigestion", 

101 "memory/concentration", 

102 "mouth sores", 

103 "nausea", 

104 "nose dry/congested", 

105 "pain", 

106 "sexual", 

107 "skin dry/itchy", 

108 "sleep", 

109 "tingling in hands/feet", 

110 ], 

111 ) 

112 super().__init__(name, bases, classdict) 

113 

114 

115class DistressThermometer( 

116 TaskHasPatientMixin, Task, metaclass=DistressThermometerMetaclass 

117): 

118 """ 

119 Server implementation of the DistressThermometer task. 

120 """ 

121 

122 __tablename__ = "distressthermometer" 

123 shortname = "Distress Thermometer" 

124 

125 distress = CamcopsColumn( 

126 "distress", 

127 Integer, 

128 permitted_value_checker=PermittedValueChecker(minimum=0, maximum=10), 

129 comment="Distress (0 none - 10 extreme)", 

130 ) 

131 other = Column("other", UnicodeText, comment="Other problems") 

132 

133 NQUESTIONS = 36 

134 COMPLETENESS_FIELDS = strseq("q", 1, NQUESTIONS) + ["distress"] 

135 

136 @staticmethod 

137 def longname(req: "CamcopsRequest") -> str: 

138 _ = req.gettext 

139 return _("Distress Thermometer") 

140 

141 def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]: 

142 if self.distress is None: 

143 return CTV_INCOMPLETE 

144 return [CtvInfo(content=f"Overall distress: {self.distress}/10")] 

145 

146 def is_complete(self) -> bool: 

147 return ( 

148 self.all_fields_not_none(self.COMPLETENESS_FIELDS) 

149 and self.field_contents_valid() 

150 ) 

151 

152 def get_task_html(self, req: CamcopsRequest) -> str: 

153 h = f""" 

154 <div class="{CssClass.SUMMARY}"> 

155 <table class="{CssClass.SUMMARY}"> 

156 {self.get_is_complete_tr(req)} 

157 {tr_qa("Overall distress (0–10)", self.distress)} 

158 </table> 

159 </div> 

160 <div class="{CssClass.EXPLANATION}"> 

161 All questions relate to distress/problems “in the past week, 

162 including today” (yes = problem, no = no problem). 

163 </div> 

164 <table class="{CssClass.TASKDETAIL}"> 

165 <tr> 

166 <th width="50%">Question</th> 

167 <th width="50%">Answer</th> 

168 </tr> 

169 """ 

170 h += tr_qa( 

171 "Distress (0 no distress – 10 extreme distress)", self.distress 

172 ) 

173 h += subheading_spanning_two_columns("Practical problems") 

174 for i in range(1, 5 + 1): 

175 h += tr_qa( 

176 f"{i}. {self.wxstring(req, 'q' + str(i))}", 

177 get_yes_no_none(req, getattr(self, "q" + str(i))), 

178 ) 

179 h += subheading_spanning_two_columns("Family problems") 

180 for i in range(6, 8 + 1): 

181 h += tr_qa( 

182 f"{i}. {self.wxstring(req, 'q' + str(i))}", 

183 get_yes_no_none(req, getattr(self, "q" + str(i))), 

184 ) 

185 h += subheading_spanning_two_columns("Emotional problems") 

186 for i in range(9, 14 + 1): 

187 h += tr_qa( 

188 f"{i}. {self.wxstring(req, 'q' + str(i))}", 

189 get_yes_no_none(req, getattr(self, "q" + str(i))), 

190 ) 

191 h += subheading_spanning_two_columns("Spiritual problems") 

192 for i in range(15, 15 + 1): 

193 h += tr_qa( 

194 f"{i}. {self.wxstring(req, 'q' + str(i))}", 

195 get_yes_no_none(req, getattr(self, "q" + str(i))), 

196 ) 

197 h += subheading_spanning_two_columns("Physical problems") 

198 for i in range(16, self.NQUESTIONS + 1): 

199 h += tr_qa( 

200 f"{i}. {self.wxstring(req, 'q' + str(i))}", 

201 get_yes_no_none(req, getattr(self, "q" + str(i))), 

202 ) 

203 h += subheading_spanning_two_columns("Other problems") 

204 h += tr_qa(self.wxstring(req, "other_s"), self.other) 

205 h += """ 

206 </table> 

207 """ 

208 return h