Coverage for cc_modules/cc_summaryelement.py : 49%

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
3"""
4camcops_server/cc_modules/cc_summaryelement.py
6===============================================================================
8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com).
10 This file is part of CamCOPS.
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.
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.
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/>.
25===============================================================================
27**Classes to represent summary information created by tasks.**
29For example, the PHQ9 task calculates a total score; that's part of its summary
30information.
32"""
34from collections import OrderedDict
35from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING, Union
37from cardinal_pythonlib.reprfunc import auto_repr
38from sqlalchemy.sql.schema import Column
39from sqlalchemy.sql.type_api import TypeEngine
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
45if TYPE_CHECKING:
46 from camcops_server.cc_modules.cc_task import Task
49# =============================================================================
50# SummaryElement
51# =============================================================================
53class SummaryElement(object):
54 """
55 Returned by tasks to represent extra summary information that they
56 calculate.
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
79 @property
80 def decorated_comment(self) -> Optional[str]:
81 return "(SUMMARY) " + self.comment if self.comment else None
84# =============================================================================
85# ExtraSummaryTable
86# =============================================================================
88class ExtraSummaryTable(TaskDescendant):
89 """
90 Additional summary information returned by a task.
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
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)
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)
137 def __repr__(self) -> str:
138 return auto_repr(self)
140 # -------------------------------------------------------------------------
141 # TaskDescendant overrides
142 # -------------------------------------------------------------------------
144 @classmethod
145 def task_ancestor_class(cls) -> Optional[Type["Task"]]:
146 return None
148 def task_ancestor(self) -> Optional["Task"]:
149 return self.task