Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/chit.py 

5 

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

7 

8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com). 

9 

10 This file is part of CamCOPS. 

11 

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

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

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

15 (at your option) any later version. 

16 

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

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

19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

20 GNU General Public License for more details. 

21 

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

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

24 

25=============================================================================== 

26 

27**Cambridge-Chicago Compulsivity Trait Scale task.** 

28 

29""" 

30 

31from camcops_server.cc_modules.cc_constants import CssClass 

32from camcops_server.cc_modules.cc_db import add_multiple_columns 

33from camcops_server.cc_modules.cc_html import ( 

34 tr_qa, 

35 get_yes_no_unknown, 

36 tr, 

37 answer, 

38) 

39from camcops_server.cc_modules.cc_request import CamcopsRequest 

40from camcops_server.cc_modules.cc_sqla_coltypes import BoolColumn 

41from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

42from camcops_server.cc_modules.cc_task import ( 

43 TaskHasPatientMixin, 

44 Task, 

45 get_from_dict, 

46) 

47from camcops_server.cc_modules.cc_text import SS 

48from cardinal_pythonlib.stringfunc import strseq 

49from sqlalchemy import Integer 

50from sqlalchemy.ext.declarative import DeclarativeMeta 

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

52 

53 

54class ChitMetaclass(DeclarativeMeta): 

55 # noinspection PyInitNewSignature 

56 def __init__(cls: Type['Chit'], 

57 name: str, 

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

59 classdict: Dict[str, Any]) -> None: 

60 add_multiple_columns( 

61 cls, "q", 1, cls.N_SCORED_QUESTIONS, 

62 minimum=0, maximum=3, 

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

64 comment_strings=[ 

65 "hate unfinished task", 

66 "just right", 

67 "keep doing task", 

68 "get stuck", 

69 "habit", 

70 "addictive", 

71 "stubborn rigid", 

72 "urges", 

73 "rewarding things", 

74 "hard moving", 

75 "higher standards", 

76 "improvement", 

77 "complete", 

78 "avoid situations", 

79 "hobby"] 

80 ) 

81 

82 setattr( 

83 cls, "q16", 

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

85 ) 

86 

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

88 

89 

90class Chit(TaskHasPatientMixin, 

91 Task, 

92 metaclass=ChitMetaclass): 

93 __tablename__ = "chit" 

94 shortname = "CHI-T" 

95 

96 N_SCORED_QUESTIONS = 15 

97 N_QUESTIONS = 16 

98 MAX_SCORE_MAIN = 3 * N_SCORED_QUESTIONS 

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

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

101 

102 @staticmethod 

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

104 _ = req.gettext 

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

106 

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

108 return self.standard_task_summary_fields() + [ 

109 SummaryElement( 

110 name="total", coltype=Integer(), 

111 value=self.total_score(), 

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

113 ] 

114 

115 def is_complete(self) -> bool: 

116 if self.any_fields_none(self.ALL_QUESTIONS): 

117 return False 

118 if not self.field_contents_valid(): 

119 return False 

120 return True 

121 

122 def total_score(self) -> int: 

123 return self.sum_fields(self.SCORED_QUESTIONS) 

124 

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

126 score_dict = { 

127 None: None, 

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

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

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

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

132 } 

133 

134 rows = "" 

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

136 q_field = "q" + str(i) 

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

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

139 

140 rows += tr_qa(question_cell, answer_cell) 

141 

142 rows += tr_qa("16. " + self.wxstring(req, "q16"), 

143 get_yes_no_unknown(req, "q16")) 

144 

145 html = """ 

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

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

148 {tr_is_complete} 

149 {total_score} 

150 </table> 

151 </div> 

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

153 <tr> 

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

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

156 </tr> 

157 {rows} 

158 </table> 

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

160 [1] Sum for questions 1–15. 

161 </div> 

162 """.format( 

163 CssClass=CssClass, 

164 tr_is_complete=self.get_is_complete_tr(req), 

165 total_score=tr( 

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

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

168 ), 

169 rows=rows, 

170 ) 

171 return html