Coverage for tasks/chit.py: 63%

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/chit.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**Cambridge-Chicago Compulsivity Trait Scale task.** 

29 

30""" 

31 

32from camcops_server.cc_modules.cc_constants import CssClass 

33from camcops_server.cc_modules.cc_db import add_multiple_columns 

34from camcops_server.cc_modules.cc_html import ( 

35 tr_qa, 

36 get_yes_no_unknown, 

37 tr, 

38 answer, 

39) 

40from camcops_server.cc_modules.cc_request import CamcopsRequest 

41from camcops_server.cc_modules.cc_sqla_coltypes import BoolColumn 

42from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

43from camcops_server.cc_modules.cc_task import ( 

44 TaskHasPatientMixin, 

45 Task, 

46 get_from_dict, 

47) 

48from camcops_server.cc_modules.cc_text import SS 

49from cardinal_pythonlib.stringfunc import strseq 

50from sqlalchemy import Integer 

51from sqlalchemy.ext.declarative import DeclarativeMeta 

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

53 

54 

55class ChitMetaclass(DeclarativeMeta): 

56 # noinspection PyInitNewSignature 

57 def __init__( 

58 cls: Type["Chit"], 

59 name: str, 

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

61 classdict: Dict[str, Any], 

62 ) -> None: 

63 add_multiple_columns( 

64 cls, 

65 "q", 

66 1, 

67 cls.N_SCORED_QUESTIONS, 

68 minimum=0, 

69 maximum=3, 

70 comment_fmt="Q{n} ({s}) (0 strongly disagree - 3 strongly agree)", 

71 comment_strings=[ 

72 "hate unfinished task", 

73 "just right", 

74 "keep doing task", 

75 "get stuck", 

76 "habit", 

77 "addictive", 

78 "stubborn rigid", 

79 "urges", 

80 "rewarding things", 

81 "hard moving", 

82 "higher standards", 

83 "improvement", 

84 "complete", 

85 "avoid situations", 

86 "hobby", 

87 ], 

88 ) 

89 

90 setattr( 

91 cls, 

92 "q16", 

93 BoolColumn("q16", comment="Q16 (negative effect) (0 no, 1 yes)"), 

94 ) 

95 

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

97 

98 

99class Chit(TaskHasPatientMixin, Task, metaclass=ChitMetaclass): 

100 __tablename__ = "chit" 

101 shortname = "CHI-T" 

102 

103 N_SCORED_QUESTIONS = 15 

104 N_QUESTIONS = 16 

105 MAX_SCORE_MAIN = 3 * N_SCORED_QUESTIONS 

106 SCORED_QUESTIONS = strseq("q", 1, N_SCORED_QUESTIONS) 

107 ALL_QUESTIONS = strseq("q", 1, N_QUESTIONS) 

108 

109 @staticmethod 

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

111 _ = req.gettext 

112 return _("Cambridge–Chicago Compulsivity Trait Scale") 

113 

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

115 return self.standard_task_summary_fields() + [ 

116 SummaryElement( 

117 name="total", 

118 coltype=Integer(), 

119 value=self.total_score(), 

120 comment=f"Total score (/{self.MAX_SCORE_MAIN})", 

121 ) 

122 ] 

123 

124 def is_complete(self) -> bool: 

125 if self.any_fields_none(self.ALL_QUESTIONS): 

126 return False 

127 if not self.field_contents_valid(): 

128 return False 

129 return True 

130 

131 def total_score(self) -> int: 

132 return self.sum_fields(self.SCORED_QUESTIONS) 

133 

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

135 score_dict = { 

136 None: None, 

137 0: "0 — " + self.wxstring(req, "a0"), 

138 1: "1 — " + self.wxstring(req, "a1"), 

139 2: "2 — " + self.wxstring(req, "a2"), 

140 3: "3 — " + self.wxstring(req, "a3"), 

141 } 

142 

143 rows = "" 

144 for i in range(1, self.N_SCORED_QUESTIONS + 1): 

145 q_field = "q" + str(i) 

146 question_cell = "{}. {}".format(i, self.wxstring(req, q_field)) 

147 answer_cell = get_from_dict(score_dict, getattr(self, q_field)) 

148 

149 rows += tr_qa(question_cell, answer_cell) 

150 

151 rows += tr_qa( 

152 "16. " + self.wxstring(req, "q16"), get_yes_no_unknown(req, "q16") 

153 ) 

154 

155 html = """ 

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

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

158 {tr_is_complete} 

159 {total_score} 

160 </table> 

161 </div> 

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

163 <tr> 

164 <th width="60%">Question</th> 

165 <th width="40%">Answer</th> 

166 </tr> 

167 {rows} 

168 </table> 

169 <div class="{CssClass.FOOTNOTES}"> 

170 [1] Sum for questions 1–15. 

171 </div> 

172 """.format( 

173 CssClass=CssClass, 

174 tr_is_complete=self.get_is_complete_tr(req), 

175 total_score=tr( 

176 req.sstring(SS.TOTAL_SCORE) + " <sup>[1]</sup>", 

177 answer(self.total_score()) + f" / {self.MAX_SCORE_MAIN}", 

178 ), 

179 rows=rows, 

180 ) 

181 return html