scout-browser 4.91.1__py3-none-any.whl → 4.92__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 (29) hide show
  1. scout/__version__.py +1 -1
  2. scout/adapter/mongo/panel.py +1 -1
  3. scout/adapter/mongo/query.py +13 -16
  4. scout/build/variant/clnsig.py +6 -8
  5. scout/commands/delete/delete_command.py +27 -4
  6. scout/constants/clnsig.py +2 -0
  7. scout/constants/indexes.py +11 -0
  8. scout/parse/panelapp.py +3 -1
  9. scout/parse/variant/callers.py +103 -26
  10. scout/parse/variant/clnsig.py +13 -0
  11. scout/parse/variant/genotype.py +1 -1
  12. scout/parse/variant/variant.py +2 -0
  13. scout/server/blueprints/genes/templates/genes/gene.html +6 -0
  14. scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +4 -4
  15. scout/server/blueprints/panels/templates/panels/panels.html +5 -5
  16. scout/server/blueprints/variant/controllers.py +6 -2
  17. scout/server/blueprints/variant/templates/variant/components.html +1 -1
  18. scout/server/blueprints/variant/templates/variant/variant_details.html +8 -1
  19. scout/server/blueprints/variant/utils.py +38 -6
  20. scout/server/blueprints/variants/controllers.py +5 -9
  21. scout/server/blueprints/variants/templates/variants/cancer-variants.html +2 -2
  22. scout/server/blueprints/variants/templates/variants/utils.html +1 -1
  23. scout/server/extensions/panelapp_extension.py +2 -2
  24. {scout_browser-4.91.1.dist-info → scout_browser-4.92.dist-info}/METADATA +1 -1
  25. {scout_browser-4.91.1.dist-info → scout_browser-4.92.dist-info}/RECORD +29 -29
  26. {scout_browser-4.91.1.dist-info → scout_browser-4.92.dist-info}/WHEEL +1 -1
  27. {scout_browser-4.91.1.dist-info → scout_browser-4.92.dist-info}/LICENSE +0 -0
  28. {scout_browser-4.91.1.dist-info → scout_browser-4.92.dist-info}/entry_points.txt +0 -0
  29. {scout_browser-4.91.1.dist-info → scout_browser-4.92.dist-info}/top_level.txt +0 -0
scout/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "4.91.1"
1
+ __version__ = "4.92"
@@ -501,7 +501,7 @@ class PanelHandler:
501
501
  new_panel["version"] = float(version)
502
502
 
503
503
  # Update same version or create new version
504
- if version == panel_obj["version"]:
504
+ if new_panel["version"] == panel_obj["version"]:
505
505
  result = self.panel_collection.find_one_and_replace(
506
506
  {"_id": panel_obj["_id"]}, new_panel, return_document=pymongo.ReturnDocument.AFTER
507
507
  )
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import re
3
3
  from datetime import datetime, timedelta
4
- from typing import Optional, Union
4
+ from typing import List, Optional, Union
5
5
 
6
6
  from scout.constants import (
7
7
  CLINSIG_MAP,
@@ -19,23 +19,19 @@ LOG = logging.getLogger(__name__)
19
19
 
20
20
  class QueryHandler(object):
21
21
  def build_case_query(
22
- self, case_id=None, status=None, older_than=None, analysis_type=[]
22
+ self,
23
+ case_ids: Optional[List[str]],
24
+ institute_id: Optional[List[str]],
25
+ status: Optional[List[str]],
26
+ older_than: Optional[int],
27
+ analysis_type: Optional[List[str]],
23
28
  ) -> dict:
24
- """Build case query based on case id, status and analysis date
25
-
26
- Args:
27
- case_id(str): id of a case
28
- status(list): one or more case status
29
- older_than(int): to select cases older than a number of months
30
- case_ids(list): a list of case _ids
31
- analysis_type(list): a list of type of analysis ["wgs", "wes", "panel"]
32
-
33
- Returns:
34
- case_query(dict): query dictionary
35
- """
29
+ """Build case query based on case id, status and analysis date."""
36
30
  case_query = {}
37
- if case_id:
38
- case_query["_id"] = case_id
31
+ if case_ids:
32
+ case_query["_id"] = {"$in": case_ids}
33
+ if institute_id:
34
+ case_query["owner"] = institute_id
39
35
  if analysis_type:
40
36
  case_query["individuals.analysis_type"] = {"$in": analysis_type}
41
37
  if older_than:
@@ -43,6 +39,7 @@ class QueryHandler(object):
43
39
  case_query["analysis_date"] = {"$lt": older_than_date}
44
40
  if status:
45
41
  case_query["status"] = {"$in": list(status)}
42
+
46
43
  return case_query
47
44
 
48
45
  def delete_variants_query(
@@ -1,18 +1,13 @@
1
1
  import logging
2
+
2
3
  from scout.constants import REV_CLINSIG_MAP
3
4
 
4
5
  LOG = logging.getLogger(__name__)
5
6
 
6
7
 
7
- def build_clnsig(clnsig_info):
8
- """Prepare clnsig information for database
9
-
10
- Args:
11
- clnsig_info(dict): Parsed information from clinvar annotation
8
+ def build_clnsig(clnsig_info: dict) -> dict:
9
+ """Prepare clnsig information for database."""
12
10
 
13
- Returns:
14
- clnsig_obj(dict): Converted and prepared for database
15
- """
16
11
  value = clnsig_info["value"]
17
12
  if value not in REV_CLINSIG_MAP:
18
13
  LOG.warning("Clinsig value %s does not have an internal representation", value)
@@ -24,4 +19,7 @@ def build_clnsig(clnsig_info):
24
19
  revstat=clnsig_info.get("revstat"),
25
20
  )
26
21
 
22
+ if isinstance(value, str) and "low_penetrance" in value:
23
+ clnsig_obj["low_penetrance"] = True
24
+
27
25
  return clnsig_obj
@@ -29,7 +29,14 @@ VARIANT_CATEGORIES = ["mei", "snv", "sv", "cancer", "cancer_sv", "str"]
29
29
 
30
30
  @click.command("variants", short_help="Delete variants for one or more cases")
31
31
  @click.option("-u", "--user", help="User running this command (email)", required=True)
32
- @click.option("-c", "--case-id", help="Case id")
32
+ @click.option("-c", "--case-id", help="Case id", multiple=True)
33
+ @click.option(
34
+ "-f",
35
+ "--case-file",
36
+ help="Path to file containing list of case IDs",
37
+ type=click.Path(exists=True),
38
+ )
39
+ @click.option("-i", "--institute", help="Restrict to cases with specified institute ID")
33
40
  @click.option(
34
41
  "--status",
35
42
  type=click.Choice(CASE_STATUSES),
@@ -42,7 +49,6 @@ VARIANT_CATEGORIES = ["mei", "snv", "sv", "cancer", "cancer_sv", "str"]
42
49
  "--analysis-type",
43
50
  type=click.Choice(["wgs", "wes", "panel"]),
44
51
  multiple=True,
45
- default=["wgs"],
46
52
  help="Type of analysis",
47
53
  )
48
54
  @click.option("--rank-threshold", type=click.INT, default=5, help="With rank threshold lower than")
@@ -62,7 +68,9 @@ VARIANT_CATEGORIES = ["mei", "snv", "sv", "cancer", "cancer_sv", "str"]
62
68
  @with_appcontext
63
69
  def variants(
64
70
  user: str,
65
- case_id: str,
71
+ case_id: list,
72
+ case_file: str,
73
+ institute: str,
66
74
  status: list,
67
75
  older_than: int,
68
76
  analysis_type: list,
@@ -73,6 +81,12 @@ def variants(
73
81
  ) -> None:
74
82
  """Delete variants for one or more cases"""
75
83
 
84
+ if case_file and case_id:
85
+ click.echo(
86
+ "You should specify either case ID (multiple times if needed) or the path to a text file containing a list of case IDs (one per line)."
87
+ )
88
+ return
89
+
76
90
  user_obj = store.user(user)
77
91
  if user_obj is None:
78
92
  click.echo(f"Could not find a user with email '{user}' in database")
@@ -86,7 +100,16 @@ def variants(
86
100
  else:
87
101
  click.confirm("Variants are going to be deleted from database. Continue?", abort=True)
88
102
 
89
- case_query = store.build_case_query(case_id, status, older_than, analysis_type)
103
+ if case_file:
104
+ case_id = [line.strip() for line in open(case_file).readlines() if line.strip()]
105
+
106
+ case_query = store.build_case_query(
107
+ case_ids=case_id,
108
+ institute_id=institute,
109
+ status=status,
110
+ older_than=older_than,
111
+ analysis_type=analysis_type,
112
+ )
90
113
  # Estimate the average size of a variant document in database
91
114
  avg_var_size = store.collection_stats("variant").get("avgObjSize", 0) # in bytes
92
115
 
scout/constants/clnsig.py CHANGED
@@ -33,7 +33,9 @@ REV_CLINSIG_MAP = {
33
33
  "conflicting_classifications_of_pathogenicity": 8,
34
34
  "uncertain_significance": 0,
35
35
  "likely_pathogenic": 4,
36
+ "likely_pathogenic,low_penetrance": 4,
36
37
  "pathogenic": 5,
38
+ "pathogenic,low_penetrance": 5,
37
39
  # These are here so that the parsing function will work with the older clinvar format
38
40
  # Where significance where annotated with numbers
39
41
  0: 0,
@@ -8,6 +8,17 @@ INDEXES = {
8
8
  name="genes",
9
9
  )
10
10
  ],
11
+ "gene_panel": [
12
+ IndexModel(
13
+ [("panel_name", ASCENDING), ("version", ASCENDING)],
14
+ name="panel_name_version",
15
+ unique=True,
16
+ ),
17
+ IndexModel(
18
+ [("genes.hgnc_id", ASCENDING)],
19
+ name="genes.hgnc_id",
20
+ ),
21
+ ],
11
22
  "hgnc_gene": [
12
23
  IndexModel(
13
24
  [("build", ASCENDING), ("chromosome", ASCENDING)],
scout/parse/panelapp.py CHANGED
@@ -1,12 +1,13 @@
1
1
  """Code to parse panel information"""
2
2
 
3
3
  import logging
4
- from typing import Dict, List, Optional
4
+ from typing import Dict, Optional
5
5
 
6
6
  from scout.constants import INCOMPLETE_PENETRANCE_MAP, MODELS_MAP, PANELAPP_CONFIDENCE_EXCLUDE
7
7
  from scout.utils.date import get_date
8
8
 
9
9
  LOG = logging.getLogger(__name__)
10
+ PANELAPP_PANELS_URL = "https://panelapp.genomicsengland.co.uk/panels/"
10
11
 
11
12
 
12
13
  def parse_panel_app_gene(
@@ -90,6 +91,7 @@ def parse_panelapp_panel(
90
91
  gene_panel["display_name"] = " - ".join([panel_info["name"], f"[{confidence.upper()}]"])
91
92
  gene_panel["institute"] = institute
92
93
  gene_panel["panel_type"] = ("clinical",)
94
+ gene_panel["description"] = f"{PANELAPP_PANELS_URL}{panel_id}"
93
95
 
94
96
  LOG.info("Parsing panel %s", gene_panel["display_name"])
95
97
 
@@ -1,11 +1,17 @@
1
1
  import logging
2
+ from typing import Optional
3
+
4
+ import cyvcf2
2
5
 
3
6
  from scout.constants import CALLERS
4
7
 
5
8
  LOG = logging.getLogger(__name__)
6
9
 
10
+ PASS_STATUS = "Pass"
11
+ FILTERED_STATUS = "Filtered"
12
+
7
13
 
8
- def parse_callers(variant, category="snv"):
14
+ def parse_callers(variant: cyvcf2.Variant, category: str = "snv") -> dict:
9
15
  """Parse how the different variant callers have performed
10
16
 
11
17
  Caller information can be passed in one of three ways, in order of priority:
@@ -13,6 +19,10 @@ def parse_callers(variant, category="snv"):
13
19
  2. If a svdb_origin tag (pipe separated) is found, callers listed will be marked Pass
14
20
  3. If a set tag (dash separated, GATK CombineVariants) is found, callers will be marked Pass or Filtered accordingly
15
21
 
22
+ If the FILTER status is not PASS (e.g. None - cyvcf2 FILTER is None if VCF file column FILTER is "PASS"),
23
+ in all of these cases, if a single caller is found, the caller status is set to the filter status.
24
+ If there is more than one caller, we can't quite tell which one is which, so all caller statuses will be "Filtered" instead.
25
+
16
26
  Args:
17
27
  variant (cyvcf2.Variant): A variant object
18
28
 
@@ -20,47 +30,114 @@ def parse_callers(variant, category="snv"):
20
30
  callers (dict): A dictionary on the format
21
31
  {'gatk': <filter>,'freebayes': <filter>,'samtools': <filter>}
22
32
  """
33
+ FILTERED = "Filtered - {}"
34
+
23
35
  relevant_callers = CALLERS[category]
24
36
  callers = {caller["id"]: None for caller in relevant_callers}
25
37
  callers_keys = set(callers.keys())
26
38
 
27
- other_info = variant.INFO.get("FOUND_IN")
28
- svdb_origin = variant.INFO.get("svdb_origin")
29
- raw_info = variant.INFO.get("set")
39
+ def get_callers_from_found_in(info_found_in: str, filter_status: Optional[str]) -> dict:
40
+ """If a FOUND_IN tag (comma separated) is found, callers listed will be marked Pass.
41
+ In case of a FILTER status, also set the caller status for a single caller to 'Filtered - status'.
42
+ If more than one caller, and FILTER status, we cant really tell which said what, and all will be
43
+ "Filtered".
44
+ """
45
+ found_ins: list = info_found_in.split(",")
46
+
47
+ call_status = PASS_STATUS
48
+ if filter_status is not None:
49
+ call_status = (
50
+ FILTERED.format(filter_status.replace(";", " - "))
51
+ if len(found_ins) == 1
52
+ else FILTERED_STATUS
53
+ )
30
54
 
31
- if other_info:
32
- for info in other_info.split(","):
33
- called_by = info.split("|")[0]
55
+ for found_in in found_ins:
56
+ called_by = found_in.split("|")[0]
34
57
  if called_by in callers_keys:
35
- callers[called_by] = "Pass"
36
- elif svdb_origin:
37
- for called_by in svdb_origin.split("|"):
58
+ callers[called_by] = call_status
59
+ return callers
60
+
61
+ info_found_in: str = variant.INFO.get("FOUND_IN")
62
+ if info_found_in:
63
+ return get_callers_from_found_in(info_found_in, variant.FILTER)
64
+
65
+ def get_callers_from_svdb_origin(svdb_origin: str, filter_status: Optional[str]) -> dict:
66
+ """If a svdb_origin tag (pipe separated) is found, callers listed will be marked Pass.
67
+ In case of a FILTER status, also set the caller status for a single caller to 'Filtered - status'.
68
+ """
69
+ svdb_callers: list = svdb_origin.split("|")
70
+
71
+ call_status = PASS_STATUS
72
+ if filter_status is not None:
73
+ call_status = (
74
+ FILTERED.format(filter_status.replace(";", " - "))
75
+ if len(svdb_callers) == 1
76
+ else FILTERED_STATUS
77
+ )
78
+
79
+ for called_by in svdb_callers:
38
80
  if called_by in callers_keys:
39
- callers[called_by] = "Pass"
40
- elif raw_info:
41
- info = raw_info.split("-")
42
- for call in info:
81
+ callers[called_by] = call_status
82
+ return callers
83
+
84
+ svdb_origin = variant.INFO.get("svdb_origin")
85
+ if svdb_origin:
86
+ return get_callers_from_svdb_origin(svdb_origin, variant.FILTER)
87
+
88
+ def get_callers_from_set(info_set: str, filter_status: str) -> dict:
89
+ """
90
+ If the FILTER status is not PASS (e.g. None - cyvcf2 FILTER is None if VCF file column FILTER is "PASS"),
91
+ in all of these cases, if a single caller is found, the "Pass" status is replaced with variant filter
92
+ status. If there is more than one caller, we can't quite tell which one is which, so all will be "Filtered"
93
+ without explicit status instead.
94
+
95
+ """
96
+
97
+ calls = info_set.split("-")
98
+
99
+ call_status = PASS_STATUS
100
+ if filter_status is not None:
101
+ call_status = (
102
+ FILTERED.format(filter_status.replace(";", " - "))
103
+ if len(calls) == 1
104
+ else FILTERED_STATUS
105
+ )
106
+
107
+ for call in calls:
43
108
  if call == "FilteredInAll":
44
109
  for caller in callers:
45
- callers[caller] = "Filtered"
46
- elif call == "Intersection":
110
+ callers[caller] = FILTERED_STATUS
111
+ return callers
112
+ if call == "Intersection":
47
113
  for caller in callers:
48
- callers[caller] = "Pass"
49
- elif "filterIn" in call:
114
+ callers[caller] = PASS_STATUS
115
+ return callers
116
+ if "filterIn" in call:
117
+ if "Filtered" not in call_status:
118
+ call_status = FILTERED_STATUS
50
119
  for caller in callers:
51
120
  if caller in call:
52
- callers[caller] = "Filtered"
121
+ callers[caller] = call_status
53
122
  elif call in callers_keys:
54
- callers[call] = "Pass"
123
+ callers[call] = PASS_STATUS
124
+ return callers
125
+
126
+ info_set = variant.INFO.get("set")
127
+ if info_set:
128
+ return get_callers_from_set(info_set, variant.FILTER)
55
129
 
56
- if raw_info or svdb_origin or other_info:
130
+ def get_callers_gatk_snv_fallback(filter_status: Optional[str]):
131
+ """As a final fallback, to accommodate a version range of MIP where no SNV caller was set for GATK,
132
+ if this is an SNV variant, and no other call was found, set as if it was a GATK call with Pass or filter status.
133
+ """
134
+ filter_status_default = "Pass"
135
+ if filter_status is not None:
136
+ filter_status_default = FILTERED.format(filter_status.replace(";", " - "))
137
+ callers["gatk"] = filter_status_default
57
138
  return callers
58
139
 
59
140
  if category == "snv":
60
- # cyvcf2 FILTER is None if VCF file column FILTER is "PASS"
61
- filter_status = "Pass"
62
- if variant.FILTER is not None:
63
- filter_status = "Filtered - {}".format(filter_status.replace(";", " - "))
64
- callers["gatk"] = filter_status
141
+ return get_callers_gatk_snv_fallback(variant.FILTER)
65
142
 
66
143
  return callers
@@ -6,6 +6,17 @@ import cyvcf2
6
6
  LOG = logging.getLogger(__name__)
7
7
 
8
8
 
9
+ def parse_clnsig_low_penetrance(sig_groups: List[str]) -> List[str]:
10
+ """If 'low_penetrance' is among the clnsig terms of an array, the term gets appended to the term immediately before in the array."""
11
+ result = []
12
+ for sig in sig_groups:
13
+ if sig == "low_penetrance" and result:
14
+ result[-1] += f",{sig}"
15
+ else:
16
+ result.append(sig)
17
+ return result
18
+
19
+
9
20
  def parse_clnsig(
10
21
  variant: cyvcf2.Variant, transcripts: Optional[dict] = None
11
22
  ) -> List[Dict[str, Union[str, int]]]:
@@ -58,6 +69,8 @@ def parse_clnsig(
58
69
  for term in significance.lstrip("_").split("/"):
59
70
  sig_groups.append("_".join(term.split(" ")))
60
71
 
72
+ sig_groups: List[str] = parse_clnsig_low_penetrance(sig_groups)
73
+
61
74
  for sig_term in sig_groups:
62
75
  clnsig_accession = {
63
76
  "value": sig_term,
@@ -495,7 +495,7 @@ def _parse_format_entry_trgt_mc(variant: cyvcf2.Variant, pos: int):
495
495
  if index in pathologic_mcs:
496
496
  pathologic_counts += int(count)
497
497
  else:
498
- pathologic_counts = int(allele)
498
+ pathologic_counts = 0 if allele == "." else int(allele)
499
499
 
500
500
  if ref_idx is not None and idx == ref_idx:
501
501
  mc_ref = pathologic_counts
@@ -92,6 +92,7 @@ def parse_variant(
92
92
 
93
93
  # cyvcf2 will set QUAL to None if '.' in vcf
94
94
  parsed_variant["quality"] = variant.QUAL
95
+
95
96
  parsed_variant["filters"] = get_filters(variant)
96
97
 
97
98
  # Add the dbsnp ids
@@ -235,6 +236,7 @@ def parse_variant(
235
236
 
236
237
  ###################### Add conservation ######################
237
238
  parsed_variant["conservation"] = parse_conservations(variant, parsed_transcripts)
239
+
238
240
  parsed_variant["callers"] = parse_callers(variant, category=category)
239
241
  set_rank_result(parsed_variant, variant, rank_results_header)
240
242
 
@@ -84,6 +84,12 @@
84
84
  <a target="_blank" href={{ record.entrez_link }} referrerpolicy="no-referrer" rel="noopener" target="_blank"> {{ entrez_id }}</a>
85
85
  </span>
86
86
  </li>
87
+ <li class="list-group-item">
88
+ PanelApp
89
+ <span class="float-end">
90
+ <a target="_blank" href={{ record.panelapp_link }} referrerpolicy="no-referrer" rel="noopener" target="_blank"> {{ symbol }} </a>
91
+ </span>
92
+ </li>
87
93
  {% if pli_score %}
88
94
  <li class="list-group-item">
89
95
  pLi Score (<a href={{ record.gnomad_link }} referrerpolicy="no-referrer" rel="noopener" target="_blank">GnomAD</a>)
@@ -79,17 +79,17 @@
79
79
  {% endif %}
80
80
  <div class="d-flex justify-content-center">
81
81
  {% if case.vcf_files.vcf_snv %}
82
- <form action="{{url_for('variants.variants', institute_id=institute._id, case_name=case.display_name) }}">
82
+ <form action="{{url_for('variants.variants', institute_id=institute._id, case_name=case.display_name) }}" target="_blank">
83
83
  <input type="hidden" id="hgnc_symbols" name="hgnc_symbols" value="{% for gene in variant.genes %}{{gene.hgnc_symbol}}{{ ", " if not loop.last else "" }}{% endfor %}"></input>
84
84
  <input type="hidden" id="gene_panels" name="gene_panels" value="['']"></input>
85
- <span><button type="submit" class="btn btn-secondary btn-sm" style="float: right;" target="_blank" rel="noopener" data-bs-toggle="tooltip" title="SNV and INDEL variants view filtered for the gene(s) {% for gene in variant.genes %}{{gene.hgnc_symbol}}{{ ", " if not loop.last else "" }}{% endfor %} ">SNVs</button></span>
85
+ <span><button type="submit" class="btn btn-secondary btn-sm" style="float: right;" data-bs-toggle="tooltip" title="SNV and INDEL variants view filtered for the gene(s) {% for gene in variant.genes %}{{gene.hgnc_symbol}}{{ ", " if not loop.last else "" }}{% endfor %} ">SNVs</button></span>
86
86
  </form>
87
87
  {% endif %}
88
88
  {% if case.vcf_files.vcf_sv %}
89
- <form action="{{url_for('variants.sv_variants', institute_id=institute._id, case_name=case.display_name) }}">
89
+ <form action="{{url_for('variants.sv_variants', institute_id=institute._id, case_name=case.display_name) }}" target="_blank">
90
90
  <input type="hidden" id="hgnc_symbols" name="hgnc_symbols" value="{% for gene in variant.genes %}{{gene.hgnc_symbol}}{{ ", " if not loop.last else "" }}{% endfor %}"></input>
91
91
  <input type="hidden" id="gene_panels" name="gene_panels" value="['']"></input>
92
- <button type="submit" class="btn btn-secondary btn-sm" target="_blank" rel="noopener" data-bs-toggle="tooltip" title="SV variants view filtered for the gene(s) {% for gene in variant.genes %}{{gene.hgnc_symbol}}{{ ", " if not loop.last else "" }}{% endfor %} ">SVs</button></span>
92
+ <button type="submit" class="btn btn-secondary btn-sm" data-bs-toggle="tooltip" title="SV variants view filtered for the gene(s) {% for gene in variant.genes %}{{gene.hgnc_symbol}}{{ ", " if not loop.last else "" }}{% endfor %} ">SVs</button></span>
93
93
  </form>
94
94
  {% endif %}
95
95
  </div>
@@ -26,6 +26,9 @@
26
26
  {{ new_panel() }}
27
27
  {{ search_gene_card() }}
28
28
  {% if panel_groups %}
29
+ <span class="float-end me-3 mt-3">
30
+ <input type="checkbox" name="hideLine" checked onclick="toggleRow(this)"> Hide removed panels</input>
31
+ </span>
29
32
  {% for institute,panels in panel_groups %}
30
33
  {{ panel_view(institute,panels) }}
31
34
  {% endfor %}
@@ -103,7 +106,7 @@
103
106
  <select name="institute" class="form-control" required>
104
107
  <option value="">Choose institute...</option>
105
108
  {% for institute in institutes %}
106
- <option value="{{ institute._id }}">{{ institute.display_name }}</option>
109
+ <option value="{{ institute._id }}">{{ institute.display_name }} ({{institute._id}})</option>
107
110
  {% endfor %}
108
111
  </select>
109
112
  </div>
@@ -141,10 +144,7 @@
141
144
  {% macro panel_view(institute, panels) %}
142
145
  <div class="card panel-default w-100 mt-3 justify-content-center">
143
146
  <div class="card-title d-flex justify-content-between">
144
- <span><strong>{{ institute.display_name }}</strong> - Panels</span>
145
- <span>
146
- <input type="checkbox" name="hideLine" checked onclick="toggleRow(this)"> Hide removed panels</input>
147
- </span>
147
+ <span><strong>{{ institute.display_name }} ({{institute._id}})</strong> - Panels</span>
148
148
  </div>
149
149
  <div class="card-body">
150
150
  <table class="table table-striped" id="panelTable" style="table-layout: fixed;">
@@ -41,13 +41,14 @@ from scout.server.utils import (
41
41
  from .utils import (
42
42
  add_gene_info,
43
43
  associate_variant_genes_with_case_panels,
44
- callers,
45
44
  clinsig_human,
46
45
  default_panels,
47
46
  end_position,
48
47
  evaluation,
49
48
  frequencies,
50
49
  frequency,
50
+ get_callers,
51
+ get_filters,
51
52
  is_affected,
52
53
  predictions,
53
54
  )
@@ -315,7 +316,10 @@ def variant(
315
316
  update_representative_gene(variant_obj, variant_genes)
316
317
 
317
318
  # Add display information about callers
318
- variant_obj["callers"] = callers(variant_obj)
319
+ variant_obj["callers"] = get_callers(variant_obj)
320
+
321
+ # annotate filters
322
+ variant_obj["filters"] = get_filters(variant_obj)
319
323
 
320
324
  # Convert affection status to strings for the template
321
325
  is_affected(variant_obj, case_obj)
@@ -17,7 +17,7 @@
17
17
  <tbody>
18
18
  {% for clinsig in variant.clinsig_human %}
19
19
  <tr>
20
- <td>{{ clinsig.human }}</td>
20
+ <td>{{ clinsig.human }} {% if clinsig.low_penetrance %}(low penetrance){% endif %}</td>
21
21
  {% if clinsig.accession %}
22
22
  <td><a href="{{ clinsig.link }}" target="_blank">{{ clinsig.accession }}</a></td>
23
23
  {% else %}
@@ -97,8 +97,15 @@
97
97
  </table>
98
98
  </div>
99
99
  <div class="panel-footer">
100
+ {% for filter in variant.filters %} <!-- collect info from variant's filters (PASS) -->
101
+ <span class="badge bg-{{ filter.label_class }}" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ filter.description }}">
102
+ {{ filter.label }}
103
+ </span>
104
+ {% endfor %}
100
105
  {% for name, caller in variant.callers %}
101
- <span class="badge bg-secondary">{{ name }}: {{ caller }}</span>
106
+ <span class="badge {% if caller == 'Pass' %}bg-success{% elif 'Filtered' in caller %}bg-secondary{% else %}bg-black{% endif %}">
107
+ {{ name }}: {{ caller }}
108
+ </span>
102
109
  {% endfor %}
103
110
  </div>
104
111
  </div>
@@ -2,7 +2,7 @@ import logging
2
2
  from typing import Dict, List, Optional, Tuple
3
3
 
4
4
  from scout.adapter import MongoAdapter
5
- from scout.constants import ACMG_COMPLETE_MAP, CALLERS, CLINSIG_MAP, SO_TERMS
5
+ from scout.constants import ACMG_COMPLETE_MAP, CALLERS, CLINSIG_MAP, SO_TERMS, VARIANT_FILTERS
6
6
  from scout.server.links import add_gene_links, add_tx_links
7
7
 
8
8
  LOG = logging.getLogger(__name__)
@@ -592,14 +592,15 @@ def clinsig_human(variant_obj):
592
592
  yield clinsig_obj
593
593
 
594
594
 
595
- def callers(variant_obj):
595
+ def get_callers(variant_obj: dict) -> List[Tuple]:
596
596
  """Return info about callers.
597
597
 
598
- Args:
599
- variant_obj(scout.models.Variant)
598
+ Given a scout.models.Variant compliant variant obj dict,
599
+ return a list of the callers that identified the variant.
600
600
 
601
- Returns:
602
- calls(list(str)): A list of the callers that identified the variant
601
+ Finds calls in the CALLERS constant for the variant category,
602
+ directly on the variant object, gathers them in a set of tuples
603
+ of caller name and status, and returns as a list of tuples.
603
604
  """
604
605
  category = variant_obj.get("category", "snv")
605
606
  calls = set()
@@ -610,6 +611,37 @@ def callers(variant_obj):
610
611
  return list(calls)
611
612
 
612
613
 
614
+ def get_filters(variant_obj: dict) -> List[Dict[str, str]]:
615
+ """Return a list with richer format descriptions about filter status,
616
+ if available. Fall back to display the filter status in a "danger" badge
617
+ if it is not known from the VARIANT_FILTERS constant.
618
+
619
+ Currently, the controller may be applied repeatedly to the same variant object
620
+ for redecoration. Check if the filter strings have already been converted
621
+ to dicts before attemting to convert them.
622
+ """
623
+ variant_filters = variant_obj.get("filters", [])
624
+
625
+ filters: List[Dict[str, str]] = []
626
+
627
+ for f in variant_filters:
628
+ if isinstance(f, str):
629
+ if f.lower() in VARIANT_FILTERS:
630
+ filters.append(VARIANT_FILTERS[f.lower()])
631
+ else:
632
+ filters.append(
633
+ {
634
+ "label": f.replace("_", " ").upper(),
635
+ "description": f.replace("_", " "),
636
+ "label_class": "danger",
637
+ }
638
+ )
639
+ elif isinstance(f, dict):
640
+ filters.append(f)
641
+
642
+ return filters
643
+
644
+
613
645
  def associate_variant_genes_with_case_panels(case_obj: Dict, variant_obj: Dict) -> None:
614
646
  """Add associated gene panels to each gene in variant object"""
615
647
 
@@ -27,12 +27,12 @@ from scout.constants import (
27
27
  MANUAL_RANK_OPTIONS,
28
28
  MOSAICISM_OPTIONS,
29
29
  SPIDEX_HUMAN,
30
- VARIANT_FILTERS,
31
30
  VARIANTS_TARGET_FROM_CATEGORY,
32
31
  )
33
32
  from scout.server.blueprints.variant.utils import (
34
- callers,
35
33
  clinsig_human,
34
+ get_callers,
35
+ get_filters,
36
36
  predictions,
37
37
  update_representative_gene,
38
38
  update_variant_case_panels,
@@ -936,14 +936,10 @@ def parse_variant(
936
936
  update_representative_gene(variant_obj, variant_genes)
937
937
 
938
938
  # Add display information about callers
939
- variant_obj["callers"] = callers(variant_obj)
939
+ variant_obj["callers"] = get_callers(variant_obj)
940
940
 
941
941
  # annotate filters
942
- variant_obj["filters"] = [
943
- VARIANT_FILTERS[f]
944
- for f in map(lambda x: x.lower(), variant_obj["filters"])
945
- if f in VARIANT_FILTERS
946
- ]
942
+ variant_obj["filters"] = get_filters(variant_obj)
947
943
 
948
944
  return variant_obj
949
945
 
@@ -1082,7 +1078,7 @@ def variant_export_lines_common(store: MongoAdapter, variant: dict, case_obj: di
1082
1078
  else variant.get("category")
1083
1079
  )
1084
1080
  variant_line.append(cat.upper() if cat else "")
1085
- variant_line.append(" ".join([f"{name}:{caller}" for name, caller in callers(variant)]))
1081
+ variant_line.append(" ".join([f"{name}:{caller}" for name, caller in get_callers(variant)]))
1086
1082
  variant_line.append(variant["chromosome"])
1087
1083
  variant_line.append(position)
1088
1084
  variant_line.append(change)
@@ -62,7 +62,7 @@
62
62
  <th title="Population frequency">Pop Freq</th>
63
63
  <th title="Observed" style="width:7%">Observed</th>
64
64
  <th title="Variant type">Type</th>
65
- <th title="Callers" style="width:8%">Callers</th>
65
+ <th title="Callers" style="width:12%">Callers</th>
66
66
  <th title="Functional consequence annotation" style="width:10%">Consequence</th>
67
67
  <th data-bs-toggle="tooltip" data-bs-placement="top" title="Tumor alt. AF. &#013; Alt. allele count | Ref. allele count">Tumor</th>
68
68
  <th data-bs-toggle="tooltip" data-bs-placement="top" title="Normal alt. AF. &#013; Alt. allele count | Ref. allele count">Normal</th>
@@ -115,7 +115,7 @@
115
115
  <td>{{ position_cell(variant) }}</td>
116
116
  <td class="text-end">{{ frequency_cell_general(variant) }}</td>
117
117
  <td>{{ observed_cell_general(variant) }}</td>
118
- <td>{{ variant.sub_category }}</td>
118
+ <td>{{ variant.sub_category|upper }}</td>
119
119
  <td>{{ callers_cell(variant) }}</td>
120
120
  <td>{{ variant_funct_anno_cell(variant) }}</td>
121
121
  <td>{{ allele_cell(variant.tumor or {}) }}</td>
@@ -56,7 +56,7 @@
56
56
  </span>
57
57
  {% endfor %}
58
58
  {% for name, caller in variant.callers %} <!-- Collect info for specific callers -->
59
- <span class="badge {% if caller == 'Pass' %}bg-success{% elif caller == 'Filtered' %}bg-secondary{% else %}bg-black{% endif %}" data-bs-toggle="tooltip" data-bs-html="true" title="{{caller}}">
59
+ <span class="badge {% if caller == 'Pass' %}bg-success{% elif 'Filtered' in caller %}bg-secondary{% else %}bg-black{% endif %}" data-bs-toggle="tooltip" data-bs-html="true" title="{{caller}}">
60
60
  {{ name }}
61
61
  </span>
62
62
  {% endfor %}
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Optional
2
+ from typing import List, Optional
3
3
 
4
4
  import requests
5
5
 
@@ -41,7 +41,7 @@ class PanelAppClient:
41
41
  for type in panel.get("types", []):
42
42
  self.panel_types.add(type["slug"])
43
43
 
44
- def get_panel_ids(self, signed_off: bool) -> list[int]:
44
+ def get_panel_ids(self, signed_off: bool) -> List[int]:
45
45
  """Returns a list of panel ids contained in a json document with gene panels data."""
46
46
 
47
47
  def get_ids(json_panels):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scout-browser
3
- Version: 4.91.1
3
+ Version: 4.92
4
4
  Summary: Clinical DNA variant visualizer and browser.
5
5
  Home-page: https://github.com/Clinical-Genomics/scout
6
6
  Author: Måns Magnusson
@@ -1,5 +1,5 @@
1
1
  scout/__init__.py,sha256=Z4liXvmEcLkC67ElsWvYHfemPKdWgWI5O6MB6XlDM8M,232
2
- scout/__version__.py,sha256=UEW2jG2n4LaWe4lbBdEuuVDJFg2ITmLfH-vIghRM4ms,23
2
+ scout/__version__.py,sha256=ANcNj-w6TB4wETdZ9CZJYc1ZGU2Q1cA11Hzzi92m9BE,21
3
3
  scout/adapter/__init__.py,sha256=-iX_hx2NI1EMAqX0pMd5_90Nnd9uvIMxv9EbefYBzsc,86
4
4
  scout/adapter/client.py,sha256=IuajRsEwTG41ZP14X09Q1Cj94zIgmIvUtlXfcAFn0EA,1513
5
5
  scout/adapter/mongo/__init__.py,sha256=NdHYCUXWUAuX5cUS3-6HCws2hW9uoGep8i0SC-oJd3k,31
@@ -20,9 +20,9 @@ scout/adapter/mongo/institute.py,sha256=GQmMKb_VzsvWwadp6gXHlSSpcG5ovF1ozdTzvpTF
20
20
  scout/adapter/mongo/managed_variant.py,sha256=YFdnIhNVIawVhmlOxHOpe6sJyso0FCGdlXOXyhSWol8,8373
21
21
  scout/adapter/mongo/matchmaker.py,sha256=amTvFOlUbrt1RmecY_8hPY6bO3j79lc2UbmzlCQcRuk,6378
22
22
  scout/adapter/mongo/omics_variant.py,sha256=VdkNG_l6vcr3UF25EixEfvIdMGkSGeNaMjLRhQHS_lc,7521
23
- scout/adapter/mongo/panel.py,sha256=XbV_oh9II89OLsWm2BWxiYKkxMGU4HGKuG-8L-drWbk,20018
23
+ scout/adapter/mongo/panel.py,sha256=d1oMEYAiDGybLmlbbf3-fQdCdU0-T7x2XdIUwZGthYk,20031
24
24
  scout/adapter/mongo/phenomodel.py,sha256=cypSS8YRzu98Bf1kC0orfrLNn_ZQSYCK8e4mNR5PaPY,2572
25
- scout/adapter/mongo/query.py,sha256=MzeMUND_BPHgJLGDEbOVgwf4ic8M9ZXFcyroQd0LMJQ,33314
25
+ scout/adapter/mongo/query.py,sha256=Zk5BV9GZYVlGoSRRjP88TpvB4teVpvHgHnSDV0W-kS0,33157
26
26
  scout/adapter/mongo/rank_model.py,sha256=wvDNI4OLf-f7ZYZ_Q_6qi0myxOJCNNJR_-2-_0u2K2M,5712
27
27
  scout/adapter/mongo/transcript.py,sha256=3U1qtyxZ1DnrzdBJm_emJXISMYFKJuX_zAKynUt8NMY,7417
28
28
  scout/adapter/mongo/user.py,sha256=QoQnRWqi_dV3ZwGzBonEU6Ap9TgMDf2x_C5UIqG0pa0,2569
@@ -44,7 +44,7 @@ scout/build/genes/exon.py,sha256=a0oyW69x0tTImu4rxce5pU3Cb_GLSIdbexU0ex_OH7Q,225
44
44
  scout/build/genes/hgnc_gene.py,sha256=3ckEc4jpwcN_bYeAbv_wJrjzWMthm0HJR1dSzAraM_A,678
45
45
  scout/build/genes/transcript.py,sha256=qXdS7bU1d-ikgN8UOSyW7u34y-qpgcpVuCccP2tKR80,2416
46
46
  scout/build/variant/__init__.py,sha256=Y70EK_8TS69seYSyIvL1Mek1FMo3XPeXcOnYVIOWggA,173
47
- scout/build/variant/clnsig.py,sha256=uAfrf4RSUGliIp13fW9XqJshodNWxjuAwUbBbNHgmCc,719
47
+ scout/build/variant/clnsig.py,sha256=O3JmBsMXZhD0PCWvM-sAgAYzU1oZ-U6Xhv_Kh8nA5mU,680
48
48
  scout/build/variant/compound.py,sha256=tYikQ4PmgAH1_yrE9uYaUX4_EoAs_XEiT8JWAjrZuDg,816
49
49
  scout/build/variant/gene.py,sha256=Fj_ouJtNAZOvxYVo9oVXaYJE5_zx-mJqL-uOARD4ku8,3857
50
50
  scout/build/variant/genotype.py,sha256=QDTZWFB8ix9Zd1m9UPWgT008i6rC7gT-uFzRr9GniDU,1009
@@ -58,7 +58,7 @@ scout/commands/serve.py,sha256=fImJrgMBYQTD18xODjGqN6NgXjTe8seI_awd9vF04rU,1564
58
58
  scout/commands/utils.py,sha256=T29f-1wTq3uoxqtv6QOqBdMBl7tLeEn8DYXnnv3gowI,306
59
59
  scout/commands/wipe_database.py,sha256=TvCoXZCT-mvTqsZaFstV5u5FM8KAQstB3JxyGHYMLtg,1005
60
60
  scout/commands/delete/__init__.py,sha256=6Z97FsWMqyKqF64Anl1zwljVNTfjJUCI7yylxIEnsUY,35
61
- scout/commands/delete/delete_command.py,sha256=X3sH0pP51n1Gmv3e7EbgXggFp_yG4ZtziSNsIpcNu78,12584
61
+ scout/commands/delete/delete_command.py,sha256=_x897Du0nTsYmSG_5LAIm6Z9sjKcaCrtAR7cwuNwl4I,13285
62
62
  scout/commands/download/__init__.py,sha256=mfDzxqKzJ0LgfPBN_fehkdX5BPy1FJ3rauA3ORLIjCM,39
63
63
  scout/commands/download/download_command.py,sha256=m5CKefst3qhs4urfNu1A2TERisUb_5WPn-wn9bGCDr0,736
64
64
  scout/commands/download/ensembl.py,sha256=CsTMjYihBtXyfofNIQ2riL9UBzydDbqoNZ7jJVQ15ak,2112
@@ -128,13 +128,13 @@ scout/constants/__init__.py,sha256=HZvAMX-37ugK0fRwa8xKGvnZkicyUJH-SH2pqw7rm-g,5
128
128
  scout/constants/acmg.py,sha256=hYPzoLUqpuTjGXfIN80Nb1njriesH9oAELu1scp-ByU,18083
129
129
  scout/constants/case_tags.py,sha256=EvLYtbZADyFEngeY8rvPsJ_1NdLmHrlnrGTlnj7tGGs,9336
130
130
  scout/constants/clinvar.py,sha256=nr7KhwMIO_7taNQokRJlpgZfenMlKsdPIMpdOx3TwKY,5594
131
- scout/constants/clnsig.py,sha256=5Z4fZU__ej9teXK4hD9vGhIGmaGL6PoJqK5GuzLWxpE,1414
131
+ scout/constants/clnsig.py,sha256=TSeZjUno2jEvQTenrltZ900ZFYIRNoul_Wm2qRjvpPA,1493
132
132
  scout/constants/disease_parsing.py,sha256=M9_OgsN88oXwKH_XpxdDma0zuWPRoHFQjL19tzojBPo,686
133
133
  scout/constants/file_types.py,sha256=3BU2cw40cHMT5IzEGEF_SsIhgYUbnIlUCRmwmB01fzI,3046
134
134
  scout/constants/filters.py,sha256=1bcj-z7__yv5eQpjB60wqSHZ3U5U0CVyNbcYT-Wn-vc,957
135
135
  scout/constants/gene_tags.py,sha256=pRRsjn9zYGR3nLFKxe1gOYqWm4uQbpfxYzfRxcptxqA,3856
136
136
  scout/constants/igv_tracks.py,sha256=NbBBnM3s1S8cJM_S36qi7SU2ACW_lJVS6EP2W0kCTIQ,4697
137
- scout/constants/indexes.py,sha256=-rb5VP68Arl2t-bFDYWiQswAF3YxjrAJVuMtQWrT__8,5497
137
+ scout/constants/indexes.py,sha256=mCj_ih9Sv7Qv4DrzLRH30EQZ-Tgyn_Sf6NYapCOlMOc,5793
138
138
  scout/constants/panels.py,sha256=X38XGPlNgOGhXHt5mSpryOS7gMeP-tUD1t1WIT2G5wM,785
139
139
  scout/constants/phenotype.py,sha256=MrbXirisR_7GPnxV3NOj3-BoM9CvtGgFZj7PfJu85RM,2331
140
140
  scout/constants/query_terms.py,sha256=2A4CuTgc7W_VMj4atkJdZFfvBATu7OQg51udFM0rMOo,1574
@@ -414,28 +414,28 @@ scout/parse/mitodel.py,sha256=3uvEXI9v9wIw97NUL7gqLLxHay0mpQpDgKaIxUbIyrE,803
414
414
  scout/parse/omim.py,sha256=nrCaFZgjUKZo9Jfku2-jcNjdsIYHsvjdWcydz4nCpZA,12465
415
415
  scout/parse/orpha.py,sha256=5u9xqGpAn8vgoJ0uVqbYiqQBiNfBwXOiTzX16kAnmFU,4392
416
416
  scout/parse/panel.py,sha256=J28e_MkKeB5r4hOutb3qimxUT7G5yg8x1Ca4bAs0I_c,9577
417
- scout/parse/panelapp.py,sha256=1UAKBm48tKlfDpNb_VH_kfqO8tgduXRSIQnWa61Fzrc,3944
417
+ scout/parse/panelapp.py,sha256=Idz6cGvQnyI-nn6yCTc6EGSRp1gX-CXN6Y4ayAee-_A,4076
418
418
  scout/parse/peddy.py,sha256=uM49GaZMtr8waCsZDvCHDS5JDQ43JUlhdWh9C7f7ZvU,5418
419
419
  scout/parse/smn.py,sha256=iOK1N8iYm9dFigsKtWq0Y0ZCa1CH29s9zeR_tH0bPuc,1153
420
420
  scout/parse/omics_variant/__init__.py,sha256=vq8Ew4_Xr2vPy_3Fg0eTpPWsQpWnUXYBhjRndBUvtTw,422
421
421
  scout/parse/omics_variant/drop.py,sha256=SD98E9ksPPv62SFUuR4TfZHVIIIy1RXZRdMhm5Hu4RQ,478
422
422
  scout/parse/variant/__init__.py,sha256=5yqCQlAYMqosRabdipFUXqopSMBN4X6jwpNiKiYKlsE,35
423
- scout/parse/variant/callers.py,sha256=roTeQUMMNxOCeRHuL-TwJpIg5OwetMn4v-5E2xWvulU,2372
424
- scout/parse/variant/clnsig.py,sha256=p5YNF_H1x6h1lTJX0D06Z9G1NfwQJ1WjnLauK1Oli28,4951
423
+ scout/parse/variant/callers.py,sha256=eA5o4Ov_v5ds__4xpif1ttj5yk2nK4GXwhYSWL4NTDg,5709
424
+ scout/parse/variant/clnsig.py,sha256=dFIvV29cvMOFw7hSgbjBEXzWV5YVKpSGQqgLuHbMePk,5421
425
425
  scout/parse/variant/compound.py,sha256=zeRHBwobusCW-ylgurHrnPsc-edeJHeXj6xjXkrbFt8,1493
426
426
  scout/parse/variant/conservation.py,sha256=8eHXy57g6ng0eMo38LsIcQ8w_H5mpBSfiMuaXF7aBi4,2949
427
427
  scout/parse/variant/coordinates.py,sha256=CU-EyD8NVgTbyIdmYDO3k-zVaMN1EDONjorDwyUSnXU,4742
428
428
  scout/parse/variant/deleteriousness.py,sha256=zeFzx218GL-5pKniyci7MVHj3a1cep4nmvoSg7u0ogA,541
429
429
  scout/parse/variant/frequency.py,sha256=kpUNrXvg6IeLvf3TFmEni5lUfp1jFIMCKMrevJwUCNg,7854
430
430
  scout/parse/variant/gene.py,sha256=30SR2ck12HQW87LlRfchdgPVzOxb74aIXC2WzPL2BPk,4688
431
- scout/parse/variant/genotype.py,sha256=IqoH3UOd34ZrPE1xkDDmXavDEYe10D5mH9zf20E_BTA,16553
431
+ scout/parse/variant/genotype.py,sha256=c53cRtC-9DH6kEb_F2n4fbXdKY3Zcq6srQC-2scqiaU,16577
432
432
  scout/parse/variant/headers.py,sha256=se3H4r22q30MIvtOyc5jWNXZLVnDx58X4h-eED7hkl4,2947
433
433
  scout/parse/variant/ids.py,sha256=N_2m7Hgdh7asHdWU4k2dMySsutxp16ODRE_OHy_Niwg,2628
434
434
  scout/parse/variant/managed_variant.py,sha256=qwmi2sPLwGZM5izSsMpvhQ9vfMHREiwiIzjDCuOdqQo,2288
435
435
  scout/parse/variant/models.py,sha256=NrqLXu7PxpIQ0NmjGRIEk4vS_y972VPiexLsZCZpOn0,507
436
436
  scout/parse/variant/rank_score.py,sha256=ipFxCTsQHMqObUbzLJlDAKUb3_lk_sqEYzH52myZVVk,486
437
437
  scout/parse/variant/transcript.py,sha256=0kxaXWrNAvSiU76ZdIl9PQFzUyj6go6u3BnNhnTk8pg,13359
438
- scout/parse/variant/variant.py,sha256=CTCaE07GqDg52ZhUPLpEOoEYLgr4y1mPtvRvAsxt5IM,24057
438
+ scout/parse/variant/variant.py,sha256=nf_0q2J7TryWhB-Oz697HYSDJTPNmkXnPHmKtjhHQUU,24059
439
439
  scout/resources/__init__.py,sha256=i9UVG651subgmOZ-Gm-JKPsXBqr5-50QUDfSpbwmwIw,443
440
440
  scout/resources/cytoBand_hg19.txt.gz,sha256=pheUD5b9NlVuvwwnbKwDc2FG80Yg70gvPxVXP-Sqd3k,6147
441
441
  scout/resources/cytoBand_hg38.txt.gz,sha256=sqSVmvPlktQ-0hTiTapJM-5UgyV6xDoYZuTF0kPuETs,6105
@@ -500,7 +500,7 @@ scout/server/blueprints/diagnoses/templates/diagnoses/disease_term.html,sha256=8
500
500
  scout/server/blueprints/genes/__init__.py,sha256=LPHrbmfVhZpLGGdExFbJp_Du1NKCsVOO_eaevpsNLC8,52
501
501
  scout/server/blueprints/genes/controllers.py,sha256=LCuGPQymKxA7sES49z_j2_B3prKmNY-ME0VK892VoPs,3629
502
502
  scout/server/blueprints/genes/views.py,sha256=lFJ7izYu0CbUJo3j5TesrUhIwreZUYw9_dDqd6iG8m4,1512
503
- scout/server/blueprints/genes/templates/genes/gene.html,sha256=X1WR-sHYGnWyhQfgN77TqC3_yoweaqu7MjwUvAO9UBo,10872
503
+ scout/server/blueprints/genes/templates/genes/gene.html,sha256=a--c-IjzNKN_JW7z9jbNCnk3bLD_oVeFvf5x8IAmynA,11197
504
504
  scout/server/blueprints/genes/templates/genes/genes.html,sha256=x6jXKijvuEX9GvIedHW4O_BerYXiWEmAdYT0HTiGnhI,1130
505
505
  scout/server/blueprints/genes/templates/genes/layout.html,sha256=cZMLe2cInq24z0sZpPxDm_kEiAe5VQbOR-8XWn6wlvI,1601
506
506
  scout/server/blueprints/institutes/__init__.py,sha256=kGSyYrBC1QaEQBDdoMkMLfaowV7roaV5DowICi_0RSQ,65
@@ -542,7 +542,7 @@ scout/server/blueprints/managed_variants/templates/managed_variants/managed_vari
542
542
  scout/server/blueprints/omics_variants/__init__.py,sha256=8UVXrChArhIvMxtgUcG-udvmlTn56q41iy-naOZw5us,37
543
543
  scout/server/blueprints/omics_variants/controllers.py,sha256=AnM70stvLniJIU3pFUX-InNjuT-7K0RpuAEYa7vM-jw,3912
544
544
  scout/server/blueprints/omics_variants/views.py,sha256=P-mo2S1RBGYxsNCFqSTNQNLvqiH9r6_AoZgsOWpopPE,3817
545
- scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html,sha256=hd8vxHY1hBqiyvgefLK3S_i_VnOgGwCJLmJUxiJhB4M,13733
545
+ scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html,sha256=gv9llZzH-AKJ4i2XJKZFJi9IBgvF84WI7QCVuvFOhTA,13703
546
546
  scout/server/blueprints/panels/__init__.py,sha256=usxBF0O7zNX1d9jt-8DRoFZwcfHHS96Gv87LDr1AgG4,53
547
547
  scout/server/blueprints/panels/controllers.py,sha256=DHIIXp_kms4DkTX2mkSdWhW-b4mk0gsRX2XU-4JP3CM,12597
548
548
  scout/server/blueprints/panels/forms.py,sha256=DYlhYpnpv7ehf9JlY3HRFwy-TZ5QDHB0RIRaNTAW1jQ,696
@@ -551,7 +551,7 @@ scout/server/blueprints/panels/templates/panels/gene-edit.html,sha256=KqdUdu9370
551
551
  scout/server/blueprints/panels/templates/panels/panel.html,sha256=qMdyxia0Oei83ECR6TTxOn62hh447XuGFF_TD63NP6E,16527
552
552
  scout/server/blueprints/panels/templates/panels/panel_pdf_case_hits.html,sha256=uzfZJiMNQiTa_6u4uMuIbK3VXIs-8Rw-MjKujFttZG8,3438
553
553
  scout/server/blueprints/panels/templates/panels/panel_pdf_simple.html,sha256=cpOnQzeKYnQwXosTKk9hkiBigJJLS3Q_y2oHDR3C8io,2744
554
- scout/server/blueprints/panels/templates/panels/panels.html,sha256=zjVzfgsapjlZBZ8Kz2zRz0oShg1msXTkkoENy9jF4Tc,14038
554
+ scout/server/blueprints/panels/templates/panels/panels.html,sha256=2IEZFbXzp4MKbx-9UZTW8rZt8pl3iZXPlkvppS3sj0Q,14106
555
555
  scout/server/blueprints/phenomodels/__init__.py,sha256=Kb1fqfCn-QsH5mz6hiuQ2DiC7icTClD4HLey6QN4GD4,34
556
556
  scout/server/blueprints/phenomodels/controllers.py,sha256=g5-BxlaHN7JBuQHEcOtQMUDEO9U9iy9HICaIaIEn3vk,11019
557
557
  scout/server/blueprints/phenomodels/forms.py,sha256=Z7dMIJml5xZ1cQV1jh_-IGVxhxk4lVhcUTvFa6ArbJo,740
@@ -600,14 +600,14 @@ scout/server/blueprints/public/static/ideograms/chromosome-X.png,sha256=Dj7npcW_
600
600
  scout/server/blueprints/public/static/ideograms/chromosome-Y.png,sha256=KlOsBLZYFVHRvXvTioT-XE57zSWoYeIwIEXo_rzLBR0,1524
601
601
  scout/server/blueprints/public/templates/public/index.html,sha256=-c6-r2G6-cdE9PLV126V8zTwYmApI88UIQKWuVP6HP4,4268
602
602
  scout/server/blueprints/variant/__init__.py,sha256=SlD8-Aoj9Jq9aVTJjtFfsu-0sUVfkzpiEXcH8z9q6dI,54
603
- scout/server/blueprints/variant/controllers.py,sha256=9pojsGPszRn61XHQg4OwCXxqniyJgTGdZvMz4_4rNxQ,25406
604
- scout/server/blueprints/variant/utils.py,sha256=fsX_PHBOHloypjtKx9LPKxjyH-HW3ERxnQl-8NOP8Sw,23127
603
+ scout/server/blueprints/variant/controllers.py,sha256=yCna3EoYG-KwfPy4k9Z-p0cMeMO-EAB4YwUt3MyBYN0,25509
604
+ scout/server/blueprints/variant/utils.py,sha256=XMnsgIzOSG2z1mXlBoWZpNvFr-Ocx860AKlKXnOJ0oI,24463
605
605
  scout/server/blueprints/variant/verification_controllers.py,sha256=eKzP222e7xuFOaQaI9MLOrD9RWtI8uGB1cJYbcXLzF0,10972
606
606
  scout/server/blueprints/variant/views.py,sha256=XAAIE35SXsGLLphUK4mQ6Kl8wpxwDEEo5kXLh6KD83w,14957
607
607
  scout/server/blueprints/variant/templates/variant/acmg.html,sha256=Fk4vL1Pu4G3wZsfiUO2jBlFLFoRgFAeqChlIyas5Bb4,8758
608
608
  scout/server/blueprints/variant/templates/variant/buttons.html,sha256=4vlnvJKhr28qqzevlecAIvumvOgLZhGyPYQm68AnKzU,7608
609
609
  scout/server/blueprints/variant/templates/variant/cancer-variant.html,sha256=1D9uLIgb06qfhcbl0wB5mRrgARVgfCJfRZhf4wEA2tc,13971
610
- scout/server/blueprints/variant/templates/variant/components.html,sha256=dINgA52b2kZ3g0DKzimVu21jmhZL2BVzEDNfMibQA_M,21507
610
+ scout/server/blueprints/variant/templates/variant/components.html,sha256=wBBrIMtEvkSX2lzFnkBB8gj--vETJ55cHtAC21aZG2s,21566
611
611
  scout/server/blueprints/variant/templates/variant/gene_disease_relations.html,sha256=1U77akxqbb4AS2GSyvFwGD6D7rP68L3KXKLUmP73664,7256
612
612
  scout/server/blueprints/variant/templates/variant/rank_score_results.html,sha256=32RfBrpZ_J-1WYE01Bdd5IC9i1MAzXT7GF27OlElk94,2040
613
613
  scout/server/blueprints/variant/templates/variant/sanger.html,sha256=0kVnscTw3KUwjR4QOEuNJMOK9eADGEn9qGNtGx2ST7Y,4507
@@ -616,22 +616,22 @@ scout/server/blueprints/variant/templates/variant/sv-variant.html,sha256=8199JLl
616
616
  scout/server/blueprints/variant/templates/variant/tx_overview.html,sha256=turyCoOCCd_N80FakxXfIl7q_WViysz1fwx3j312_Lg,6737
617
617
  scout/server/blueprints/variant/templates/variant/utils.html,sha256=lF-w3400plEn0gVpHG-9k7N9L_p1U-PFGitcT_YlZw8,25414
618
618
  scout/server/blueprints/variant/templates/variant/variant.html,sha256=saZzZ-ppdjE_4hSfW3MqMGyu5l_L8upyXS1uzwhbMiM,17844
619
- scout/server/blueprints/variant/templates/variant/variant_details.html,sha256=J-pF8LRXFnCxIbNfL7klTLj172rlpWF8PznO4ie9Igc,19921
619
+ scout/server/blueprints/variant/templates/variant/variant_details.html,sha256=a-_DgccaehxiAQaBeTv9PXubwjHOGVqH1fj7WQMWWqM,20332
620
620
  scout/server/blueprints/variants/__init__.py,sha256=W1KCz9kEbVlNO0o3NvLitYLQoP_3JSJ5KSjhpcjlUBQ,55
621
- scout/server/blueprints/variants/controllers.py,sha256=OOBoemjmuOAADLv3wgKZU2OHiuH2CaK8bO3-mMhRV3M,72924
621
+ scout/server/blueprints/variants/controllers.py,sha256=xUxBgVe7sns5FzsjS1Z0VOgnRMTNSpIcotFzSjW9wwU,72824
622
622
  scout/server/blueprints/variants/forms.py,sha256=w4Woeek6gpZfPM_9e1E_n-gpVvNxXPU_ria7cvP1HSo,10750
623
623
  scout/server/blueprints/variants/utils.py,sha256=ifFBoyigx0A5KPE4iz9NSpyuUeF1bElrb4ohQLD2GlU,919
624
624
  scout/server/blueprints/variants/views.py,sha256=skUGpZyRDzW4BEDIqWKajHBLF3qBUSP-UYSZYxbv3l8,28895
625
625
  scout/server/blueprints/variants/static/form_scripts.js,sha256=o3GCboaesA9Sm1HgejS_yQwt0I-NTkvcl56jiBdLqZs,8319
626
626
  scout/server/blueprints/variants/templates/variants/cancer-sv-variants.html,sha256=rLASILYRFwTIA3S0WtfN3QS7JbL_VvXKYJOoa-1yQJQ,7389
627
- scout/server/blueprints/variants/templates/variants/cancer-variants.html,sha256=6t1ZKUm2f6l5NJKDQvo9RBc4DBZgkWBXiePoIFkm6OY,9789
627
+ scout/server/blueprints/variants/templates/variants/cancer-variants.html,sha256=CTZyD1nne-w8EwcO6_ugnS6eMndLAzomlCNKJ1MM6VU,9796
628
628
  scout/server/blueprints/variants/templates/variants/components.html,sha256=xXa0ndN42htflWDYsbKhMwIYdk8hBJ0znyinVfLCU2o,17815
629
629
  scout/server/blueprints/variants/templates/variants/fusion-variants.html,sha256=XGaLgWobzeFHwyQLXr_Yq9THssf8tGU91VbFKdGOFBg,4801
630
630
  scout/server/blueprints/variants/templates/variants/indicators.html,sha256=BX6Wg8OpsALCGGozR1eXT57D0Ixrf-OFXVg6G20Wjr0,4400
631
631
  scout/server/blueprints/variants/templates/variants/mei-variants.html,sha256=2Tb0vfzM--kJa5mVbT7L32h4E8nKYRSb245g6O5JIUU,5860
632
632
  scout/server/blueprints/variants/templates/variants/str-variants.html,sha256=bjjeyoEO1aScqIDLtCh3xexZfvf1906yusPGJTyeNLU,10644
633
633
  scout/server/blueprints/variants/templates/variants/sv-variants.html,sha256=V_3hTZXmI_VEcQ6DpxVrTYnM3cBDGWtPri8cDVIsR9A,6153
634
- scout/server/blueprints/variants/templates/variants/utils.html,sha256=3jixwVolEzf7-mmV8e7AgDLoMrQlJfucKa877FF5SUg,50042
634
+ scout/server/blueprints/variants/templates/variants/utils.html,sha256=MNDc2JwumU9ukISizSAraxIY06rHXR2Ze32RNnDEBI4,50042
635
635
  scout/server/blueprints/variants/templates/variants/variants.html,sha256=KnCcsA1VaRdsbRCCw9Rg0TJTUvq03X9S24QgCqVToUk,9328
636
636
  scout/server/extensions/__init__.py,sha256=s6qkGSFNRi_tP7yoeoXB5UarvLHidaK1Yw2Pae7Py90,1366
637
637
  scout/server/extensions/beacon_extension.py,sha256=YDXQQl5kFcsA4OFHDMVurIKLw_3Gl6yWfcy3lYHl9RE,9904
@@ -644,7 +644,7 @@ scout/server/extensions/ldap_extension.py,sha256=nVgJ6YhSyvpg8J4bSYzJwoEvKhP0faW
644
644
  scout/server/extensions/loqus_extension.py,sha256=uiqUXQ7Q7DCj6C20TKgL8yLu9DXov95vrJfhq0tvbTM,12602
645
645
  scout/server/extensions/matchmaker_extension.py,sha256=mNytCYnZX1hgdq1otkvnyOkh4dj9SVgQthJAfKb8TMI,5024
646
646
  scout/server/extensions/mongo_extension.py,sha256=bKB0K5ibp-BWynOTgzBJd5qIYO0S9zRtEyDUw7EoxSQ,1029
647
- scout/server/extensions/panelapp_extension.py,sha256=UoPFGKqXJtAfbw3WRTxvHZweNI4jVgYgrhWkgVJouRo,2732
647
+ scout/server/extensions/panelapp_extension.py,sha256=UnHhyG7iSMy3ERQg5Sl3DOkmKjsLPgAEfPkzlfn2BrY,2738
648
648
  scout/server/extensions/phenopacket_extension.py,sha256=kcEUIOSfkQAlAmUm07hQS1BeUjeN4lBc-InvaNtbFxo,7295
649
649
  scout/server/extensions/rerunner_extension.py,sha256=SEwQi5BZR5X70BoD0U7TfyGgGv2WbJbas0v1efuv_r8,1104
650
650
  scout/server/static/bs_styles.css,sha256=Y7aq8Es3NHj1OaLPX0eiY5485C8gENptpuYmf7W3o1w,6421
@@ -677,9 +677,9 @@ scout/utils/md5.py,sha256=KkgdxOf7xbF9AF40ZjQKCgWaxFWJ9tp9RKjd8SU6IoA,649
677
677
  scout/utils/scout_requests.py,sha256=lgPumNI_EikBZR1m9ztZI_mZAfV29y1KGoiBv9kejzQ,12797
678
678
  scout/utils/sort.py,sha256=1AcbeZ6vdt_UXM3BLDBa3aQmN4qxrqtskxwD19oBhvw,756
679
679
  scout/utils/track_resources.py,sha256=eUjSEe-Ff8BIb4BHPC_COkJocQO2PaWueiPz1GAuiwY,2614
680
- scout_browser-4.91.1.dist-info/LICENSE,sha256=TM1Y9Cqbwk55JVfxD-_bpGLtZQAeN9RovQlqHK6eOTY,1485
681
- scout_browser-4.91.1.dist-info/METADATA,sha256=b8Nefs04nnQtwP5Auh5mCb4ZMX909osa6b7rnp9iEkU,14262
682
- scout_browser-4.91.1.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
683
- scout_browser-4.91.1.dist-info/entry_points.txt,sha256=q_mxFwbMFTwXRDDIRVcqKram2ubMVmvs3CSNvZri1nY,45
684
- scout_browser-4.91.1.dist-info/top_level.txt,sha256=qM75h71bztMaLYsxn1up4c_n2rjc_ZnyaW6Q0K5uOXc,6
685
- scout_browser-4.91.1.dist-info/RECORD,,
680
+ scout_browser-4.92.dist-info/LICENSE,sha256=TM1Y9Cqbwk55JVfxD-_bpGLtZQAeN9RovQlqHK6eOTY,1485
681
+ scout_browser-4.92.dist-info/METADATA,sha256=Z78U2w0_9MMsAmsc1pLdjEAkA2k2J06aUwZ2R6VIbJM,14260
682
+ scout_browser-4.92.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
683
+ scout_browser-4.92.dist-info/entry_points.txt,sha256=q_mxFwbMFTwXRDDIRVcqKram2ubMVmvs3CSNvZri1nY,45
684
+ scout_browser-4.92.dist-info/top_level.txt,sha256=qM75h71bztMaLYsxn1up4c_n2rjc_ZnyaW6Q0K5uOXc,6
685
+ scout_browser-4.92.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.45.0)
2
+ Generator: bdist_wheel (0.45.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5