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/cc_modules/cc_summaryelement.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**Classes to represent summary information created by tasks.** 

28 

29For example, the PHQ9 task calculates a total score; that's part of its summary 

30information. 

31 

32""" 

33 

34from collections import OrderedDict 

35from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING, Union 

36 

37from cardinal_pythonlib.reprfunc import auto_repr 

38from sqlalchemy.sql.schema import Column 

39from sqlalchemy.sql.type_api import TypeEngine 

40 

41from camcops_server.cc_modules.cc_db import TaskDescendant 

42from camcops_server.cc_modules.cc_tsv import TsvPage 

43from camcops_server.cc_modules.cc_xml import XmlElement 

44 

45if TYPE_CHECKING: 

46 from camcops_server.cc_modules.cc_task import Task 

47 

48 

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

50# SummaryElement 

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

52 

53class SummaryElement(object): 

54 """ 

55 Returned by tasks to represent extra summary information that they 

56 calculate. 

57 

58 Use this for extra information that can be added to a row represented by a 

59 task or its ancillary object. 

60 """ 

61 def __init__(self, 

62 name: str, 

63 coltype: TypeEngine, 

64 value: Any, 

65 comment: str = None) -> None: 

66 """ 

67 Args: 

68 name: column name 

69 coltype: SQLAlchemy column type; e.g. ``Integer()``, 

70 ``String(length=50)`` 

71 value: value 

72 comment: explanatory comment 

73 """ 

74 self.name = name 

75 self.coltype = coltype 

76 self.value = value 

77 self.comment = comment 

78 

79 @property 

80 def decorated_comment(self) -> Optional[str]: 

81 return "(SUMMARY) " + self.comment if self.comment else None 

82 

83 

84# ============================================================================= 

85# ExtraSummaryTable 

86# ============================================================================= 

87 

88class ExtraSummaryTable(TaskDescendant): 

89 """ 

90 Additional summary information returned by a task. 

91 

92 Use this to represent an entire table that doesn't have a 1:1 relationship 

93 with rows of a task or ancillary object. 

94 """ 

95 def __init__(self, 

96 tablename: str, 

97 xmlname: str, 

98 columns: List[Column], 

99 rows: List[Union[Dict[str, Any], OrderedDict]], 

100 task: "Task") -> None: 

101 """ 

102 Args: 

103 tablename: name of the additional summary table 

104 xmlname: name of the XML tag to encapsulate this information 

105 columns: list of SQLAlchemy columns 

106 rows: list of rows, where each row is a dictionary mapping 

107 column names to values 

108 task: parent task (for cross-referencing in some kinds of export) 

109 """ 

110 self.tablename = tablename 

111 self.xmlname = xmlname 

112 self.columns = columns 

113 self.rows = rows 

114 self.task = task 

115 

116 def get_xml_element(self) -> XmlElement: 

117 """ 

118 Returns an :class:`camcops_server.cc_modules.cc_xml.XmlElement` 

119 representing this summary table. 

120 """ 

121 itembranches = [] # type: List[XmlElement] 

122 for valuedict in self.rows: 

123 leaves = [] # type: List[XmlElement] 

124 for k, v in valuedict.items(): 

125 leaves.append(XmlElement(name=k, value=v)) 

126 branch = XmlElement(name=self.tablename, value=leaves) 

127 itembranches.append(branch) 

128 return XmlElement(name=self.xmlname, value=itembranches) 

129 

130 def get_tsv_page(self) -> TsvPage: 

131 """ 

132 Returns an :class:`camcops_server.cc_modules.cc_tsv.TsvPage` 

133 representing this summary table. 

134 """ 

135 return TsvPage(name=self.tablename, rows=self.rows) 

136 

137 def __repr__(self) -> str: 

138 return auto_repr(self) 

139 

140 # ------------------------------------------------------------------------- 

141 # TaskDescendant overrides 

142 # ------------------------------------------------------------------------- 

143 

144 @classmethod 

145 def task_ancestor_class(cls) -> Optional[Type["Task"]]: 

146 return None 

147 

148 def task_ancestor(self) -> Optional["Task"]: 

149 return self.task