This repository was archived by the owner on May 13, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDrugCRD.py
More file actions
executable file
·261 lines (209 loc) · 8.14 KB
/
DrugCRD.py
File metadata and controls
executable file
·261 lines (209 loc) · 8.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#!/usr/bin/env python
"""Report to list the Comprehensive Review Dates for drug information docs.
"""
from functools import cached_property
from datetime import date
from cdrcgi import Controller, Reporter
class Control(Controller):
"""One master class to rule them all."""
SUBTITLE = "Drugs Comprehensive Review Dates"
TYPES = "single_agent", "combination"
RADIO_BUTTONS = (
(
"show_all", "Display Review Dates",
(
("N", "Show only last review date"),
("Y", "Show all review dates"),
),
),
(
"show_id", "ID Display",
(
("N", "Without CDR ID"),
("Y", "With CDR ID"),
),
),
(
"show_unpub", "Version Display",
(
("N", "Publishable only"),
("Y", "Publishable and non-publishable"),
),
),
)
def build_tables(self):
"""Assemble the tables to be rendered for the report."""
if not self.agent_types:
self.bail("At least one agent type must be selected")
return [agent_type.table for agent_type in self.agent_types]
def populate_form(self, page):
"""Add the fields to the form page.
It's not completely clear why two versions of the report are supported,
one of which shows all of the reviews' dates for each drug document,
and the other of which shows just the date of the most recent review,
given that there is not a single drug document in the system wieh more
than one comprehensive review. TODO: Ask William about this.
Pass:
page - object on which the form lives
"""
fieldset = page.fieldset("Select Agent Type(s)")
for value in self.TYPES:
label = value.replace("_", " ").title() + " Drug"
opts = dict(label=label, value=value, checked=True)
fieldset.append(page.checkbox("type", **opts))
page.form.append(fieldset)
for name, label, values in self.RADIO_BUTTONS:
fieldset = page.fieldset(label)
checked = True
for value, label in values:
opts = dict(checked=checked, value=value, label=label)
fieldset.append(page.radio_button(name, **opts))
checked = False
page.form.append(fieldset)
page.add_output_options("html")
@cached_property
def agent_types(self):
"""Drug agent types selected by the user for the report."""
types = self.fields.getlist("type")
return [AgentType(self, t) for t in types]
@cached_property
def columns(self):
"""Column headers for the report."""
columns = []
if self.show_id:
columns.append(self.Reporter.Column("CDR ID", width="50px"))
columns.extend([
self.Reporter.Column("Doc Title", width="400px"),
self.Reporter.Column("Date", width="75px"),
])
return columns
@cached_property
def show_all(self):
"""Show all dates (instead of just the last one)?"""
return self.fields.getvalue("show_all") == "Y"
@cached_property
def show_id(self):
"""True if the report should include a column for the CDR IDs."""
return self.fields.getvalue("show_id") == "Y"
@cached_property
def show_unpub(self):
"""True if the report should include unpublished summaries."""
return self.fields.getvalue("show_unpub") == "Y"
@cached_property
def subtitle(self):
"""What we show under the main banner."""
if self.request != self.SUBMIT:
return self.SUBTITLE
return f"{self.SUBTITLE} ({date.today()})"
@cached_property
def title(self):
"""What we show for the main banner."""
if self.request != self.SUBMIT:
return self.TITLE
return "PDQ Drug Summary Comprehensive Review Report"
class AgentType:
"""Subset of drug summaries based on drug agent type."""
DOCTYPE = "DrugInformationSummary"
COMBO_PATH = f"/{DOCTYPE}/DrugInfoMetaData/DrugInfoType/@Combination"
def __init__(self, control, type_name):
"""Remember the caller's values.
Pass:
control - access to the fields and the database
type_name - "single_agent" or "combination"
"""
self.__control = control
self.__type_name = type_name
def __lt__(self, other):
"Support sorting by caption."
return self.caption < other.caption
@cached_property
def caption(self):
"""What to display at the top of the table."""
if self.__type_name == "combination":
return "Combination Drugs"
return "Single Agent Drugs"
@cached_property
def docs(self):
"""Drug information summaries of this agent type."""
suffix = "" if self.__control.show_unpub else "_pub"
query_term = f"query_term{suffix}"
fields = "t.doc_id", "t.value"
query = self.__control.Query(f"{query_term} t", *fields)
query.where(f"t.path = '/{self.DOCTYPE}/Title'")
if self.__type_name == "combination":
query.join(f"{query_term} c", "c.doc_id = t.doc_id")
query.where(f"c.path = '{self.COMBO_PATH}'")
query.where("c.value = 'Yes'")
else:
query.outer(f"{query_term} c", "c.doc_id = t.doc_id",
f"c.path = '{self.COMBO_PATH}'", "c.value = 'Yes'")
query.where("c.doc_id IS NULL")
self.__control.logger.info("query:\n%s", query)
rows = query.unique().execute(self.__control.cursor).fetchall()
return [Drug(self.__control, *row) for row in rows]
@cached_property
def table(self):
"""Report table for drugs of this action type."""
opts = dict(
caption=self.caption,
sheet_name=self.__type_name,
columns=self.__control.columns,
)
rows = []
for doc in sorted(self.docs):
rows += doc.rows
return Reporter.Table(rows, **opts)
class Drug:
"""Drug information summary document."""
REVIEW_DATE_PATH = f"/{AgentType.DOCTYPE}/ComprehensiveReviewDate"
DATE_TYPE_PATH = f"{REVIEW_DATE_PATH}/@DateType"
def __init__(self, control, doc_id, title):
self.__control = control
self.__doc_id = doc_id
self.__title = title
def __lt__(self, other):
return self.title.upper() < other.title.upper()
@cached_property
def control(self):
"""Access to the report settings and the database."""
return self.__control
@cached_property
def doc_id(self):
"""CDR ID of this DrugInformationSummary document."""
return self.__doc_id
@cached_property
def rows(self):
"""Report table row(s) for this drug document."""
reviews = self.reviews or [""]
if not self.control.show_all:
reviews = reviews[-1:]
rows = []
for review in reviews:
row = [self.title, review]
if self.control.show_id:
row.insert(0, self.doc_id)
rows.append(row)
return rows
@cached_property
def reviews(self):
"""Sequence of comprehensive review dates for this drug document."""
query = self.control.Query("query_term", "value")
query.where(query.Condition("doc_id", self.doc_id))
query.where(query.Condition("path", self.REVIEW_DATE_PATH))
rows = query.execute(self.control.cursor).fetchall()
return sorted([row.value for row in rows])
@cached_property
def title(self):
"""Title for this drug document."""
return self.__title
class Review:
"Information about a single proposed or actual comprehensive review"
def __init__(self, date, state):
self.date = date
self.state = state
def __lt__(self, other):
"Support sorting reviews in chronological order"
return (self.date, self.state) < (other.date, other.state)
if __name__ == "__main__":
"Allow import (by doc or lint tools, for example) without side effects"
Control().run()