Coverage for cc_modules/cc_summaryelement.py: 50%
48 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
1#!/usr/bin/env python
3"""
4camcops_server/cc_modules/cc_summaryelement.py
6===============================================================================
8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
11 This file is part of CamCOPS.
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.
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.
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/>.
26===============================================================================
28**Classes to represent summary information created by tasks.**
30For example, the PHQ9 task calculates a total score; that's part of its summary
31information.
33"""
35from collections import OrderedDict
36from typing import Any, Dict, List, Optional, Set, Type, TYPE_CHECKING, Union
38from cardinal_pythonlib.reprfunc import auto_repr
39from sqlalchemy.sql.schema import Column
40from sqlalchemy.sql.type_api import TypeEngine
42from camcops_server.cc_modules.cc_dataclasses import SummarySchemaInfo
43from camcops_server.cc_modules.cc_db import TaskDescendant
44from camcops_server.cc_modules.cc_spreadsheet import SpreadsheetPage
45from camcops_server.cc_modules.cc_xml import XmlElement
47if TYPE_CHECKING:
48 from camcops_server.cc_modules.cc_task import Task
51# =============================================================================
52# SummaryElement
53# =============================================================================
56class SummaryElement(object):
57 """
58 Returned by tasks to represent extra summary information that they
59 calculate.
61 Use this for extra information that can be added to a row represented by a
62 task or its ancillary object.
63 """
65 def __init__(
66 self, name: str, coltype: TypeEngine, value: Any, comment: str = None
67 ) -> None:
68 """
69 Args:
70 name: column name
71 coltype: SQLAlchemy column type; e.g. ``Integer()``,
72 ``String(length=50)``
73 value: value
74 comment: explanatory comment
75 """
76 self.name = name
77 self.coltype = coltype
78 self.value = value
79 self.comment = comment
81 @property
82 def decorated_comment(self) -> Optional[str]:
83 return "(SUMMARY) " + self.comment if self.comment else None
86# =============================================================================
87# ExtraSummaryTable
88# =============================================================================
91class ExtraSummaryTable(TaskDescendant):
92 """
93 Additional summary information returned by a task.
95 Use this to represent an entire table that doesn't have a 1:1 relationship
96 with rows of a task or ancillary object.
97 """
99 def __init__(
100 self,
101 tablename: str,
102 xmlname: str,
103 columns: List[Column],
104 rows: List[Union[Dict[str, Any], OrderedDict]],
105 task: "Task",
106 ) -> None:
107 """
108 Args:
109 tablename: name of the additional summary table
110 xmlname: name of the XML tag to encapsulate this information
111 columns: list of SQLAlchemy columns
112 rows: list of rows, where each row is a dictionary mapping
113 column names to values
114 task: parent task (for cross-referencing in some kinds of export)
115 """
116 self.tablename = tablename
117 self.xmlname = xmlname
118 self.columns = columns
119 self.rows = rows
120 self.task = task
122 def get_xml_element(self) -> XmlElement:
123 """
124 Returns an :class:`camcops_server.cc_modules.cc_xml.XmlElement`
125 representing this summary table.
126 """
127 itembranches = [] # type: List[XmlElement]
128 for valuedict in self.rows:
129 leaves = [] # type: List[XmlElement]
130 for k, v in valuedict.items():
131 leaves.append(XmlElement(name=k, value=v))
132 branch = XmlElement(name=self.tablename, value=leaves)
133 itembranches.append(branch)
134 return XmlElement(name=self.xmlname, value=itembranches)
136 def get_spreadsheet_page(self) -> SpreadsheetPage:
137 """
138 Returns an
139 :class:`camcops_server.cc_modules.cc_spreadsheet.SpreadsheetPage`
140 representing this summary table.
141 """
142 return SpreadsheetPage(name=self.tablename, rows=self.rows)
144 def get_spreadsheet_schema_elements(self) -> Set[SummarySchemaInfo]:
145 """
146 Schema equivalent to :func:`get_spreadsheet_page`.
147 """
148 return set(
149 SummarySchemaInfo.from_column(
150 c,
151 table_name=self.tablename,
152 source=SummarySchemaInfo.SSV_SUMMARY,
153 )
154 for c in self.columns
155 )
157 def __repr__(self) -> str:
158 return auto_repr(self)
160 # -------------------------------------------------------------------------
161 # TaskDescendant overrides
162 # -------------------------------------------------------------------------
164 @classmethod
165 def task_ancestor_class(cls) -> Optional[Type["Task"]]:
166 return None
168 def task_ancestor(self) -> Optional["Task"]:
169 return self.task