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/elixhauserci.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**Elixhauser Comorbidity Index task.** 

28 

29""" 

30 

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

32 

33from sqlalchemy.ext.declarative import DeclarativeMeta 

34from sqlalchemy.sql.sqltypes import Integer 

35 

36from camcops_server.cc_modules.cc_constants import CssClass 

37from camcops_server.cc_modules.cc_html import get_yes_no_unknown, tr_qa 

38from camcops_server.cc_modules.cc_request import CamcopsRequest 

39from camcops_server.cc_modules.cc_sqla_coltypes import BoolColumn 

40from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

41from camcops_server.cc_modules.cc_task import ( 

42 Task, 

43 TaskHasClinicianMixin, 

44 TaskHasPatientMixin, 

45) 

46from camcops_server.cc_modules.cc_text import SS 

47 

48 

49# ============================================================================= 

50# ElixhauserCI 

51# ============================================================================= 

52 

53FIELDNAMES = [ 

54 "congestive_heart_failure", 

55 "cardiac_arrhythmias", 

56 "valvular_disease", 

57 "pulmonary_circulation_disorders", 

58 "peripheral_vascular_disorders", 

59 

60 "hypertension_uncomplicated", 

61 "hypertension_complicated", 

62 "paralysis", 

63 "other_neurological_disorders", 

64 "chronic_pulmonary_disease", 

65 

66 "diabetes_uncomplicated", 

67 "diabetes_complicated", 

68 "hypothyroidism", 

69 "renal_failure", 

70 "liver_disease", 

71 

72 "peptic_ulcer_disease_exc_bleeding", 

73 "aids_hiv", 

74 "lymphoma", 

75 "metastatic_cancer", 

76 "solid_tumor_without_metastasis", 

77 

78 "rheumatoid_arthritis_collagen_vascular_diseases", 

79 "coagulopathy", 

80 "obesity", 

81 "weight_loss", 

82 "fluid_electrolyte_disorders", 

83 

84 "blood_loss_anemia", 

85 "deficiency_anemia", 

86 "alcohol_abuse", 

87 "drug_abuse", 

88 "psychoses", 

89 

90 "depression", 

91] 

92MAX_SCORE = len(FIELDNAMES) 

93 

94CONSTRAINT_NAME_MAP = { 

95 "pulmonary_circulation_disorders": "ck_elixhauserci_pulm_circ", 

96 "peptic_ulcer_disease_exc_bleeding": "ck_elixhauserci_peptic", 

97 "solid_tumor_without_metastasis": "ck_elixhauserci_tumour_no_mets", 

98 "rheumatoid_arthritis_collagen_vascular_diseases": "ck_elixhauserci_ra_cvd", # noqa 

99} 

100 

101 

102class ElixhauserCIMetaclass(DeclarativeMeta): 

103 # noinspection PyInitNewSignature 

104 def __init__(cls: Type['ElixhauserCI'], 

105 name: str, 

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

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

108 for colname in FIELDNAMES: 

109 constraint_name = CONSTRAINT_NAME_MAP.get(colname) 

110 setattr( 

111 cls, colname, 

112 BoolColumn(colname, comment="Disease present (0 no, 1 yes)", 

113 constraint_name=constraint_name)) 

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

115 

116 

117class ElixhauserCI(TaskHasPatientMixin, 

118 TaskHasClinicianMixin, 

119 Task, 

120 metaclass=ElixhauserCIMetaclass): 

121 __tablename__ = "elixhauserci" 

122 shortname = "ElixhauserCI" 

123 

124 @staticmethod 

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

126 _ = req.gettext 

127 return _("Elixhauser Comorbidity Index") 

128 

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

130 return self.standard_task_summary_fields() + [ 

131 SummaryElement( 

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

133 value=self.total_score(), 

134 comment=f"Total score (out of {MAX_SCORE})" 

135 ), 

136 ] 

137 

138 def is_complete(self) -> bool: 

139 return self.all_fields_not_none(FIELDNAMES) 

140 

141 def total_score(self) -> int: 

142 return self.count_booleans(FIELDNAMES) 

143 

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

145 score = self.total_score() 

146 q_a = "" 

147 for f in FIELDNAMES: 

148 v = getattr(self, f) 

149 q_a += tr_qa( 

150 self.wxstring(req, f), 

151 get_yes_no_unknown(req, v) 

152 ) 

153 return f""" 

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

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

156 {self.get_is_complete_tr(req)} 

157 <tr> 

158 <td>{req.sstring(SS.TOTAL_SCORE)}</td> 

159 <td><b>{score}</b> / {MAX_SCORE}</td> 

160 </tr> 

161 </table> 

162 </div> 

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

164 <tr> 

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

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

167 </tr> 

168 {q_a} 

169 </table> 

170 """