scout-browser 4.101.0__py3-none-any.whl → 4.102.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.
Files changed (45) hide show
  1. scout/adapter/mongo/clinvar.py +7 -7
  2. scout/adapter/mongo/hgnc.py +7 -2
  3. scout/adapter/mongo/omics_variant.py +8 -0
  4. scout/adapter/mongo/variant_loader.py +6 -2
  5. scout/constants/__init__.py +1 -0
  6. scout/constants/igv_tracks.py +6 -2
  7. scout/constants/phenotype.py +1 -0
  8. scout/load/hpo.py +8 -2
  9. scout/server/blueprints/alignviewers/controllers.py +8 -6
  10. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +2 -0
  11. scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
  12. scout/server/blueprints/cases/controllers.py +56 -28
  13. scout/server/blueprints/cases/templates/cases/case_report.html +9 -88
  14. scout/server/blueprints/cases/templates/cases/matchmaker.html +1 -1
  15. scout/server/blueprints/cases/templates/cases/phenotype.html +1 -1
  16. scout/server/blueprints/cases/templates/cases/utils.html +26 -24
  17. scout/server/blueprints/cases/views.py +32 -33
  18. scout/server/blueprints/clinvar/controllers.py +3 -2
  19. scout/server/blueprints/diagnoses/controllers.py +4 -8
  20. scout/server/blueprints/diagnoses/templates/diagnoses/diagnoses.html +1 -1
  21. scout/server/blueprints/diagnoses/templates/diagnoses/disease_term.html +1 -1
  22. scout/server/blueprints/diagnoses/views.py +2 -2
  23. scout/server/blueprints/institutes/controllers.py +107 -73
  24. scout/server/blueprints/institutes/templates/overview/cases.html +1 -1
  25. scout/server/blueprints/login/controllers.py +2 -1
  26. scout/server/blueprints/login/views.py +5 -2
  27. scout/server/blueprints/omics_variants/views.py +2 -2
  28. scout/server/blueprints/phenotypes/controllers.py +15 -2
  29. scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +1 -1
  30. scout/server/blueprints/variant/controllers.py +10 -11
  31. scout/server/blueprints/variant/templates/variant/utils.html +1 -1
  32. scout/server/blueprints/variant/templates/variant/variant_details.html +68 -60
  33. scout/server/blueprints/variant/utils.py +25 -0
  34. scout/server/blueprints/variants/controllers.py +11 -42
  35. scout/server/blueprints/variants/views.py +9 -8
  36. scout/server/config.py +3 -0
  37. scout/server/extensions/beacon_extension.py +7 -2
  38. scout/server/templates/bootstrap_global.html +11 -1
  39. scout/server/templates/layout.html +6 -1
  40. scout/server/utils.py +24 -3
  41. {scout_browser-4.101.0.dist-info → scout_browser-4.102.0.dist-info}/METADATA +1 -1
  42. {scout_browser-4.101.0.dist-info → scout_browser-4.102.0.dist-info}/RECORD +45 -45
  43. {scout_browser-4.101.0.dist-info → scout_browser-4.102.0.dist-info}/WHEEL +0 -0
  44. {scout_browser-4.101.0.dist-info → scout_browser-4.102.0.dist-info}/entry_points.txt +0 -0
  45. {scout_browser-4.101.0.dist-info → scout_browser-4.102.0.dist-info}/licenses/LICENSE +0 -0
@@ -13,7 +13,7 @@ from flask import (
13
13
  session,
14
14
  url_for,
15
15
  )
16
- from flask_login import login_user, logout_user
16
+ from flask_login import logout_user
17
17
 
18
18
  from scout.server.extensions import login_manager, oauth_client, store
19
19
  from scout.server.utils import public_endpoint
@@ -102,11 +102,14 @@ def authorized():
102
102
 
103
103
  @login_bp.route("/logout")
104
104
  def logout():
105
+ session.pop("email", None)
106
+ session.pop("name", None)
107
+ session.pop("locale", None)
108
+ session.pop("consent_given", None)
105
109
  logout_user() # logs out user from scout
106
110
  for provider in ["GOOGLE", "KEYCLOAK"]:
107
111
  if current_app.config.get(provider):
108
112
  controllers.logout_oidc_user(session, provider)
109
- session.clear()
110
113
  flash("you logged out", "success")
111
114
  return redirect(url_for("public.index"))
112
115
 
@@ -17,7 +17,7 @@ from scout.server.blueprints.variants.controllers import (
17
17
  )
18
18
  from scout.server.blueprints.variants.forms import OutlierFiltersForm
19
19
  from scout.server.extensions import store
20
- from scout.server.utils import institute_and_case, templated
20
+ from scout.server.utils import get_case_genome_build, institute_and_case, templated
21
21
 
22
22
  from . import controllers
23
23
 
@@ -71,7 +71,7 @@ def outliers(institute_id, case_name):
71
71
  # Populate chromosome select choices
72
72
  populate_chrom_choices(form, case_obj)
73
73
 
74
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
74
+ genome_build = get_case_genome_build(case_obj)
75
75
  cytobands = store.cytoband_by_chrom(genome_build)
76
76
 
77
77
  update_form_hgnc_symbols(store, case_obj, form)
@@ -1,7 +1,17 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from typing import Optional
3
4
 
4
- def hpo_terms(store, query=None, limit=None, page=None):
5
+ from scout.adapter import MongoAdapter
6
+ from scout.constants import HPO_LINK_URL
7
+
8
+
9
+ def hpo_terms(
10
+ store: MongoAdapter,
11
+ query: Optional[str] = None,
12
+ limit: Optional[str] = None,
13
+ page: Optional[str] = None,
14
+ ) -> dict:
5
15
  """Retrieves a list of HPO terms from scout database
6
16
 
7
17
  Args:
@@ -29,4 +39,7 @@ def hpo_terms(store, query=None, limit=None, page=None):
29
39
  hpo_phenotypes["phenotypes"] = list(store.hpo_terms(query=query, limit=limit, skip=skip))
30
40
  else:
31
41
  hpo_phenotypes["phenotypes"] = list(store.hpo_terms(limit=limit, skip=skip))
32
- return hpo_phenotypes
42
+
43
+ data = hpo_phenotypes
44
+ data["hpo_link_url"] = HPO_LINK_URL
45
+ return data
@@ -34,7 +34,7 @@
34
34
  </thead>
35
35
  {% for pheno in phenotypes %}
36
36
  <tr>
37
- <td><a href="http://hpo.jax.org/app/browse/term/{{pheno.hpo_id}}" referrerpolicy="no-referrer" target="_blank">{{ pheno.hpo_id }}</a></td>
37
+ <td><a href="{{hpo_link_url}}{{pheno.hpo_id}}" referrerpolicy="no-referrer" target="_blank">{{ pheno.hpo_id }}</a></td>
38
38
  <td><span class="text-body">{{ pheno.description }}</span></td>
39
39
  <td><span class="text-body">{{pheno.genes|length}}</span></td>
40
40
  </tr>
@@ -28,6 +28,7 @@ from scout.constants import (
28
28
  VERBS_MAP,
29
29
  )
30
30
  from scout.server.blueprints.variant.utils import (
31
+ get_str_mc,
31
32
  update_representative_gene,
32
33
  update_variant_case_panels,
33
34
  )
@@ -40,6 +41,7 @@ from scout.server.utils import (
40
41
  case_has_chanjo_coverage,
41
42
  case_has_mt_alignments,
42
43
  case_has_rna_tracks,
44
+ get_case_genome_build,
43
45
  user_institutes,
44
46
  variant_institute_and_case,
45
47
  )
@@ -232,9 +234,7 @@ def variant(
232
234
 
233
235
  variant_id = variant_obj["variant_id"]
234
236
 
235
- genome_build = str(case_obj.get("genome_build", "37"))
236
- if genome_build not in ["37", "38"]:
237
- genome_build = "37"
237
+ genome_build = get_case_genome_build(case_obj)
238
238
 
239
239
  # is variant located on the mitochondria
240
240
  variant_obj["is_mitochondrial"] = any(
@@ -314,6 +314,9 @@ def variant(
314
314
 
315
315
  variant_obj["end_position"] = end_position(variant_obj)
316
316
 
317
+ # common motif count for STR variants
318
+ variant_obj["str_mc"] = get_str_mc(variant_obj)
319
+
317
320
  # Add general variant links
318
321
  variant_obj.update(get_variant_links(institute_obj, variant_obj, int(genome_build)))
319
322
  variant_obj["frequencies"] = frequencies(variant_obj)
@@ -425,9 +428,7 @@ def get_gene_has_full_coverage(institute_obj, case_obj, variant_obj) -> Dict[int
425
428
  if not case_obj.get("chanjo2_coverage"):
426
429
  return {}
427
430
 
428
- genome_build = str(case_obj.get("genome_build", "37"))
429
- if genome_build not in ["37", "38"]:
430
- genome_build = "37"
431
+ genome_build = get_case_genome_build(case_obj)
431
432
 
432
433
  gene_has_full_coverage: dict = {
433
434
  hgnc_id: chanjo2.get_gene_complete_coverage(
@@ -436,7 +437,7 @@ def get_gene_has_full_coverage(institute_obj, case_obj, variant_obj) -> Dict[int
436
437
  individuals=case_obj.get("individuals"),
437
438
  build=genome_build,
438
439
  )
439
- for hgnc_id in [gene.get("hgnc_id") for gene in variant_obj.get("genes")]
440
+ for hgnc_id in [gene.get("hgnc_id") for gene in variant_obj.get("genes", [])]
440
441
  }
441
442
  return gene_has_full_coverage
442
443
 
@@ -555,7 +556,7 @@ def observations(store: MongoAdapter, loqusdb: LoqusDB, variant_obj: dict) -> Di
555
556
  f"Could not find a Loqus instance with id:{loqus_id}",
556
557
  "warning",
557
558
  )
558
- obs_data[loqus_id]["observations"] = "N/A"
559
+ obs_data[loqus_id] = {"observations": "N/A"}
559
560
  continue
560
561
 
561
562
  if obs_data[loqus_id] == {}: # Variant was not found
@@ -656,9 +657,7 @@ def variant_acmg(store: MongoAdapter, institute_id: str, case_name: str, variant
656
657
  store, variant_obj, institute_id, case_name
657
658
  )
658
659
 
659
- genome_build = str(case_obj.get("genome_build", "37"))
660
- if genome_build not in ["37", "38"]:
661
- genome_build = "37"
660
+ genome_build = get_case_genome_build(case_obj)
662
661
 
663
662
  add_gene_info(store, variant_obj, genome_build=genome_build)
664
663
 
@@ -396,7 +396,7 @@
396
396
  <div class="col-1">
397
397
  <!--Define build variable to be used in the UCSC link-->
398
398
  {% set build = "hg19" %}
399
- {% if case.genome_build == 38 or variant.chromosome == "MT" %}
399
+ {% if case.genome_build == "38" or variant.chromosome == "MT" %}
400
400
  {% set build = "hg38" %}
401
401
  {% endif %}
402
402
 
@@ -164,38 +164,42 @@
164
164
  </div>
165
165
  {% endmacro %}
166
166
 
167
+ {% macro frequencies_table(variant) %}
168
+ <table class="table table-sm align-middle mb-1" style="font-size: 0.875rem;">
169
+ <thead class="table-light">
170
+ <tr>
171
+ <th scope="col" class="py-1 px-2">Source</th>
172
+ <th scope="col" class="py-1 px-2">Frequency</th>
173
+ </tr>
174
+ </thead>
175
+ <tbody>
176
+ {% for freq_name, value, link in variant.frequencies %}
177
+ <tr>
178
+ <td class="py-1 px-2">
179
+ {% if link %}
180
+ <a href="{{ link }}" target="_blank" rel="noopener" referrerpolicy="no-referrer">{{ freq_name }}</a>
181
+ {% else %}
182
+ {{ freq_name }}
183
+ {% endif %}
184
+ </td>
185
+ <td class="py-1 px-2">
186
+ {% if value %}
187
+ <span class="badge bg-secondary" style="font-size: 0.75rem;">{{ value|human_decimal }}</span>
188
+ {% else %}
189
+ -
190
+ {% endif %}
191
+ </td>
192
+ </tr>
193
+ {% endfor %}
194
+ </tbody>
195
+ </table>
196
+ {% endmacro %}
197
+
167
198
  {% macro frequencies(variant) %}
168
199
  <div class="card panel-default">
169
200
  <div class="panel-heading">Frequencies</div>
170
201
  <div class="card-body">
171
- <table class="table">
172
- <thead class="thead table-light">
173
- <tr>
174
- <th scope="col">Source</th>
175
- <th scope="col">Frequency</th>
176
- </tr>
177
- </thead>
178
- <tbody>
179
- {% for freq_name, value, link in variant.frequencies %}
180
- <tr>
181
- <td>
182
- {% if link %}
183
- <a href="{{ link }}" target="_blank" rel="noopener" referrerpolicy="no-referrer">{{ freq_name }}</a>
184
- {% else %}
185
- {{ freq_name }}
186
- {% endif %}
187
- </td>
188
- <td>
189
- {% if value %}
190
- <span class="badge bg-secondary">{{ value|human_decimal }}</span>
191
- {% else %}
192
- -
193
- {% endif %}
194
- </td>
195
- </tr>
196
- {% endfor %}
197
- </tbody>
198
- </table>
202
+ {{ frequencies_table(variant) }}
199
203
  </div>
200
204
  </div>
201
205
  {% endmacro %}
@@ -282,6 +286,41 @@
282
286
  </div>
283
287
  {% endmacro %}
284
288
 
289
+ {% macro old_observations_table(variant) %}
290
+ <table class="table">
291
+ <thead class="thead table-light">
292
+ <tr>
293
+ <th scope="col">Local archive</th>
294
+ <th scope="col">Nr obs.</th>
295
+ <th scope="col">Nr homo.</th>
296
+ <th scope="col">Frequency</th>
297
+ </tr>
298
+ </thead>
299
+ <tbody>
300
+ <tr>
301
+ <td>RD</td>
302
+ <td>{{ variant.local_obs_old|default('N/A') }}</td>
303
+ <td>{{ variant.local_obs_hom_old|default('N/A') }}</td>
304
+ <td>{% if variant.local_obs_old_freq %} {{variant.local_obs_old_freq|round(6)}} {% elif variant.local_obs_old_nr_cases and variant.local_obs_old %} {{ (variant.local_obs_old/variant.local_obs_old_nr_cases)|round(5) }} {% elif variant.local_obs_old_nr_cases %} 0 / {{variant.local_obs_old_nr_cases}} {% else %} N/A {% endif %}</td>
305
+ </tr>
306
+ {% if variant.category in ['cancer', 'cancer_sv'] %}
307
+ <tr>
308
+ <td>Cancer Germline</td>
309
+ <td>{{ variant.local_obs_cancer_germline_old|default('N/A') }}</td>
310
+ <td>{{ variant.local_obs_cancer_germline_hom_old|default('N/A') }}</td>
311
+ <td>{% if variant.local_obs_cancer_germline_old_freq %} {{variant.local_obs_cancer_germline_old_freq|round(6)}} {% elif variant.local_obs_cancer_germline_old_nr_cases and variant.local_obs_cancer_germline_old %} {{ (variant.local_obs_cancer_germline_old/variant.local_obs_cancer_germline_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_germline_old_nr_cases %} 0 / {{variant.local_obs_cancer_germline_old_nr_cases}} {% else %} N/A {% endif %}</td>
312
+ </tr>
313
+ <tr>
314
+ <td>Cancer Somatic</td>
315
+ <td>{{ variant.local_obs_cancer_somatic_old|default('N/A') }}</td>
316
+ <td>{{ variant.local_obs_cancer_somatic_hom_old|default('N/A') }}</td>
317
+ <td>{% if variant.local_obs_cancer_somatic_old_freq %} {{variant.local_obs_cancer_somatic_old_freq|round(6)}} {% elif variant.local_obs_cancer_somatic_old_nr_cases and variant.local_obs_cancer_somatic_old %} {{ (variant.local_obs_cancer_somatic_old/variant.local_obs_cancer_somatic_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_somatic_old_nr_cases %} 0 / {{variant.local_obs_cancer_somatic_old_nr_cases}} {% else %} N/A {% endif %}</td>
318
+ </tr>
319
+ {% endif %}
320
+ </tbody>
321
+ </table>
322
+ {% endmacro %}
323
+
285
324
  {% macro old_observations(variant, obs_date) %}
286
325
  {% if "SHOW_OBSERVED_VARIANT_ARCHIVE" in config and config["SHOW_OBSERVED_VARIANT_ARCHIVE"] == true %}
287
326
  <div class="card panel-default">
@@ -289,38 +328,7 @@
289
328
  <a href="https://github.com/moonso/loqusdb" target="_blank" data-bs-toggle="tooltip" title="Local observations annotated from an archive copy of the loqusdb local frequency database. Only variants above a quality threshold are included, and each case is included only once. {% if variant.local_obs_old_desc %} {{variant.local_obs_old_desc}} {% endif %}">Local observations (archive {{ obs_date or variant.local_obs_old_date or "version"}})</a>
290
329
  </div>
291
330
  <div class="card-body">
292
- <table class="table">
293
- <thead class="thead table-light">
294
- <tr>
295
- <th scope="col">Archive</th>
296
- <th scope="col">Nr obs.</th>
297
- <th scope="col">Nr homo.</th>
298
- <th scope="col">Frequency</th>
299
- </tr>
300
- </thead>
301
- <tbody>
302
- <tr>
303
- <td>RD</td>
304
- <td>{{ variant.local_obs_old|default('N/A') }}</td>
305
- <td>{{ variant.local_obs_hom_old|default('N/A') }}</td>
306
- <td>{% if variant.local_obs_old_freq %} {{variant.local_obs_old_freq|round(6)}} {% elif variant.local_obs_old_nr_cases and variant.local_obs_old %} {{ (variant.local_obs_old/variant.local_obs_old_nr_cases)|round(5) }} {% elif variant.local_obs_old_nr_cases %} 0 / {{variant.local_obs_old_nr_cases}} {% else %} N/A {% endif %}</td>
307
- </tr>
308
- {% if variant.category in ['cancer', 'cancer_sv'] %}
309
- <tr>
310
- <td>Cancer Germline</td>
311
- <td>{{ variant.local_obs_cancer_germline_old|default('N/A') }}</td>
312
- <td>{{ variant.local_obs_cancer_germline_hom_old|default('N/A') }}</td>
313
- <td>{% if variant.local_obs_cancer_germline_old_freq %} {{variant.local_obs_cancer_germline_old_freq|round(6)}} {% elif variant.local_obs_cancer_germline_old_nr_cases and variant.local_obs_cancer_germline_old %} {{ (variant.local_obs_cancer_germline_old/variant.local_obs_cancer_germline_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_germline_old_nr_cases %} 0 / {{variant.local_obs_cancer_germline_old_nr_cases}} {% else %} N/A {% endif %}</td>
314
- </tr>
315
- <tr>
316
- <td>Cancer Somatic</td>
317
- <td>{{ variant.local_obs_cancer_somatic_old|default('N/A') }}</td>
318
- <td>{{ variant.local_obs_cancer_somatic_hom_old|default('N/A') }}</td>
319
- <td>{% if variant.local_obs_cancer_somatic_old_freq %} {{variant.local_obs_cancer_somatic_old_freq|round(6)}} {% elif variant.local_obs_cancer_somatic_old_nr_cases and variant.local_obs_cancer_somatic_old %} {{ (variant.local_obs_cancer_somatic_old/variant.local_obs_cancer_somatic_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_somatic_old_nr_cases %} 0 / {{variant.local_obs_cancer_somatic_old_nr_cases}} {% else %} N/A {% endif %}</td>
320
- </tr>
321
- {% endif %}
322
- </tbody>
323
- </table>
331
+ {{ old_observations_table(variant) }}
324
332
  </div>
325
333
  </div>
326
334
  {% endif %}
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import re
2
3
  from typing import Dict, List, Optional, Tuple
3
4
 
4
5
  from scout.adapter import MongoAdapter
@@ -683,3 +684,27 @@ def associate_variant_genes_with_case_panels(case_obj: Dict, variant_obj: Dict)
683
684
  geneid_gene[hgnc_id]["associated_gene_panels"] = matching_panels
684
685
 
685
686
  variant_obj["genes"] = list(geneid_gene.values())
687
+
688
+
689
+ def get_str_mc(variant_obj: dict) -> Optional[int]:
690
+ """Return variant Short Tandem Repeat motif count, either as given by its ALT MC value
691
+ from the variant FORMAT field, or as a number given in the ALT on the form
692
+ '<STR123>'.
693
+ """
694
+ NUM = re.compile(r"\d+")
695
+
696
+ alt_mc = None
697
+ if variant_obj["alternative"] == ".":
698
+ return alt_mc
699
+
700
+ for sample in variant_obj["samples"]:
701
+ if sample["genotype_call"] in ["./.", ".|", "0/0", "0|0"]:
702
+ continue
703
+ alt_mc = sample.get("alt_mc")
704
+ if alt_mc:
705
+ return alt_mc
706
+
707
+ alt_num = NUM.search(variant_obj["alternative"])
708
+ if alt_num:
709
+ alt_mc = int(alt_num.group())
710
+ return alt_mc
@@ -35,6 +35,7 @@ from scout.server.blueprints.variant.utils import (
35
35
  clinsig_human,
36
36
  get_callers,
37
37
  get_filters,
38
+ get_str_mc,
38
39
  predictions,
39
40
  update_representative_gene,
40
41
  update_variant_case_panels,
@@ -45,6 +46,7 @@ from scout.server.links import add_gene_links, cosmic_links, str_source_link
45
46
  from scout.server.utils import (
46
47
  case_has_alignments,
47
48
  case_has_mt_alignments,
49
+ get_case_genome_build,
48
50
  institute_and_case,
49
51
  user_institutes,
50
52
  )
@@ -57,8 +59,6 @@ from .forms import (
57
59
  )
58
60
  from .utils import update_case_panels
59
61
 
60
- NUM = re.compile(r"\d+")
61
-
62
62
  LOG = logging.getLogger(__name__)
63
63
 
64
64
 
@@ -106,7 +106,7 @@ def populate_persistent_filters_choices(
106
106
  def populate_chrom_choices(form, case_obj):
107
107
  """Populate the option of the chromosome select according to the case genome build"""
108
108
  # Populate chromosome choices
109
- chromosomes = CHROMOSOMES if "37" in str(case_obj.get("genome_build")) else CHROMOSOMES_38
109
+ chromosomes = CHROMOSOMES if get_case_genome_build(case_obj) == "37" else CHROMOSOMES_38
110
110
  form.chrom.choices = [(chrom, chrom) for chrom in chromosomes]
111
111
 
112
112
 
@@ -139,9 +139,7 @@ def variants(
139
139
  more_variants = variant_count > (skip_count + per_page)
140
140
  variant_res = variants_query.skip(skip_count).limit(per_page)
141
141
 
142
- genome_build = str(case_obj.get("genome_build", "37"))
143
- if genome_build not in ["37", "38"]:
144
- genome_build = "37"
142
+ genome_build = get_case_genome_build(case_obj)
145
143
 
146
144
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
147
145
 
@@ -237,9 +235,7 @@ def sv_variants(store, institute_obj, case_obj, variants_query, variant_count, p
237
235
 
238
236
  more_variants = variant_count > (skip_count + per_page)
239
237
  variants = []
240
- genome_build = str(case_obj.get("genome_build", "37"))
241
- if genome_build not in ["37", "38"]:
242
- genome_build = "37"
238
+ genome_build = get_case_genome_build(case_obj)
243
239
 
244
240
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
245
241
 
@@ -285,9 +281,7 @@ def mei_variants(
285
281
 
286
282
  more_variants = variant_count > (skip_count + per_page)
287
283
  variants = []
288
- genome_build = str(case_obj.get("genome_build", "37"))
289
- if genome_build not in ["37", "38"]:
290
- genome_build = "37"
284
+ genome_build = get_case_genome_build(case_obj)
291
285
 
292
286
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
293
287
 
@@ -353,9 +347,7 @@ def fusion_variants(
353
347
 
354
348
  more_variants = variant_count > (skip_count + per_page)
355
349
  variants = []
356
- genome_build = str(case_obj.get("genome_build", "38"))
357
- if genome_build not in ["37", "38"]:
358
- genome_build = "38"
350
+ genome_build = get_case_genome_build(case_obj)
359
351
 
360
352
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
361
353
 
@@ -997,28 +989,6 @@ def parse_variant(
997
989
  return variant_obj
998
990
 
999
991
 
1000
- def get_str_mc(variant_obj: dict) -> Optional[int]:
1001
- """Return variant Short Tandem Repeat motif count, either as given by its ALT MC value
1002
- from the variant FORMAT field, or as a number given in the ALT on the form
1003
- '<STR123>'.
1004
- """
1005
- alt_mc = None
1006
- if variant_obj["alternative"] == ".":
1007
- return alt_mc
1008
-
1009
- for sample in variant_obj["samples"]:
1010
- if sample["genotype_call"] in ["./.", ".|", "0/0", "0|0"]:
1011
- continue
1012
- alt_mc = sample.get("alt_mc")
1013
- if alt_mc:
1014
- return alt_mc
1015
-
1016
- alt_num = NUM.search(variant_obj["alternative"])
1017
- if alt_num:
1018
- alt_mc = int(alt_num.group())
1019
- return alt_mc
1020
-
1021
-
1022
992
  def download_str_variants(case_obj, variant_objs):
1023
993
  """Download filtered STR variants for a case to a CSV file
1024
994
 
@@ -1502,7 +1472,9 @@ def upload_panel(store, institute_id, case_name, stream):
1502
1472
  hgnc_symbols = set()
1503
1473
  for raw_symbol in raw_symbols:
1504
1474
  matching_genes = list(
1505
- store.gene_by_symbol_or_aliases(symbol=raw_symbol, build=case_obj.get("genome_build"))
1475
+ store.gene_by_symbol_or_aliases(
1476
+ symbol=raw_symbol, build=get_case_genome_build(case_obj)
1477
+ )
1506
1478
  )
1507
1479
  if not matching_genes:
1508
1480
  flash("HGNC symbol not found: {}".format(raw_symbol), "warning")
@@ -1983,10 +1955,7 @@ def update_form_hgnc_symbols(store, case_obj, form):
1983
1955
  genome_build = None
1984
1956
  case_obj = case_obj or {}
1985
1957
 
1986
- for build in ["37", "38"]:
1987
- if build in str(case_obj.get("genome_build", "")):
1988
- genome_build = build
1989
- break
1958
+ genome_build = get_case_genome_build(case_obj)
1990
1959
 
1991
1960
  # retrieve current symbols from form
1992
1961
  if form.hgnc_symbols.data:
@@ -19,7 +19,7 @@ from scout.constants import (
19
19
  SEVERE_SO_TERMS_SV,
20
20
  )
21
21
  from scout.server.extensions import store
22
- from scout.server.utils import institute_and_case, templated
22
+ from scout.server.utils import get_case_genome_build, institute_and_case, templated
23
23
 
24
24
  from . import controllers
25
25
  from .forms import (
@@ -129,7 +129,7 @@ def variants(institute_id, case_name):
129
129
 
130
130
  controllers.update_form_hgnc_symbols(store, case_obj, form)
131
131
 
132
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
132
+ genome_build = get_case_genome_build(case_obj)
133
133
  cytobands = store.cytoband_by_chrom(genome_build)
134
134
 
135
135
  variants_query = store.variants(
@@ -220,7 +220,7 @@ def str_variants(institute_id, case_name):
220
220
 
221
221
  controllers.activate_case(store, institute_obj, case_obj, current_user)
222
222
 
223
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
223
+ genome_build = get_case_genome_build(case_obj)
224
224
  cytobands = store.cytoband_by_chrom(genome_build)
225
225
 
226
226
  query = form.data
@@ -231,6 +231,7 @@ def str_variants(institute_id, case_name):
231
231
  ).sort(
232
232
  [
233
233
  ("str_repid", pymongo.ASCENDING),
234
+ ("str_trid", pymongo.ASCENDING),
234
235
  ("chromosome", pymongo.ASCENDING),
235
236
  ("position", pymongo.ASCENDING),
236
237
  ]
@@ -302,7 +303,7 @@ def sv_variants(institute_id, case_name):
302
303
  # Populate custom soft filters
303
304
  controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
304
305
 
305
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
306
+ genome_build = get_case_genome_build(case_obj)
306
307
  cytobands = store.cytoband_by_chrom(genome_build)
307
308
 
308
309
  controllers.update_form_hgnc_symbols(store, case_obj, form)
@@ -397,7 +398,7 @@ def mei_variants(institute_id, case_name):
397
398
  # populate available panel choices
398
399
  form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj)
399
400
 
400
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
401
+ genome_build = get_case_genome_build(case_obj)
401
402
  cytobands = store.cytoband_by_chrom(genome_build)
402
403
 
403
404
  controllers.update_form_hgnc_symbols(store, case_obj, form)
@@ -509,7 +510,7 @@ def cancer_variants(institute_id, case_name):
509
510
 
510
511
  form.gene_panels.choices = controllers.gene_panel_choices(store, institute_obj, case_obj)
511
512
 
512
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
513
+ genome_build = get_case_genome_build(case_obj)
513
514
  cytobands = store.cytoband_by_chrom(genome_build)
514
515
 
515
516
  controllers.update_form_hgnc_symbols(store, case_obj, form)
@@ -587,7 +588,7 @@ def cancer_sv_variants(institute_id, case_name):
587
588
  # Populate custom soft filters
588
589
  controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
589
590
 
590
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
591
+ genome_build = get_case_genome_build(case_obj)
591
592
  cytobands = store.cytoband_by_chrom(genome_build)
592
593
 
593
594
  controllers.update_form_hgnc_symbols(store, case_obj, form)
@@ -671,7 +672,7 @@ def fusion_variants(institute_id, case_name):
671
672
  # Populate custom soft filters
672
673
  controllers.populate_institute_soft_filters(form=form, institute_obj=institute_obj)
673
674
 
674
- genome_build = "38" if "38" in str(case_obj.get("genome_build", "37")) else "37"
675
+ genome_build = get_case_genome_build(case_obj)
675
676
  cytobands = store.cytoband_by_chrom(genome_build)
676
677
 
677
678
  controllers.update_form_hgnc_symbols(store, case_obj, form)
scout/server/config.py CHANGED
@@ -1,6 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  SECRET_KEY = "this is not secret..."
3
3
  REMEMBER_COOKIE_NAME = "scout_remember_me" # Prevent session timeout when user closes browser
4
+ # INSTANCE_NAME = "Development" # Name will be displayed on the top navigation menu
5
+ # INSTANCE_COLOR = "#800000" # Color of the top navigation menu
6
+
4
7
  # SESSION_TIMEOUT_MINUTES = 60 # Minutes of inactivity before session times out
5
8
 
6
9
  # MONGO_URI = "mongodb://127.0.0.1:27011,127.0.0.1:27012,127.0.0.1:27013/?replicaSet=rs0&readPreference=primary"
@@ -8,7 +8,12 @@ import logging
8
8
  from flask import flash, url_for
9
9
  from flask_login import current_user
10
10
 
11
- from scout.utils.scout_requests import delete_request_json, get_request_json, post_request_json
11
+ from scout.server.utils import get_case_genome_build
12
+ from scout.utils.scout_requests import (
13
+ delete_request_json,
14
+ get_request_json,
15
+ post_request_json,
16
+ )
12
17
 
13
18
  LOG = logging.getLogger(__name__)
14
19
  DATASET_BUILDS = ["GRCh37", "GRCh38"]
@@ -58,7 +63,7 @@ class Beacon:
58
63
  data(dict): a dictionary with base info to be used as json data in beacon add request (lacks path to VCF file to extract variants from)
59
64
  """
60
65
  # Initialize key/values to be sent in request:
61
- assembly = "GRCh38" if "38" in str(case_obj.get("genome_build", "37")) else "GRCh37"
66
+ assembly = "GRCh38" if get_case_genome_build(case_obj) == "38" else "GRCh37"
62
67
  dataset_id = "_".join([case_obj["owner"], case_obj.get("build", assembly)])
63
68
 
64
69
  samples = []
@@ -12,7 +12,17 @@
12
12
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-dark.min.css" integrity="sha384-pZAJcuaxKZEGkzXV5bYqUcSwBfMZPdQS/+JXdYOu9ScyZJMnGHD5Xi6HVHfZuULH" crossorigin="anonymous">
13
13
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
14
14
  <link rel="stylesheet" href="{{ url_for('static', filename='bs_styles.css') }}">
15
- {% endblock %}
15
+
16
+ {% if config.INSTANCE_COLOR %}
17
+ <style>
18
+ /* Override Scout's bg-primary with color set on app config, if available */
19
+ nav.navbar.bg-primary {
20
+ background-color: {{ config.INSTANCE_COLOR }} !important;
21
+ }
22
+ </style>
23
+ {% endif %}
24
+
25
+ {% endblock %}
16
26
 
17
27
  {% block css_style %}
18
28
  {% endblock %}
@@ -18,9 +18,14 @@
18
18
 
19
19
  {% block navbar %}
20
20
  <nav class="navbar navbar-expand-lg nav-pills navbar-dark bg-primary sticky-top" >
21
- <div class="container-fluid bg-primary rounded-bottom">
21
+ <div class="container-fluid rounded-bottom">
22
22
  <a class="navbar-brand" href="{{ url_for('cases.index') }}">
23
23
  <img src="{{ url_for('public.static', filename='scout-logo.png') }}" width="30" height="30" class="d-inline-block align-top text-white" alt="">Scout</a>
24
+ {% if config.INSTANCE_NAME %}
25
+ <span class="badge bg-light text-dark">
26
+ {{ config.INSTANCE_NAME }}
27
+ </span>
28
+ {% endif %}
24
29
  <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
25
30
  <span class="navbar-toggler-icon"></span>
26
31
  </button>