scout-browser 4.88__py3-none-any.whl → 4.89__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scout/__version__.py +1 -1
- scout/adapter/mongo/base.py +1 -1
- scout/adapter/mongo/case.py +185 -117
- scout/adapter/mongo/omics_variant.py +19 -0
- scout/build/case.py +1 -0
- scout/commands/load/variants.py +121 -40
- scout/commands/update/case.py +56 -10
- scout/constants/case_tags.py +5 -0
- scout/constants/disease_parsing.py +2 -2
- scout/constants/igv_tracks.py +2 -2
- scout/constants/indexes.py +8 -1
- scout/demo/643594.config.yaml +1 -0
- scout/demo/panel_1.txt +2 -0
- scout/demo/resources/ensembl_exons_37_reduced.txt +135 -0
- scout/demo/resources/ensembl_exons_38_reduced.txt +166 -0
- scout/demo/resources/ensembl_genes_37_reduced.txt +2 -0
- scout/demo/resources/ensembl_genes_38_reduced.txt +2 -0
- scout/demo/resources/ensembl_transcripts_37_reduced.txt +27 -0
- scout/demo/resources/ensembl_transcripts_38_reduced.txt +36 -0
- scout/demo/resources/hgnc_reduced_set.txt +2 -0
- scout/log/handlers.py +2 -1
- scout/log/log.py +48 -61
- scout/models/case/case_loading_models.py +2 -0
- scout/parse/omim.py +2 -2
- scout/server/app.py +23 -7
- scout/server/blueprints/alignviewers/controllers.py +46 -23
- scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
- scout/server/blueprints/cases/controllers.py +21 -47
- scout/server/blueprints/cases/templates/cases/case_report.html +4 -1
- scout/server/blueprints/cases/templates/cases/case_sma.html +19 -0
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +7 -7
- scout/server/blueprints/cases/templates/cases/individuals_table.html +1 -1
- scout/server/blueprints/clinvar/form.py +1 -1
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +2 -2
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +9 -3
- scout/server/blueprints/institutes/controllers.py +11 -38
- scout/server/blueprints/institutes/forms.py +18 -4
- scout/server/blueprints/institutes/templates/overview/cases.html +137 -46
- scout/server/blueprints/login/views.py +16 -12
- scout/server/blueprints/panels/controllers.py +4 -1
- scout/server/blueprints/panels/templates/panels/panel.html +1 -1
- scout/server/blueprints/panels/templates/panels/panels.html +5 -5
- scout/server/blueprints/public/templates/public/index.html +18 -10
- scout/server/blueprints/variant/templates/variant/components.html +0 -1
- scout/server/blueprints/variant/templates/variant/gene_disease_relations.html +1 -1
- scout/server/config.py +3 -0
- scout/server/extensions/__init__.py +2 -0
- scout/server/extensions/chanjo2_extension.py +46 -0
- scout/server/extensions/chanjo_extension.py +44 -1
- scout/server/extensions/matchmaker_extension.py +0 -1
- scout/server/links.py +11 -2
- scout/server/templates/report_base.html +1 -0
- scout/utils/convert.py +1 -1
- scout/utils/date.py +1 -1
- {scout_browser-4.88.dist-info → scout_browser-4.89.dist-info}/METADATA +1 -1
- {scout_browser-4.88.dist-info → scout_browser-4.89.dist-info}/RECORD +60 -59
- {scout_browser-4.88.dist-info → scout_browser-4.89.dist-info}/LICENSE +0 -0
- {scout_browser-4.88.dist-info → scout_browser-4.89.dist-info}/WHEEL +0 -0
- {scout_browser-4.88.dist-info → scout_browser-4.89.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.88.dist-info → scout_browser-4.89.dist-info}/top_level.txt +0 -0
scout/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "4.
|
1
|
+
__version__ = "4.89"
|
scout/adapter/mongo/base.py
CHANGED
@@ -90,7 +90,7 @@ class MongoAdapter(
|
|
90
90
|
def init_app(self, app):
|
91
91
|
"""Setup via Flask."""
|
92
92
|
dbname = app.config["MONGO_DBNAME"]
|
93
|
-
LOG.
|
93
|
+
LOG.info(f"Database name: {dbname}")
|
94
94
|
self.setup(app.config["MONGO_DATABASE"])
|
95
95
|
|
96
96
|
def setup(self, database):
|
scout/adapter/mongo/case.py
CHANGED
@@ -4,10 +4,11 @@ import logging
|
|
4
4
|
import operator
|
5
5
|
import re
|
6
6
|
from copy import deepcopy
|
7
|
-
from typing import Any, Dict, List, Optional
|
7
|
+
from typing import Any, Dict, List, Optional, Union
|
8
8
|
|
9
9
|
import pymongo
|
10
10
|
from bson import ObjectId
|
11
|
+
from werkzeug.datastructures import ImmutableMultiDict
|
11
12
|
|
12
13
|
from scout.build.case import build_case
|
13
14
|
from scout.constants import ACMG_MAP, FILE_TYPE_MAP, ID_PROJECTION, OMICS_FILE_TYPE_MAP
|
@@ -17,6 +18,7 @@ from scout.utils.algorithms import ui_score
|
|
17
18
|
from scout.utils.sort import get_load_priority
|
18
19
|
|
19
20
|
LOG = logging.getLogger(__name__)
|
21
|
+
EXISTS = "$exists"
|
20
22
|
|
21
23
|
|
22
24
|
class CaseHandler(object):
|
@@ -38,7 +40,7 @@ class CaseHandler(object):
|
|
38
40
|
set_1 = set()
|
39
41
|
if len(phenotype_terms) == 0:
|
40
42
|
LOG.warning("No phenotype terms provided, please provide ar least one HPO term")
|
41
|
-
return
|
43
|
+
return []
|
42
44
|
# Add all ancestors of all terms
|
43
45
|
for term in phenotype_terms:
|
44
46
|
hpo_term = self.hpo_term(term)
|
@@ -73,53 +75,48 @@ class CaseHandler(object):
|
|
73
75
|
self,
|
74
76
|
query: Dict[str, Any],
|
75
77
|
query_field: str,
|
76
|
-
|
78
|
+
query_value: str,
|
77
79
|
institute_id: str,
|
78
80
|
):
|
79
|
-
"""Adds query parameters when search is performed by case or phenotype similarity
|
80
|
-
|
81
|
-
Args:
|
82
|
-
query(dict): cases search query
|
83
|
-
query_field(str) example:"status"
|
84
|
-
query_term(str) example:"active"
|
85
|
-
name_query(dict) args provided by users in cases filter search
|
86
|
-
institute_id(str): institute to search cases for
|
87
|
-
"""
|
81
|
+
"""Adds query parameters when search is performed by case or phenotype similarity."""
|
88
82
|
hpo_terms = []
|
89
|
-
order = None
|
90
83
|
CASE_SIMILAR_PROJECTION = {"phenotype_terms": 1}
|
84
|
+
|
91
85
|
if query_field == "similar_case":
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
86
|
+
temp_query_or = {
|
87
|
+
"$or": [
|
88
|
+
{"display_name": query_value},
|
89
|
+
{"individuals.display_name": query_value},
|
90
|
+
{"individuals.subject_id": query_value},
|
91
|
+
{"_id": query_value},
|
92
|
+
]
|
93
|
+
}
|
94
|
+
temp_query = {"$and": [{"owner": institute_id}, temp_query_or]}
|
95
|
+
case_obj = self.case_collection.find_one(temp_query, CASE_SIMILAR_PROJECTION)
|
97
96
|
if case_obj is None:
|
98
97
|
query["_id"] = {"$in": []} # No result should be returned by query
|
99
98
|
return
|
100
99
|
|
101
100
|
for term in case_obj.get("phenotype_terms", []):
|
102
101
|
hpo_terms.append(term.get("phenotype_id"))
|
102
|
+
|
103
103
|
similar_cases = self.cases_by_phenotype(hpo_terms, institute_id, case_obj["_id"])
|
104
104
|
else: # similar HPO terms
|
105
|
-
hpo_terms = list(
|
105
|
+
hpo_terms = list(query_value.replace(" ", "").split(","))
|
106
106
|
similar_cases = self.cases_by_phenotype(hpo_terms, institute_id, None)
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
order
|
114
|
-
|
115
|
-
similar_case_ids.
|
116
|
-
|
117
|
-
query["_id"] = {"$in": similar_case_ids}
|
118
|
-
|
119
|
-
return order
|
108
|
+
similar_case_ids = [
|
109
|
+
similar_case[0] for similar_case in similar_cases
|
110
|
+
] # These are sorted by the most similar to the least
|
111
|
+
self._update_case_id_query(
|
112
|
+
query, similar_case_ids
|
113
|
+
) # This might mess up the order of the _ids
|
114
|
+
query["_id"]["$in"] = sorted(
|
115
|
+
query["_id"]["$in"], key=lambda idx: similar_case_ids.index(idx)
|
116
|
+
) # Sort them again by similarity
|
120
117
|
|
121
118
|
def _set_genes_of_interest_query(
|
122
|
-
self, query: Dict[str, Any], query_field: str,
|
119
|
+
self, query: Dict[str, Any], query_field: str, query_value: str
|
123
120
|
):
|
124
121
|
"""Adds query parameters when search is aimed at retrieving cases with a certain pinned or causative gene
|
125
122
|
|
@@ -128,11 +125,11 @@ class CaseHandler(object):
|
|
128
125
|
Args:
|
129
126
|
query(dict): cases search query
|
130
127
|
query_field(str) "pinned" or "causative"
|
131
|
-
|
128
|
+
query_value(str) example:"POT1"
|
132
129
|
"""
|
133
|
-
hgnc_id = self.hgnc_id(hgnc_symbol=
|
130
|
+
hgnc_id = self.hgnc_id(hgnc_symbol=query_value)
|
134
131
|
if hgnc_id is None:
|
135
|
-
LOG.debug(f"No gene with the HGNC symbol {
|
132
|
+
LOG.debug(f"No gene with the HGNC symbol {query_value} found.")
|
136
133
|
query["_id"] = {"$in": []} # No result should be returned by query
|
137
134
|
return
|
138
135
|
|
@@ -158,19 +155,21 @@ class CaseHandler(object):
|
|
158
155
|
]
|
159
156
|
)
|
160
157
|
case_ids = [case["_id"] for case in cases_with_gene_doc]
|
161
|
-
query
|
158
|
+
self._update_case_id_query(query, case_ids)
|
162
159
|
|
163
|
-
def _set_case_name_query(self, query: Dict[str, Any],
|
160
|
+
def _set_case_name_query(self, query: Dict[str, Any], query_value: str):
|
164
161
|
"""Set case query to reg exp search in case and individual display names for parts of the name query."""
|
165
162
|
|
166
|
-
case_name_regex = {"$regex": re.escape(
|
167
|
-
|
163
|
+
case_name_regex = {"$regex": re.escape(query_value)}
|
164
|
+
or_options = [
|
168
165
|
{"display_name": case_name_regex},
|
169
166
|
{"individuals.display_name": case_name_regex},
|
167
|
+
{"individuals.subject_id": case_name_regex},
|
170
168
|
{"_id": case_name_regex},
|
171
169
|
]
|
170
|
+
self.update_case_query_or_options(query=query, or_options=or_options)
|
172
171
|
|
173
|
-
def _set_case_phenotype_query(self, query: Dict[str, Any],
|
172
|
+
def _set_case_phenotype_query(self, query: Dict[str, Any], query_value: str):
|
174
173
|
"""Set case query based on phenotype terms.
|
175
174
|
|
176
175
|
The user may have provided multiple query (HPO) terms.
|
@@ -178,18 +177,12 @@ class CaseHandler(object):
|
|
178
177
|
If the no query term is given (the phenotype query string is empty), instead query for cases
|
179
178
|
that lack HPO terms.
|
180
179
|
"""
|
181
|
-
if
|
180
|
+
if query_value != "":
|
182
181
|
query["phenotype_terms.phenotype_id"] = {
|
183
|
-
"$in": list(
|
182
|
+
"$in": list(query_value.replace(" ", "").split(","))
|
184
183
|
}
|
185
|
-
return
|
186
184
|
|
187
|
-
|
188
|
-
{"phenotype_terms": {"$size": 0}},
|
189
|
-
{"phenotype_terms": {"$exists": False}},
|
190
|
-
]
|
191
|
-
|
192
|
-
def _set_diagnosis_query(self, query: Dict[str, Any], query_term: str):
|
185
|
+
def _set_diagnosis_query(self, query: Dict[str, Any], query_value: str):
|
193
186
|
"""Set diagnosis query based on query term.
|
194
187
|
The user might have provided multiple query terms.
|
195
188
|
|
@@ -201,92 +194,148 @@ class CaseHandler(object):
|
|
201
194
|
|
202
195
|
The query should be set to check for cases with no HPO terms if the query term is empty.
|
203
196
|
"""
|
204
|
-
if
|
205
|
-
omim_terms = list(
|
206
|
-
|
197
|
+
if query_value != "":
|
198
|
+
omim_terms = list(query_value.replace(" ", "").split(","))
|
199
|
+
|
200
|
+
or_options = [
|
207
201
|
{"diagnosis_phenotypes.disease_id": {"$in": omim_terms}},
|
208
202
|
{"diagnosis_phenotypes": {"$in": omim_terms}},
|
209
203
|
]
|
210
|
-
return
|
211
204
|
|
212
|
-
|
213
|
-
{"diagnosis_phenotypes": {"$size": 0}},
|
214
|
-
{"diagnosis_phenotypes": {"$exists": False}},
|
215
|
-
]
|
205
|
+
self.update_case_query_or_options(query=query, or_options=or_options)
|
216
206
|
|
217
|
-
def _set_synopsis_query(self, query: Dict[str, Any],
|
218
|
-
"""Set query to search in the free text synopsis for
|
207
|
+
def _set_synopsis_query(self, query: Dict[str, Any], query_value: str):
|
208
|
+
"""Set query to search in the free text synopsis for query_value."""
|
219
209
|
|
220
|
-
if
|
221
|
-
query["$text"] = {"$search": re.escape(
|
210
|
+
if query_value != "":
|
211
|
+
query["$text"] = {"$search": re.escape(query_value)}
|
222
212
|
else:
|
223
213
|
query["synopsis"] = ""
|
224
214
|
|
225
|
-
def
|
226
|
-
"""
|
215
|
+
def update_case_query_or_options(self, query: dict, or_options: List[dict]):
|
216
|
+
"""Populates the available options in the query $and field"""
|
217
|
+
if not or_options:
|
218
|
+
return
|
219
|
+
query.setdefault("$or", []).extend(or_options)
|
227
220
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
221
|
+
def populate_case_query(
|
222
|
+
self, query: dict, name_query: Union[str, ImmutableMultiDict], owner=None, collaborator=None
|
223
|
+
):
|
224
|
+
"""Parses and adds query parameters provided by users in cases search filter."""
|
225
|
+
|
226
|
+
def set_case_item_query(query: dict, query_field: str, query_value: str):
|
227
|
+
# Mapping query fields to their corresponding handling functions
|
228
|
+
handlers = {
|
229
|
+
"case": self._set_case_name_query,
|
230
|
+
"exact_pheno": self._set_case_phenotype_query,
|
231
|
+
"exact_dia": self._set_diagnosis_query,
|
232
|
+
"synopsis": self._set_synopsis_query,
|
233
|
+
"panel": set_panel_query,
|
234
|
+
"status": set_status_query,
|
235
|
+
"tags": set_tags_query,
|
236
|
+
"track": set_track_query,
|
237
|
+
"pheno_group": set_pheno_group_query,
|
238
|
+
"cohort": set_cohort_query,
|
239
|
+
"similar_case": set_similar_case_query,
|
240
|
+
"similar_pheno": set_similar_pheno_query,
|
241
|
+
"pinned": set_pinned_gene_query,
|
242
|
+
"causative": set_causative_gene_query,
|
243
|
+
"user": set_user_query,
|
244
|
+
}
|
237
245
|
|
238
|
-
|
239
|
-
|
246
|
+
handler = handlers.get(query_field)
|
247
|
+
if handler:
|
248
|
+
handler(query, query_value)
|
240
249
|
|
241
|
-
|
242
|
-
|
250
|
+
def set_panel_query(query: dict, query_value: str):
|
251
|
+
"""Updates the query with a certain value."""
|
252
|
+
query.update(
|
253
|
+
{"panels": {"$elemMatch": {"panel_name": query_value, "is_default": True}}}
|
254
|
+
)
|
243
255
|
|
244
|
-
|
245
|
-
|
256
|
+
def set_status_query(query: dict, query_value: str):
|
257
|
+
"""Updates the query with a certain value."""
|
258
|
+
query.update({"status": query_value})
|
246
259
|
|
247
|
-
|
248
|
-
|
260
|
+
def set_tags_query(query: dict, query_value: str):
|
261
|
+
"""Updates the query with a certain value."""
|
262
|
+
query.update({"tags": query_value.lower()})
|
249
263
|
|
250
|
-
|
251
|
-
|
264
|
+
def set_track_query(query: dict, query_value: str):
|
265
|
+
"""Updates the query with a certain value."""
|
266
|
+
query.update({"track": query_value})
|
252
267
|
|
253
|
-
|
254
|
-
|
268
|
+
def set_pheno_group_query(query: dict, query_value: str):
|
269
|
+
"""Updates the query with a certain value."""
|
270
|
+
query.update({"phenotype_groups.phenotype_id": query_value})
|
255
271
|
|
256
|
-
|
257
|
-
|
272
|
+
def set_cohort_query(query: dict, query_value: str):
|
273
|
+
"""Updates the query with a certain value."""
|
274
|
+
query.update({"cohorts": query_value})
|
258
275
|
|
259
|
-
|
260
|
-
|
276
|
+
def set_similar_case_query(query: dict, query_value: str):
|
277
|
+
"""Updates the query with a certain value."""
|
278
|
+
self._set_similar_phenotype_query(
|
279
|
+
query, "similar_case", query_value, owner or collaborator
|
280
|
+
)
|
261
281
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
{"phenotype_groups": {"$size": 0}},
|
268
|
-
{"phenotype_groups": {"$exists": False}},
|
269
|
-
]
|
270
|
-
if query_field == "cohort":
|
271
|
-
query["cohorts"] = query_term
|
282
|
+
def set_similar_pheno_query(query: dict, query_value: str):
|
283
|
+
"""Updates the query with a certain value."""
|
284
|
+
self._set_similar_phenotype_query(
|
285
|
+
query, "similar_pheno", query_value, owner or collaborator
|
286
|
+
)
|
272
287
|
|
273
|
-
|
274
|
-
|
275
|
-
|
288
|
+
def set_pinned_gene_query(query: dict, query_value: str):
|
289
|
+
"""Updates the query with a certain value."""
|
290
|
+
self._set_genes_of_interest_query(
|
291
|
+
query=query, query_field="pinned", query_value=query_value
|
276
292
|
)
|
277
293
|
|
278
|
-
|
279
|
-
|
294
|
+
def set_causative_gene_query(query: dict, query_value: str):
|
295
|
+
"""Updates the query with a certain value."""
|
296
|
+
self._set_genes_of_interest_query(
|
297
|
+
query=query, query_field="causative", query_value=query_value
|
298
|
+
)
|
280
299
|
|
281
|
-
|
282
|
-
|
300
|
+
def set_user_query(query: dict, query_value: str):
|
301
|
+
# Handling the 'user' field query separately
|
302
|
+
query_terms = query_value.split(" ")
|
283
303
|
user_query = {
|
284
304
|
"$and": [{"name": {"$regex": term, "$options": "i"}} for term in query_terms]
|
285
305
|
}
|
286
306
|
users = self.user_collection.find(user_query)
|
287
307
|
query["assignees"] = {"$in": [user["_id"] for user in users]}
|
288
308
|
|
289
|
-
|
309
|
+
if isinstance(name_query, str):
|
310
|
+
# Example: status -> Comes from a GET request from dashboard cases
|
311
|
+
query_field, query_value = name_query.split(":", 1)
|
312
|
+
set_case_item_query(
|
313
|
+
query=query, query_field=query_field.strip(), query_value=query_value.strip()
|
314
|
+
)
|
315
|
+
else:
|
316
|
+
# POST request form from more advanced case search from cases page
|
317
|
+
for query_field in [
|
318
|
+
"case",
|
319
|
+
"exact_pheno",
|
320
|
+
"exact_dia",
|
321
|
+
"synopsis",
|
322
|
+
"panel",
|
323
|
+
"status",
|
324
|
+
"tags",
|
325
|
+
"track",
|
326
|
+
"pheno_group",
|
327
|
+
"cohort",
|
328
|
+
"pinned",
|
329
|
+
"causative",
|
330
|
+
"user",
|
331
|
+
"similar_case", # In order to be able to sort results by phenotype similarity, keep this at the bottom
|
332
|
+
"similar_pheno", # In order to be able to sort results by phenotype similarity, keep this at the bottom
|
333
|
+
]:
|
334
|
+
query_value = name_query.get(query_field)
|
335
|
+
if query_value not in ["", None]:
|
336
|
+
set_case_item_query(
|
337
|
+
query=query, query_field=query_field, query_value=query_value.strip()
|
338
|
+
)
|
290
339
|
|
291
340
|
def _update_case_id_query(self, query, id_list):
|
292
341
|
"""Update a case query ["_id"]["$in"] values using an additional list of case _ids
|
@@ -300,6 +349,7 @@ class CaseHandler(object):
|
|
300
349
|
query["_id"]["$in"] = list(
|
301
350
|
set(preselected_ids).intersection(set(id_list))
|
302
351
|
) # limit also by case _ids present in id_list
|
352
|
+
|
303
353
|
else: # use id_list for filtering
|
304
354
|
query["_id"] = {"$in": id_list}
|
305
355
|
|
@@ -380,7 +430,6 @@ class CaseHandler(object):
|
|
380
430
|
query[set_key] = set_value
|
381
431
|
|
382
432
|
query = query or {}
|
383
|
-
order = None
|
384
433
|
# Prioritize when both owner and collaborator params are present
|
385
434
|
if collaborator and owner:
|
386
435
|
collaborator = None
|
@@ -398,14 +447,14 @@ class CaseHandler(object):
|
|
398
447
|
query=query,
|
399
448
|
condition=skip_assigned,
|
400
449
|
set_key="assignees",
|
401
|
-
set_value={
|
450
|
+
set_value={EXISTS: False},
|
402
451
|
)
|
403
452
|
|
404
453
|
_conditional_set_query_value(
|
405
454
|
query=query,
|
406
455
|
condition=has_causatives,
|
407
456
|
set_key="causatives",
|
408
|
-
set_value={
|
457
|
+
set_value={EXISTS: True, "$ne": []},
|
409
458
|
)
|
410
459
|
|
411
460
|
_conditional_set_query_value(
|
@@ -441,28 +490,28 @@ class CaseHandler(object):
|
|
441
490
|
query=query,
|
442
491
|
condition=is_research,
|
443
492
|
set_key="is_research",
|
444
|
-
set_value={
|
493
|
+
set_value={EXISTS: True, "$eq": True},
|
445
494
|
)
|
446
495
|
|
447
496
|
_conditional_set_query_value(
|
448
497
|
query=query,
|
449
498
|
condition=phenotype_terms,
|
450
499
|
set_key="phenotype_terms",
|
451
|
-
set_value={
|
500
|
+
set_value={EXISTS: True, "$ne": []},
|
452
501
|
)
|
453
502
|
|
454
503
|
_conditional_set_query_value(
|
455
504
|
query=query,
|
456
505
|
condition=pinned,
|
457
506
|
set_key="suspects",
|
458
|
-
set_value={
|
507
|
+
set_value={EXISTS: True, "$ne": []},
|
459
508
|
)
|
460
509
|
|
461
510
|
_conditional_set_query_value(
|
462
511
|
query=query,
|
463
512
|
condition=cohort,
|
464
513
|
set_key="cohorts",
|
465
|
-
set_value={
|
514
|
+
set_value={EXISTS: True, "$ne": []},
|
466
515
|
)
|
467
516
|
|
468
517
|
_conditional_set_query_value(
|
@@ -478,7 +527,7 @@ class CaseHandler(object):
|
|
478
527
|
|
479
528
|
if name_query:
|
480
529
|
# Case search filter form query
|
481
|
-
|
530
|
+
self.populate_case_query(query, name_query, owner, collaborator)
|
482
531
|
|
483
532
|
if within_days:
|
484
533
|
query["_id"] = {
|
@@ -507,11 +556,23 @@ class CaseHandler(object):
|
|
507
556
|
if yield_query:
|
508
557
|
return query
|
509
558
|
|
510
|
-
if
|
511
|
-
|
559
|
+
if name_query and self.is_pheno_similarity_query(name_query):
|
560
|
+
result_order: list = query["_id"]["$in"]
|
561
|
+
results = self.case_collection.find(query, projection)
|
562
|
+
# Return the result in order of descending phenotype similarity (the same order or the _ids provided in the query)
|
563
|
+
return sorted(list(results), key=lambda res: result_order.index(res["_id"]))
|
512
564
|
|
513
565
|
return self.case_collection.find(query, projection).sort("updated_at", -1)
|
514
566
|
|
567
|
+
def is_pheno_similarity_query(self, name_query: Union[str, ImmutableMultiDict]) -> bool:
|
568
|
+
"""Return True if the user query contains 'similar_case' or 'similar_pheno' fields."""
|
569
|
+
similar_pheno_keys = ["similar_case", "similar_pheno"]
|
570
|
+
|
571
|
+
if isinstance(name_query, str):
|
572
|
+
return any(key in name_query for key in similar_pheno_keys)
|
573
|
+
|
574
|
+
return any(name_query.get(key) not in [None, ""] for key in similar_pheno_keys)
|
575
|
+
|
515
576
|
def rna_cases(self, owner):
|
516
577
|
"""Retrieve all cases with RNA-seq data for a given institute
|
517
578
|
|
@@ -521,7 +582,7 @@ class CaseHandler(object):
|
|
521
582
|
Returns:
|
522
583
|
list of case _ids
|
523
584
|
"""
|
524
|
-
EXISTS_NOT_NULL = {
|
585
|
+
EXISTS_NOT_NULL = {EXISTS: True, "$nin": [None, ""]}
|
525
586
|
query = {
|
526
587
|
"owner": owner,
|
527
588
|
"$or": [
|
@@ -1001,6 +1062,7 @@ class CaseHandler(object):
|
|
1001
1062
|
- gene_fusion_report_research: path to the research gene fusions report
|
1002
1063
|
- genome_build: If there is a new genome build
|
1003
1064
|
- has_meivariants: If there are new mei variants
|
1065
|
+
- has_outliers: If there are new outlier variants
|
1004
1066
|
- has_strvariants: If there are new strvariants
|
1005
1067
|
- has_svvariants: If there are new svvariants
|
1006
1068
|
- individuals: There could be new individuals
|
@@ -1008,16 +1070,19 @@ class CaseHandler(object):
|
|
1008
1070
|
- madeline_info: If there is a new pedigree
|
1009
1071
|
- mme_submission: If case was submitted to MatchMaker Exchange
|
1010
1072
|
- multiqc: If there's an updated multiqc report location
|
1073
|
+
- omics_files: If there are updated OMICS files
|
1011
1074
|
- panels: The new gene panels are added
|
1012
1075
|
- pipeline_version: path to the pipeline executable version report file
|
1013
1076
|
- rank_model_version: If there is a new rank model
|
1014
1077
|
- reference_info: path to the pipeline reference version report file
|
1015
1078
|
- rerun_requested: Is set to False since that is probably what happened
|
1016
1079
|
- research_requested: Boolean, if research variants where requested for this case
|
1080
|
+
- rna_genome_build: If there is a new RNA genome build ("37" or "38")
|
1017
1081
|
- RNAfusion_inspector: path to the RNA fusion inspector report
|
1018
1082
|
- RNAfusion_inspector_research: path to the research RNA fusion inspector report
|
1019
1083
|
- RNAfusion_report: path to the RNA fusion report
|
1020
1084
|
- RNAfusion_report_research: path to the research RNA fusion report
|
1085
|
+
- rna_delivery_report: path to the RNA delivery report
|
1021
1086
|
- smn_tsv: path to static SMN TSV file
|
1022
1087
|
- status: case status
|
1023
1088
|
- sv_rank_model_version: If there is a new sv rank model
|
@@ -1086,10 +1151,12 @@ class CaseHandler(object):
|
|
1086
1151
|
"rerun_requested": case_obj.get("rerun_requested", False),
|
1087
1152
|
"research_requested": case_obj.get("research_requested", False),
|
1088
1153
|
"reference_info": case_obj.get("reference_info"),
|
1154
|
+
"rna_genome_build": case_obj.get("rna_genome_build"),
|
1089
1155
|
"RNAfusion_inspector": case_obj.get("RNAfusion_inspector"),
|
1090
1156
|
"RNAfusion_inspector_research": case_obj.get("RNAfusion_inspector_research"),
|
1091
1157
|
"RNAfusion_report": case_obj.get("RNAfusion_report"),
|
1092
1158
|
"RNAfusion_report_research": case_obj.get("RNAfusion_report_research"),
|
1159
|
+
"rna_delivery_report": case_obj.get("rna_delivery_report"),
|
1093
1160
|
"smn_tsv": case_obj.get("smn_tsv"),
|
1094
1161
|
"status": case_obj.get("status"),
|
1095
1162
|
"sv_rank_model_version": case_obj.get("sv_rank_model_version"),
|
@@ -1138,6 +1205,7 @@ class CaseHandler(object):
|
|
1138
1205
|
"RNAfusion_inspector_research",
|
1139
1206
|
"RNAfusion_report",
|
1140
1207
|
"RNAfusion_report_research",
|
1208
|
+
"rna_delivery_report",
|
1141
1209
|
"smn_tsv",
|
1142
1210
|
"sv_rank_model_version",
|
1143
1211
|
]:
|
@@ -9,6 +9,25 @@ LOG = logging.getLogger(__name__)
|
|
9
9
|
|
10
10
|
|
11
11
|
class OmicsVariantHandler:
|
12
|
+
|
13
|
+
def delete_omics_variants_by_category(self, case_id: str, variant_type: str, category: str):
|
14
|
+
"""Delete all OMICS variants for a case, given case, variant_type and category."""
|
15
|
+
|
16
|
+
LOG.info(
|
17
|
+
"Deleting old %s %s OMICS variants.",
|
18
|
+
variant_type,
|
19
|
+
category,
|
20
|
+
)
|
21
|
+
|
22
|
+
query = {
|
23
|
+
"case_id": case_id,
|
24
|
+
"variant_type": variant_type,
|
25
|
+
"category": category,
|
26
|
+
}
|
27
|
+
result = self.omics_variant_collection.delete_many(query)
|
28
|
+
|
29
|
+
LOG.info("%s variants deleted", result.deleted_count)
|
30
|
+
|
12
31
|
def delete_omics_variants(self, case_id: str, file_type: str):
|
13
32
|
"""Delete OMICS variants for a case"""
|
14
33
|
omics_file_type = OMICS_FILE_TYPE_MAP.get(file_type)
|
scout/build/case.py
CHANGED
@@ -289,6 +289,7 @@ def build_case(case_data, adapter):
|
|
289
289
|
case_obj["vcf_files"] = case_data.get("vcf_files", {})
|
290
290
|
case_obj["omics_files"] = case_data.get("omics_files", {})
|
291
291
|
case_obj["delivery_report"] = case_data.get("delivery_report")
|
292
|
+
case_obj["rna_delivery_report"] = case_data.get("rna_delivery_report")
|
292
293
|
|
293
294
|
_populate_pipeline_info(case_obj, case_data)
|
294
295
|
|