scout-browser 4.95.0__py3-none-any.whl → 4.97.0__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/adapter/mongo/case.py +75 -70
- scout/adapter/mongo/filter.py +28 -11
- scout/adapter/mongo/institute.py +2 -0
- scout/adapter/mongo/omics_variant.py +20 -5
- scout/adapter/mongo/query.py +104 -95
- scout/adapter/mongo/variant.py +0 -5
- scout/adapter/mongo/variant_loader.py +10 -12
- scout/build/case.py +3 -1
- scout/build/individual.py +3 -11
- scout/commands/delete/delete_command.py +87 -49
- scout/commands/load/research.py +4 -4
- scout/commands/load/variants.py +25 -8
- scout/commands/setup/setup_scout.py +1 -1
- scout/commands/update/case.py +12 -0
- scout/commands/update/individual.py +1 -2
- scout/constants/__init__.py +7 -2
- scout/constants/acmg.py +25 -18
- scout/constants/file_types.py +68 -119
- scout/constants/filters.py +2 -1
- scout/constants/gene_tags.py +3 -3
- scout/constants/igv_tracks.py +7 -11
- scout/constants/query_terms.py +2 -2
- scout/demo/643594.config.yaml +6 -0
- scout/demo/643594.peddy.ped +1 -1
- scout/demo/643594.somalier.ancestry.tsv +4 -0
- scout/demo/643594.somalier.pairs.tsv +4 -0
- scout/demo/643594.somalier.samples.tsv +4 -0
- scout/demo/cancer.load_config.yaml +2 -3
- scout/demo/resources/__init__.py +1 -1
- scout/demo/resources/gnomad.v4.1.constraint_metrics_reduced.tsv +3755 -0
- scout/demo/rnafusion.load_config.yaml +1 -0
- scout/exceptions/database.py +1 -1
- scout/load/all.py +8 -16
- scout/models/case/case.py +1 -0
- scout/models/case/case_loading_models.py +15 -5
- scout/models/managed_variant.py +3 -3
- scout/models/omics_variant.py +3 -3
- scout/parse/case.py +113 -5
- scout/parse/pedqc.py +127 -0
- scout/parse/variant/frequency.py +9 -6
- scout/parse/variant/variant.py +71 -39
- scout/server/app.py +14 -0
- scout/server/blueprints/alignviewers/controllers.py +2 -0
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +3 -0
- scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
- scout/server/blueprints/cases/controllers.py +25 -3
- scout/server/blueprints/cases/templates/cases/case.html +3 -0
- scout/server/blueprints/cases/templates/cases/case_report.html +28 -2
- scout/server/blueprints/cases/templates/cases/chanjo2_form.html +2 -2
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +12 -0
- scout/server/blueprints/cases/templates/cases/gene_panel.html +9 -3
- scout/server/blueprints/cases/templates/cases/individuals_table.html +4 -1
- scout/server/blueprints/cases/templates/cases/utils.html +23 -19
- scout/server/blueprints/cases/views.py +5 -9
- scout/server/blueprints/clinvar/controllers.py +12 -11
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +10 -14
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +15 -7
- scout/server/blueprints/clinvar/views.py +18 -31
- scout/server/blueprints/institutes/controllers.py +20 -1
- scout/server/blueprints/institutes/forms.py +5 -1
- scout/server/blueprints/institutes/templates/overview/institute_settings.html +7 -0
- scout/server/blueprints/institutes/templates/overview/utils.html +20 -1
- scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +9 -2
- scout/server/blueprints/omics_variants/views.py +8 -10
- scout/server/blueprints/variant/controllers.py +30 -1
- scout/server/blueprints/variant/templates/variant/cancer-variant.html +21 -5
- scout/server/blueprints/variant/templates/variant/components.html +26 -9
- scout/server/blueprints/variant/templates/variant/variant.html +4 -2
- scout/server/blueprints/variant/templates/variant/variant_details.html +1 -1
- scout/server/blueprints/variant/utils.py +2 -0
- scout/server/blueprints/variant/views.py +10 -3
- scout/server/blueprints/variants/controllers.py +29 -3
- scout/server/blueprints/variants/forms.py +37 -10
- scout/server/blueprints/variants/templates/variants/cancer-variants.html +5 -4
- scout/server/blueprints/variants/templates/variants/components.html +12 -10
- scout/server/blueprints/variants/templates/variants/str-variants.html +13 -9
- scout/server/blueprints/variants/templates/variants/utils.html +59 -36
- scout/server/blueprints/variants/views.py +45 -60
- scout/server/extensions/beacon_extension.py +1 -1
- scout/server/extensions/bionano_extension.py +5 -5
- scout/server/extensions/chanjo2_extension.py +40 -1
- scout/server/extensions/chanjo_extension.py +1 -1
- scout/server/extensions/clinvar_extension.py +56 -2
- scout/server/extensions/matchmaker_extension.py +1 -1
- scout/server/links.py +0 -14
- scout/server/static/bs_styles.css +2 -0
- scout/server/templates/layout.html +1 -0
- scout/server/utils.py +5 -0
- scout/utils/acmg.py +5 -5
- scout/utils/ensembl_biomart_clients.py +2 -11
- scout/utils/scout_requests.py +1 -1
- {scout_browser-4.95.0.dist-info → scout_browser-4.97.0.dist-info}/METADATA +1 -1
- {scout_browser-4.95.0.dist-info → scout_browser-4.97.0.dist-info}/RECORD +96 -94
- scout/demo/resources/gnomad.v4.0.constraint_metrics_reduced.tsv +0 -3755
- scout/parse/peddy.py +0 -149
- scout/utils/sort.py +0 -21
- {scout_browser-4.95.0.dist-info → scout_browser-4.97.0.dist-info}/WHEEL +0 -0
- {scout_browser-4.95.0.dist-info → scout_browser-4.97.0.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.95.0.dist-info → scout_browser-4.97.0.dist-info}/licenses/LICENSE +0 -0
scout/adapter/mongo/case.py
CHANGED
@@ -3,6 +3,7 @@ import datetime
|
|
3
3
|
import logging
|
4
4
|
import operator
|
5
5
|
import re
|
6
|
+
from collections import OrderedDict
|
6
7
|
from copy import deepcopy
|
7
8
|
from typing import Any, Dict, List, Optional
|
8
9
|
|
@@ -11,11 +12,16 @@ from bson import ObjectId
|
|
11
12
|
from werkzeug.datastructures import ImmutableMultiDict
|
12
13
|
|
13
14
|
from scout.build.case import build_case
|
14
|
-
from scout.constants import
|
15
|
+
from scout.constants import (
|
16
|
+
ACMG_MAP,
|
17
|
+
CCV_MAP,
|
18
|
+
ID_PROJECTION,
|
19
|
+
ORDERED_FILE_TYPE_MAP,
|
20
|
+
ORDERED_OMICS_FILE_TYPE_MAP,
|
21
|
+
)
|
15
22
|
from scout.exceptions import ConfigError, IntegrityError
|
16
23
|
from scout.parse.variant.ids import parse_document_id
|
17
24
|
from scout.utils.algorithms import ui_score
|
18
|
-
from scout.utils.sort import get_load_priority
|
19
25
|
|
20
26
|
LOG = logging.getLogger(__name__)
|
21
27
|
EXISTS = "$exists"
|
@@ -886,11 +892,17 @@ class CaseHandler(object):
|
|
886
892
|
if key in old_case:
|
887
893
|
new_case[key] = old_case[key]
|
888
894
|
|
889
|
-
def
|
895
|
+
def _load_clinical_omics_variants(self, case_obj: dict, build: str, update: bool = False):
|
890
896
|
"""Load omics variants. The OMICS FILE type dict contains all we need to
|
891
897
|
determine how to load variants (type, category etc)."""
|
892
898
|
|
893
|
-
|
899
|
+
CLINICAL_ORDERED_OMICS_FILE_TYPE_MAP = OrderedDict(
|
900
|
+
(key, value)
|
901
|
+
for key, value in ORDERED_OMICS_FILE_TYPE_MAP.items()
|
902
|
+
if value["variant_type"] != "research"
|
903
|
+
)
|
904
|
+
|
905
|
+
for omics_file in CLINICAL_ORDERED_OMICS_FILE_TYPE_MAP.keys():
|
894
906
|
if not case_obj["omics_files"].get(omics_file):
|
895
907
|
LOG.debug("didn't find %s for case, skipping", omics_file)
|
896
908
|
continue
|
@@ -901,6 +913,38 @@ class CaseHandler(object):
|
|
901
913
|
|
902
914
|
self.load_omics_variants(case_obj=case_obj, build=build, file_type=omics_file)
|
903
915
|
|
916
|
+
def _load_clinical_variants(self, case_obj: dict, build: str, update: bool = False):
|
917
|
+
"""Load variants in the order specified by CLINICAL_ORDERED_FILE_TYPE_MAP."""
|
918
|
+
CLINICAL_ORDERED_FILE_TYPE_MAP = OrderedDict(
|
919
|
+
(key, value)
|
920
|
+
for key, value in ORDERED_FILE_TYPE_MAP.items()
|
921
|
+
if value["variant_type"] != "research"
|
922
|
+
)
|
923
|
+
load_type_cat = set()
|
924
|
+
for file_name, vcf_dict in CLINICAL_ORDERED_FILE_TYPE_MAP.items():
|
925
|
+
if not case_obj["vcf_files"].get(file_name):
|
926
|
+
LOG.debug("didn't find {}, skipping".format(file_name))
|
927
|
+
continue
|
928
|
+
load_type_cat.add((vcf_dict["variant_type"], vcf_dict["category"]))
|
929
|
+
|
930
|
+
for variant_type, category in load_type_cat:
|
931
|
+
if update:
|
932
|
+
self.delete_variants(
|
933
|
+
case_id=case_obj["_id"],
|
934
|
+
variant_type=variant_type,
|
935
|
+
category=category,
|
936
|
+
)
|
937
|
+
self.load_variants(
|
938
|
+
case_obj=case_obj,
|
939
|
+
variant_type=variant_type,
|
940
|
+
category=category,
|
941
|
+
build=build,
|
942
|
+
rank_threshold=case_obj.get("rank_score_threshold", 5),
|
943
|
+
custom_images=self._get_variants_custom_images(
|
944
|
+
variant_category=category, case=case_obj
|
945
|
+
),
|
946
|
+
)
|
947
|
+
|
904
948
|
def load_case(self, config_data: dict, update: bool = False, keep_actions: bool = True) -> dict:
|
905
949
|
"""Load a case into the database
|
906
950
|
|
@@ -950,77 +994,36 @@ class CaseHandler(object):
|
|
950
994
|
old_evaluated_variants = list(
|
951
995
|
self.evaluated_variants(case_obj["_id"], case_obj["owner"])
|
952
996
|
)
|
953
|
-
|
954
|
-
# load from files
|
955
|
-
files = [
|
956
|
-
{
|
957
|
-
"file_name": file_type,
|
958
|
-
"variant_type": FILE_TYPE_MAP[file_type]["variant_type"],
|
959
|
-
"category": FILE_TYPE_MAP[file_type]["category"],
|
960
|
-
}
|
961
|
-
for file_type in FILE_TYPE_MAP.keys()
|
962
|
-
if FILE_TYPE_MAP[file_type]["variant_type"] != "research"
|
963
|
-
]
|
964
|
-
|
965
|
-
# (type, category) tuples are not unique - eg SNV, SNV_MT
|
966
|
-
load_variants = set()
|
967
997
|
try:
|
968
|
-
|
969
|
-
|
970
|
-
if not case_obj["vcf_files"].get(vcf_file["file_name"]):
|
971
|
-
LOG.debug("didn't find {}, skipping".format(vcf_file["file_name"]))
|
972
|
-
continue
|
973
|
-
load_variants.add((vcf_file["variant_type"], vcf_file["category"]))
|
974
|
-
|
975
|
-
for variant_type, category in sorted(
|
976
|
-
load_variants,
|
977
|
-
key=lambda tup: get_load_priority(variant_type=tup[0], category=tup[1]),
|
978
|
-
):
|
979
|
-
if update:
|
980
|
-
self.delete_variants(
|
981
|
-
case_id=case_obj["_id"],
|
982
|
-
variant_type=variant_type,
|
983
|
-
category=category,
|
984
|
-
)
|
985
|
-
# add variants
|
986
|
-
self.load_variants(
|
987
|
-
case_obj=case_obj,
|
988
|
-
variant_type=variant_type,
|
989
|
-
category=category,
|
990
|
-
build=genome_build,
|
991
|
-
rank_threshold=case_obj.get("rank_score_threshold", 5),
|
992
|
-
custom_images=self._get_variants_custom_images(
|
993
|
-
variant_category=category, case=case_obj
|
994
|
-
),
|
995
|
-
)
|
998
|
+
self._load_clinical_variants(case_obj, build=genome_build, update=update)
|
999
|
+
self._load_clinical_omics_variants(case_obj, build=genome_build, update=update)
|
996
1000
|
|
997
1001
|
except (IntegrityError, ValueError, ConfigError, KeyError) as error:
|
998
|
-
LOG.
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
if
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
self.update_case_sanger_variants(institute_obj, case_obj, old_sanger_variants)
|
1002
|
+
LOG.exception(error)
|
1003
|
+
raise error
|
1004
|
+
else:
|
1005
|
+
if not existing_case:
|
1006
|
+
LOG.info("Loading case %s into database", case_obj["display_name"])
|
1007
|
+
self.add_case(case_obj, institute_obj)
|
1008
|
+
finally:
|
1009
|
+
if existing_case:
|
1010
|
+
self.update_case_data_sharing(old_case=existing_case, new_case=case_obj)
|
1011
|
+
case_obj["rerun_requested"] = False
|
1012
|
+
if case_obj["status"] in ["active", "archived"]:
|
1013
|
+
case_obj["status"] = "inactive"
|
1014
|
+
|
1015
|
+
case_obj["variants_stats"] = self.case_variants_count(
|
1016
|
+
case_id=case_obj["_id"],
|
1017
|
+
institute_id=institute_obj["_id"],
|
1018
|
+
force_update_case=True,
|
1019
|
+
)
|
1017
1020
|
|
1018
|
-
|
1019
|
-
|
1021
|
+
self.update_case_cli(case_obj, institute_obj)
|
1022
|
+
# update Sanger status for the new inserted variants
|
1023
|
+
self.update_case_sanger_variants(institute_obj, case_obj, old_sanger_variants)
|
1020
1024
|
|
1021
|
-
|
1022
|
-
|
1023
|
-
self.add_case(case_obj, institute_obj)
|
1025
|
+
if keep_actions and old_evaluated_variants:
|
1026
|
+
self.update_variant_actions(institute_obj, case_obj, old_evaluated_variants)
|
1024
1027
|
|
1025
1028
|
return case_obj
|
1026
1029
|
|
@@ -1087,6 +1090,7 @@ class CaseHandler(object):
|
|
1087
1090
|
Returns:
|
1088
1091
|
updated_case(dict): The updated case information
|
1089
1092
|
"""
|
1093
|
+
|
1090
1094
|
LOG.info("Updating case {0}".format(case_obj["_id"]))
|
1091
1095
|
old_case = self.case_collection.find_one({"_id": case_obj["_id"]})
|
1092
1096
|
|
@@ -1146,6 +1150,7 @@ class CaseHandler(object):
|
|
1146
1150
|
"RNAfusion_report": case_obj.get("RNAfusion_report"),
|
1147
1151
|
"RNAfusion_report_research": case_obj.get("RNAfusion_report_research"),
|
1148
1152
|
"rna_delivery_report": case_obj.get("rna_delivery_report"),
|
1153
|
+
"scout_load_version": case_obj.get("scout_load_version"),
|
1149
1154
|
"smn_tsv": case_obj.get("smn_tsv"),
|
1150
1155
|
"status": case_obj.get("status"),
|
1151
1156
|
"sv_rank_model_version": case_obj.get("sv_rank_model_version"),
|
scout/adapter/mongo/filter.py
CHANGED
@@ -24,10 +24,10 @@ class FilterHandler(object):
|
|
24
24
|
Returns:
|
25
25
|
filter_obj(dict)
|
26
26
|
"""
|
27
|
-
filter_obj = None
|
28
|
-
LOG.debug("Retrieve filter {}".format(filter_id))
|
29
27
|
filter_obj = self.filter_collection.find_one({"_id": ObjectId(filter_id)})
|
28
|
+
|
30
29
|
if filter_obj is not None:
|
30
|
+
self.set_legacy_options(filter_obj)
|
31
31
|
# use _id to preselect the currently loaded filter, and drop it while we are at it
|
32
32
|
filter_obj.update([("filters", filter_obj.pop("_id", None))])
|
33
33
|
return filter_obj
|
@@ -49,15 +49,6 @@ class FilterHandler(object):
|
|
49
49
|
Returns:
|
50
50
|
filter_id(str) - a unique id that can be cast to ObjectId
|
51
51
|
"""
|
52
|
-
|
53
|
-
LOG.info(
|
54
|
-
"Stashing filter for user '%s' and institute %s.",
|
55
|
-
user_obj.get("email"),
|
56
|
-
institute_obj.get("display_name"),
|
57
|
-
)
|
58
|
-
|
59
|
-
LOG.info("Filter object {}".format(filter_obj))
|
60
|
-
|
61
52
|
institute_id = institute_obj.get("_id")
|
62
53
|
filter_dict = {"institute_id": institute_id, "category": category}
|
63
54
|
|
@@ -271,3 +262,29 @@ class FilterHandler(object):
|
|
271
262
|
)
|
272
263
|
|
273
264
|
return filters_res
|
265
|
+
|
266
|
+
def set_legacy_options(self, filter_obj):
|
267
|
+
"""Update remaining legacy filter options,
|
268
|
+
i.e. filter controls that changed names or functionality.
|
269
|
+
In particular, clinsig_confident_always_returned was split into two different
|
270
|
+
options: clinvar_trusted_revstat and prioritise_clinvar.
|
271
|
+
"""
|
272
|
+
if "clinsig_confident_always_returned" not in filter_obj:
|
273
|
+
return
|
274
|
+
|
275
|
+
filter_value = filter_obj.pop("clinsig_confident_always_returned", ["True"])
|
276
|
+
filter_obj["clinvar_trusted_revstat"] = filter_value
|
277
|
+
filter_obj["prioritise_clinvar"] = filter_value
|
278
|
+
|
279
|
+
self.filter_collection.find_one_and_update(
|
280
|
+
{"_id": filter_obj["_id"]},
|
281
|
+
{
|
282
|
+
"$set": {
|
283
|
+
"clinvar_trusted_revstat": filter_value,
|
284
|
+
"prioritise_clinvar": filter_value,
|
285
|
+
},
|
286
|
+
"$unset": {
|
287
|
+
"clinsig_confident_always_returned": "",
|
288
|
+
},
|
289
|
+
},
|
290
|
+
)
|
scout/adapter/mongo/institute.py
CHANGED
@@ -56,6 +56,7 @@ class InstituteHandler(object):
|
|
56
56
|
check_show_all_vars: Optional[str] = None,
|
57
57
|
clinvar_key: Optional[str] = None,
|
58
58
|
clinvar_submitters: Optional[List[str]] = None,
|
59
|
+
soft_filters: Optional[dict] = None,
|
59
60
|
) -> Union[dict, str]:
|
60
61
|
"""Update the information for an institute."""
|
61
62
|
|
@@ -127,6 +128,7 @@ class InstituteHandler(object):
|
|
127
128
|
"alamut_institution": alamut_institution,
|
128
129
|
"clinvar_key": clinvar_key,
|
129
130
|
"show_all_cases_status": show_all_cases_status,
|
131
|
+
"soft_filters": soft_filters,
|
130
132
|
}
|
131
133
|
for key, value in ADMIN_SETTINGS.items():
|
132
134
|
if value not in [None, "", []]:
|
@@ -1,11 +1,14 @@
|
|
1
1
|
import logging
|
2
2
|
from typing import Dict, Optional
|
3
3
|
|
4
|
-
from
|
4
|
+
from pymongo import ASCENDING, DESCENDING
|
5
|
+
|
6
|
+
from scout.constants import ORDERED_OMICS_FILE_TYPE_MAP
|
5
7
|
from scout.models.omics_variant import OmicsVariantLoader
|
6
8
|
from scout.parse.omics_variant import parse_omics_file
|
7
9
|
|
8
10
|
LOG = logging.getLogger(__name__)
|
11
|
+
SORT_ORDER = {"asc": ASCENDING, "desc": DESCENDING}
|
9
12
|
|
10
13
|
|
11
14
|
class OmicsVariantHandler:
|
@@ -30,7 +33,7 @@ class OmicsVariantHandler:
|
|
30
33
|
|
31
34
|
def delete_omics_variants(self, case_id: str, file_type: str):
|
32
35
|
"""Delete OMICS variants for a case"""
|
33
|
-
omics_file_type =
|
36
|
+
omics_file_type = ORDERED_OMICS_FILE_TYPE_MAP.get(file_type)
|
34
37
|
category = omics_file_type["category"]
|
35
38
|
sub_category = omics_file_type["sub_category"]
|
36
39
|
variant_type = omics_file_type["variant_type"]
|
@@ -123,7 +126,7 @@ class OmicsVariantHandler:
|
|
123
126
|
case_panels = case_obj.get("panels", [])
|
124
127
|
gene_to_panels = self.gene_to_panels(case_obj)
|
125
128
|
|
126
|
-
omics_file_type: dict =
|
129
|
+
omics_file_type: dict = ORDERED_OMICS_FILE_TYPE_MAP.get(file_type)
|
127
130
|
|
128
131
|
nr_inserted = 0
|
129
132
|
|
@@ -180,9 +183,21 @@ class OmicsVariantHandler:
|
|
180
183
|
else:
|
181
184
|
nr_of_variants = skip + nr_of_variants
|
182
185
|
|
183
|
-
|
186
|
+
variants_query = self.build_query(case_id, query=query, category=category, build=build)
|
187
|
+
|
188
|
+
if query.get("sort_by") and query.get("sort_order"):
|
189
|
+
return (
|
190
|
+
self.omics_variant_collection.find(variants_query, projection)
|
191
|
+
.sort([(query.get("sort_by"), SORT_ORDER[query.get("sort_order")])])
|
192
|
+
.skip(skip)
|
193
|
+
.limit(nr_of_variants)
|
194
|
+
)
|
195
|
+
|
184
196
|
return self.omics_variant_collection.find(
|
185
|
-
|
197
|
+
variants_query,
|
198
|
+
projection,
|
199
|
+
skip=skip,
|
200
|
+
limit=nr_of_variants,
|
186
201
|
)
|
187
202
|
|
188
203
|
def count_omics_variants(
|