scout-browser 4.88.1__py3-none-any.whl → 4.89.1__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.
Files changed (59) hide show
  1. scout/__version__.py +1 -1
  2. scout/adapter/mongo/base.py +1 -1
  3. scout/adapter/mongo/case.py +185 -117
  4. scout/adapter/mongo/omics_variant.py +19 -0
  5. scout/build/case.py +1 -0
  6. scout/commands/load/variants.py +121 -40
  7. scout/commands/update/case.py +56 -10
  8. scout/constants/case_tags.py +5 -0
  9. scout/constants/disease_parsing.py +2 -2
  10. scout/constants/igv_tracks.py +2 -2
  11. scout/constants/indexes.py +8 -1
  12. scout/demo/643594.config.yaml +1 -0
  13. scout/demo/panel_1.txt +2 -0
  14. scout/demo/resources/ensembl_exons_37_reduced.txt +135 -0
  15. scout/demo/resources/ensembl_exons_38_reduced.txt +166 -0
  16. scout/demo/resources/ensembl_genes_37_reduced.txt +2 -0
  17. scout/demo/resources/ensembl_genes_38_reduced.txt +2 -0
  18. scout/demo/resources/ensembl_transcripts_37_reduced.txt +27 -0
  19. scout/demo/resources/ensembl_transcripts_38_reduced.txt +36 -0
  20. scout/demo/resources/hgnc_reduced_set.txt +2 -0
  21. scout/log/handlers.py +2 -1
  22. scout/log/log.py +48 -61
  23. scout/models/case/case_loading_models.py +2 -0
  24. scout/parse/omim.py +2 -2
  25. scout/server/app.py +23 -7
  26. scout/server/blueprints/alignviewers/controllers.py +46 -23
  27. scout/server/blueprints/cases/controllers.py +21 -47
  28. scout/server/blueprints/cases/templates/cases/case_report.html +9 -4
  29. scout/server/blueprints/cases/templates/cases/case_sma.html +19 -0
  30. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +7 -7
  31. scout/server/blueprints/cases/templates/cases/individuals_table.html +1 -1
  32. scout/server/blueprints/clinvar/form.py +1 -1
  33. scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +2 -2
  34. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +9 -3
  35. scout/server/blueprints/institutes/controllers.py +11 -38
  36. scout/server/blueprints/institutes/forms.py +18 -4
  37. scout/server/blueprints/institutes/templates/overview/cases.html +137 -46
  38. scout/server/blueprints/login/views.py +16 -12
  39. scout/server/blueprints/panels/controllers.py +4 -1
  40. scout/server/blueprints/panels/templates/panels/panel.html +1 -1
  41. scout/server/blueprints/panels/templates/panels/panels.html +5 -5
  42. scout/server/blueprints/public/templates/public/index.html +18 -10
  43. scout/server/blueprints/variant/templates/variant/components.html +0 -1
  44. scout/server/blueprints/variant/templates/variant/gene_disease_relations.html +1 -1
  45. scout/server/config.py +3 -0
  46. scout/server/extensions/__init__.py +2 -0
  47. scout/server/extensions/chanjo2_extension.py +46 -0
  48. scout/server/extensions/chanjo_extension.py +44 -1
  49. scout/server/extensions/matchmaker_extension.py +0 -1
  50. scout/server/links.py +11 -2
  51. scout/server/templates/report_base.html +59 -0
  52. scout/utils/convert.py +1 -1
  53. scout/utils/date.py +1 -1
  54. {scout_browser-4.88.1.dist-info → scout_browser-4.89.1.dist-info}/METADATA +1 -1
  55. {scout_browser-4.88.1.dist-info → scout_browser-4.89.1.dist-info}/RECORD +59 -58
  56. {scout_browser-4.88.1.dist-info → scout_browser-4.89.1.dist-info}/LICENSE +0 -0
  57. {scout_browser-4.88.1.dist-info → scout_browser-4.89.1.dist-info}/WHEEL +0 -0
  58. {scout_browser-4.88.1.dist-info → scout_browser-4.89.1.dist-info}/entry_points.txt +0 -0
  59. {scout_browser-4.88.1.dist-info → scout_browser-4.89.1.dist-info}/top_level.txt +0 -0
scout/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "4.88.1"
1
+ __version__ = "4.89.1"
@@ -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.debug(f"Database name: {dbname}")
93
+ LOG.info(f"Database name: {dbname}")
94
94
  self.setup(app.config["MONGO_DATABASE"])
95
95
 
96
96
  def setup(self, database):
@@ -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 None
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
- query_term: str,
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
- case_obj = self.case(
93
- display_name=query_term,
94
- institute_id=institute_id,
95
- projection=CASE_SIMILAR_PROJECTION,
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(query_term.replace(" ", "").split(","))
105
+ hpo_terms = list(query_value.replace(" ", "").split(","))
106
106
  similar_cases = self.cases_by_phenotype(hpo_terms, institute_id, None)
107
107
 
108
- if len(similar_cases) == 0: # No cases similar to given phenotype
109
- query["_id"] = {"$in": []} # No result should be returned by query
110
- return
111
-
112
- similar_case_ids = []
113
- order = []
114
- for i in similar_cases:
115
- similar_case_ids.append(i[0])
116
- order.append(i[1])
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, query_term: 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
- query_term(str) example:"POT1"
128
+ query_value(str) example:"POT1"
132
129
  """
133
- hgnc_id = self.hgnc_id(hgnc_symbol=query_term)
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 {query_term} found.")
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["_id"] = {"$in": case_ids}
158
+ self._update_case_id_query(query, case_ids)
162
159
 
163
- def _set_case_name_query(self, query: Dict[str, Any], query_term: str):
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(query_term)}
167
- query["$or"] = [
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], query_term: str):
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 query_term != "":
180
+ if query_value != "":
182
181
  query["phenotype_terms.phenotype_id"] = {
183
- "$in": list(query_term.replace(" ", "").split(","))
182
+ "$in": list(query_value.replace(" ", "").split(","))
184
183
  }
185
- return
186
184
 
187
- query["$or"] = [
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 query_term != "":
205
- omim_terms = list(query_term.replace(" ", "").split(","))
206
- query["$or"] = [
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
- query["$or"] = [
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], query_term: str):
218
- """Set query to search in the free text synopsis for query_term."""
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 query_term != "":
221
- query["$text"] = {"$search": re.escape(query_term)}
210
+ if query_value != "":
211
+ query["$text"] = {"$search": re.escape(query_value)}
222
212
  else:
223
213
  query["synopsis"] = ""
224
214
 
225
- def _populate_name_query(self, query, name_query, owner=None, collaborator=None):
226
- """Parses and adds query parameters provided by users in cases search filter.
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
- Args:
229
- query(dict): cases search query
230
- name_query(dict): args provided by users in cases filter search
231
- owner(dict): an institute id
232
- collaborator(dict): an institute id
233
- """
234
- order = None
235
- query_field = name_query.split(":")[0] # example:status
236
- query_term = name_query[name_query.index(":") + 1 :].strip()
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
- if query_field == "case" and query_term != "":
239
- self._set_case_name_query(query, query_term)
246
+ handler = handlers.get(query_field)
247
+ if handler:
248
+ handler(query, query_value)
240
249
 
241
- if query_field == "exact_pheno":
242
- self._set_case_phenotype_query(query, query_term)
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
- if query_field == "exact_dia":
245
- self._set_diagnosis_query(query, query_term)
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
- if query_field == "synopsis":
248
- self._set_synopsis_query(query, query_term)
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
- if query_field == "panel":
251
- query["panels"] = {"$elemMatch": {"panel_name": query_term, "is_default": True}}
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
- if query_field == "status":
254
- query["status"] = query_term
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
- if query_field == "tags":
257
- query["tags"] = query_term.lower()
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
- if query_field == "track":
260
- query["track"] = query_term
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
- if query_field == "pheno_group":
263
- if query_term != "":
264
- query["phenotype_groups.phenotype_id"] = query_term
265
- else:
266
- query["$or"] = [
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
- if query_term != "" and query_field in ["similar_case", "similar_pheno"]:
274
- order = self._set_similar_phenotype_query(
275
- query, query_field, query_term, owner or collaborator
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
- if query_term != "" and query_field in ["pinned", "causative"]:
279
- self._set_genes_of_interest_query(query, query_field, query_term)
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
- if query_field == "user":
282
- query_terms = query_term.split(" ")
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
- return order
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={"$exists": False},
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={"$exists": True, "$ne": []},
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={"$exists": True, "$eq": True},
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={"$exists": True, "$ne": []},
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={"$exists": True, "$ne": []},
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={"$exists": True, "$ne": []},
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
- order = self._populate_name_query(query, name_query, owner, collaborator)
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 order:
511
- return self.case_collection.find(query, projection)
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 = {"$exists": True, "$nin": [None, ""]}
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