Coverage for tasks/zbi.py: 65%

51 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/zbi.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.sqltypes import Integer 

35 

36from camcops_server.cc_modules.cc_constants import ( 

37 CssClass, 

38 DATA_COLLECTION_UNLESS_UPGRADED_DIV, 

39) 

40from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo 

41from camcops_server.cc_modules.cc_db import add_multiple_columns 

42from camcops_server.cc_modules.cc_html import answer, tr 

43from camcops_server.cc_modules.cc_request import CamcopsRequest 

44from camcops_server.cc_modules.cc_string import AS 

45from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

46from camcops_server.cc_modules.cc_task import ( 

47 get_from_dict, 

48 Task, 

49 TaskHasPatientMixin, 

50 TaskHasRespondentMixin, 

51) 

52 

53 

54# ============================================================================= 

55# ZBI 

56# ============================================================================= 

57 

58 

59class Zbi12Metaclass(DeclarativeMeta): 

60 # noinspection PyInitNewSignature 

61 def __init__( 

62 cls: Type["Zbi12"], 

63 name: str, 

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

65 classdict: Dict[str, Any], 

66 ) -> None: 

67 add_multiple_columns( 

68 cls, 

69 "q", 

70 1, 

71 cls.NQUESTIONS, 

72 minimum=cls.MIN_PER_Q, 

73 maximum=cls.MAX_PER_Q, 

74 comment_fmt="Q{n}, {s} (0-4, higher worse)", 

75 comment_strings=[ 

76 "insufficient time for self", # 1 

77 "stressed with other responsibilities", 

78 "angry", 

79 "other relationships affected", 

80 "strained", # 5 

81 "health suffered", 

82 "insufficient privacy", 

83 "social life suffered", 

84 "lost control", 

85 "uncertain", # 10 

86 "should do more", 

87 "could care better", 

88 ], 

89 ) 

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

91 

92 

93class Zbi12( 

94 TaskHasRespondentMixin, TaskHasPatientMixin, Task, metaclass=Zbi12Metaclass 

95): 

96 """ 

97 Server implementation of the ZBI-12 task. 

98 """ 

99 

100 __tablename__ = "zbi12" 

101 shortname = "ZBI-12" 

102 info_filename_stem = "zbi" 

103 

104 MIN_PER_Q = 0 

105 MAX_PER_Q = 4 

106 NQUESTIONS = 12 

107 TASK_FIELDS = strseq("q", 1, NQUESTIONS) 

108 MAX_TOTAL = MAX_PER_Q * NQUESTIONS 

109 

110 @staticmethod 

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

112 _ = req.gettext 

113 return _("Zarit Burden Interview-12") 

114 

115 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]: 

116 return self.standard_task_summary_fields() + [ 

117 SummaryElement( 

118 name="total_score", 

119 coltype=Integer(), 

120 value=self.total_score(), 

121 comment=f"Total score (/ {self.MAX_TOTAL})", 

122 ) 

123 ] 

124 

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

126 if not self.is_complete(): 

127 return CTV_INCOMPLETE 

128 return [ 

129 CtvInfo( 

130 content=f"ZBI-12 total score " 

131 f"{self.total_score()}/{self.MAX_TOTAL}" 

132 ) 

133 ] 

134 

135 def total_score(self) -> int: 

136 return self.sum_fields(self.TASK_FIELDS) 

137 

138 def is_complete(self) -> bool: 

139 return ( 

140 self.field_contents_valid() 

141 and self.is_respondent_complete() 

142 and self.all_fields_not_none(self.TASK_FIELDS) 

143 ) 

144 

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

146 option_dict = {None: None} 

147 for a in range(self.MIN_PER_Q, self.MAX_PER_Q + 1): 

148 option_dict[a] = req.wappstring(AS.ZBI_A_PREFIX + str(a)) 

149 h = f""" 

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

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

152 {self.get_is_complete_tr(req)} 

153 <tr> 

154 <td>Total score (/ {self.MAX_TOTAL})</td> 

155 <td>{answer(self.total_score())}</td> 

156 </td> 

157 </table> 

158 </div> 

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

160 <tr> 

161 <th width="75%">Question</th> 

162 <th width="25%">Answer ({self.MIN_PER_Q}–{self.MAX_PER_Q}) 

163 </th> 

164 </tr> 

165 """ 

166 for q in range(1, self.NQUESTIONS + 1): 

167 a = getattr(self, "q" + str(q)) 

168 fa = ( 

169 f"{a}: {get_from_dict(option_dict, a)}" 

170 if a is not None 

171 else None 

172 ) 

173 h += tr(self.wxstring(req, "q" + str(q)), answer(fa)) 

174 h += ( 

175 """ 

176 </table> 

177 """ 

178 + DATA_COLLECTION_UNLESS_UPGRADED_DIV 

179 ) 

180 return h