scout-browser 4.84__py3-none-any.whl → 4.86__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 (85) hide show
  1. scout/__version__.py +1 -1
  2. scout/adapter/mongo/base.py +17 -14
  3. scout/adapter/mongo/case.py +20 -1
  4. scout/adapter/mongo/cytoband.py +13 -0
  5. scout/adapter/mongo/filter.py +36 -1
  6. scout/adapter/mongo/hgnc.py +1 -1
  7. scout/adapter/mongo/omics_variant.py +145 -0
  8. scout/adapter/mongo/query.py +13 -3
  9. scout/adapter/mongo/variant.py +10 -4
  10. scout/build/case.py +5 -0
  11. scout/build/variant/variant.py +1 -0
  12. scout/commands/update/genes.py +9 -13
  13. scout/constants/__init__.py +3 -1
  14. scout/constants/case_tags.py +1 -0
  15. scout/constants/clinvar.py +1 -1
  16. scout/constants/file_types.py +31 -0
  17. scout/constants/filters.py +4 -0
  18. scout/constants/indexes.py +30 -13
  19. scout/constants/variant_tags.py +3 -0
  20. scout/demo/643594.clinical.mei.vcf.gz +0 -0
  21. scout/demo/643594.clinical.mei.vcf.gz.tbi +0 -0
  22. scout/demo/643594.config.yaml +4 -0
  23. scout/demo/drop/fraser_top_hits_clinical.tsv +5 -0
  24. scout/demo/drop/outrider_top_hits_clinical.tsv +10 -0
  25. scout/load/hgnc_gene.py +39 -6
  26. scout/load/setup.py +4 -4
  27. scout/models/case/case_loading_models.py +25 -2
  28. scout/models/omics_variant.py +227 -0
  29. scout/parse/hgnc.py +1 -0
  30. scout/parse/omics_variant/__init__.py +11 -0
  31. scout/parse/omics_variant/drop.py +19 -0
  32. scout/parse/variant/callers.py +6 -3
  33. scout/parse/variant/frequency.py +10 -2
  34. scout/parse/variant/transcript.py +1 -1
  35. scout/parse/variant/variant.py +10 -4
  36. scout/server/app.py +4 -1
  37. scout/server/blueprints/alignviewers/controllers.py +35 -24
  38. scout/server/blueprints/alignviewers/templates/alignviewers/igv_sashimi_viewer.html +19 -15
  39. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +45 -5
  40. scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
  41. scout/server/blueprints/alignviewers/views.py +10 -2
  42. scout/server/blueprints/cases/controllers.py +18 -1
  43. scout/server/blueprints/cases/templates/cases/case.html +28 -10
  44. scout/server/blueprints/cases/templates/cases/case_report.html +2 -17
  45. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +1 -1
  46. scout/server/blueprints/cases/templates/cases/gene_panel.html +27 -41
  47. scout/server/blueprints/cases/templates/cases/phenotype.html +8 -5
  48. scout/server/blueprints/cases/templates/cases/utils.html +27 -4
  49. scout/server/blueprints/clinvar/controllers.py +9 -3
  50. scout/server/blueprints/dashboard/controllers.py +44 -13
  51. scout/server/blueprints/dashboard/static/charts.js +46 -36
  52. scout/server/blueprints/dashboard/templates/dashboard/dashboard_general.html +2 -2
  53. scout/server/blueprints/institutes/forms.py +2 -0
  54. scout/server/blueprints/institutes/templates/overview/cases.html +6 -4
  55. scout/server/blueprints/institutes/templates/overview/gene_variants.html +40 -27
  56. scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +1 -1
  57. scout/server/blueprints/institutes/views.py +5 -12
  58. scout/server/blueprints/omics_variants/__init__.py +1 -0
  59. scout/server/blueprints/omics_variants/controllers.py +122 -0
  60. scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +262 -0
  61. scout/server/blueprints/omics_variants/views.py +106 -0
  62. scout/server/blueprints/panels/controllers.py +1 -7
  63. scout/server/blueprints/panels/templates/panels/panels.html +12 -4
  64. scout/server/blueprints/panels/views.py +9 -11
  65. scout/server/blueprints/variant/templates/variant/buttons.html +7 -2
  66. scout/server/blueprints/variant/templates/variant/str-variant-reviewer.html +1 -1
  67. scout/server/blueprints/variant/templates/variant/utils.html +1 -1
  68. scout/server/blueprints/variant/utils.py +54 -103
  69. scout/server/blueprints/variant/views.py +1 -0
  70. scout/server/blueprints/variants/controllers.py +1 -4
  71. scout/server/blueprints/variants/forms.py +42 -0
  72. scout/server/blueprints/variants/templates/variants/utils.html +8 -4
  73. scout/server/blueprints/variants/views.py +28 -7
  74. scout/server/config.py +4 -0
  75. scout/server/extensions/clinvar_extension.py +7 -7
  76. scout/server/links.py +2 -2
  77. scout/server/templates/bootstrap_global.html +1 -4
  78. scout/server/templates/utils.html +4 -4
  79. scout/server/utils.py +4 -1
  80. {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/METADATA +11 -11
  81. {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/RECORD +85 -75
  82. {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/WHEEL +1 -1
  83. {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/LICENSE +0 -0
  84. {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/entry_points.txt +0 -0
  85. {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/top_level.txt +0 -0
@@ -100,7 +100,7 @@
100
100
  <div class="col-3">Show tracks:</div>
101
101
  <div class="col-6">
102
102
  <select name="user_tracks" class="selectpicker" data-width="90%" data-style="btn-secondary" multiple>
103
- {% for track in igv_tracks %}
103
+ {% for track in igv_tracks|sort %}
104
104
  <!--pre-select option if user has saved it in preferences or select all options if user has no preferences yet-->
105
105
  <option value="{{ track }}" {{ "selected" if current_user.igv_tracks and track in current_user.igv_tracks or current_user.igv_tracks is not defined }}>{{ track }}</option>
106
106
  {% endfor %}
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Dict, List, Optional
2
+ from typing import Dict, List, Optional, Tuple
3
3
 
4
4
  from scout.adapter import MongoAdapter
5
5
  from scout.constants import ACMG_COMPLETE_MAP, CALLERS, CLINSIG_MAP, SO_TERMS
@@ -333,122 +333,72 @@ def predictions(genes):
333
333
  return data
334
334
 
335
335
 
336
- def frequencies(variant_obj):
337
- """Add frequencies in the correct way for the template
338
-
339
- This function converts the raw annotations to something better to visualize.
340
- GnomAD is mandatory and will always be shown.
336
+ def frequencies(variant_obj: dict) -> list[Tuple]:
337
+ """Convert raw annotations to a more visual format with frequencies.
341
338
 
342
339
  Args:
343
340
  variant_obj(scout.models.Variant)
344
341
 
345
342
  Returns:
346
- frequencies(list(tuple)): A list of frequencies to display
343
+ list of tuple: A list of frequencies to display.
347
344
  """
348
345
  is_mitochondrial_variant = variant_obj.get("chromosome") == "MT"
346
+ category = variant_obj["category"]
347
+
348
+ # Define frequency mappings for each category
349
+ frequency_mappings = {
350
+ "sv": {
351
+ "gnomad_frequency": ("GnomAD", variant_obj.get("gnomad_sv_link")),
352
+ "clingen_cgh_benign": ("ClinGen CGH (benign)", None),
353
+ "clingen_cgh_pathogenic": ("ClinGen CGH (pathogenic)", None),
354
+ "clingen_ngi": ("ClinGen NGI", None),
355
+ "clingen_mip": ("ClinGen MIP", None),
356
+ "swegen": ("SweGen", None),
357
+ "decipher": ("Decipher", None),
358
+ "thousand_genomes_frequency": ("1000G", None),
359
+ "thousand_genomes_frequency_left": ("1000G(left)", None),
360
+ "thousand_genomes_frequency_right": ("1000G(right)", None),
361
+ "colorsdb_af": ("CoLoRSdb", None),
362
+ },
363
+ "mei": {
364
+ "swegen_alu": ("SweGen ALU", None),
365
+ "swegen_herv": ("SweGen HERV", None),
366
+ "swegen_l1": ("SweGen L1", None),
367
+ "swegen_sva": ("SweGen SVA", None),
368
+ "swegen_mei_max": ("SweGen MEI(max)", None),
369
+ },
370
+ "snv": {
371
+ "gnomad_frequency": ("GnomAD", variant_obj.get("gnomad_link")),
372
+ "thousand_genomes_frequency": ("1000G", variant_obj.get("thousandg_link")),
373
+ "max_thousand_genomes_frequency": ("1000G(max)", variant_obj.get("thousandg_link")),
374
+ "exac_frequency": ("ExAC", variant_obj.get("exac_link")),
375
+ "max_exac_frequency": ("ExAC(max)", variant_obj.get("exac_link")),
376
+ "swegen": ("SweGen", variant_obj.get("swegen_link")),
377
+ "gnomad_mt_homoplasmic_frequency": (
378
+ "GnomAD MT, homoplasmic",
379
+ variant_obj.get("gnomad_link"),
380
+ ),
381
+ "gnomad_mt_heteroplasmic_frequency": (
382
+ "GnomAD MT, heteroplasmic",
383
+ variant_obj.get("gnomad_link"),
384
+ ),
385
+ "colorsdb_af": ("CoLoRSdb", None),
386
+ },
387
+ }
388
+
389
+ # Select the appropriate frequency dictionary
390
+ freqs = frequency_mappings.get(category, frequency_mappings["snv"])
349
391
 
350
- if variant_obj["category"] == "sv":
351
- freqs = {
352
- "gnomad_frequency": {
353
- "display_name": "GnomAD",
354
- "link": variant_obj.get("gnomad_sv_link"),
355
- },
356
- "clingen_cgh_benign": {
357
- "display_name": "ClinGen CGH (benign)",
358
- "link": None,
359
- },
360
- "clingen_cgh_pathogenic": {
361
- "display_name": "ClinGen CGH (pathogenic)",
362
- "link": None,
363
- },
364
- "clingen_ngi": {"display_name": "ClinGen NGI", "link": None},
365
- "clingen_mip": {"display_name": "ClinGen MIP", "link": None},
366
- "swegen": {"display_name": "SweGen", "link": None},
367
- "decipher": {"display_name": "Decipher", "link": None},
368
- "thousand_genomes_frequency": {"display_name": "1000G", "link": None},
369
- "thousand_genomes_frequency_left": {
370
- "display_name": "1000G(left)",
371
- "link": None,
372
- },
373
- "thousand_genomes_frequency_right": {
374
- "display_name": "1000G(right)",
375
- "link": None,
376
- },
377
- }
378
- elif variant_obj["category"] == "mei":
379
- freqs = {
380
- "swegen_alu": {
381
- "display_name": "SweGen ALU",
382
- "link": None,
383
- },
384
- "swegen_herv": {
385
- "display_name": "SweGen HERV",
386
- "link": None,
387
- },
388
- "swegen_l1": {
389
- "display_name": "SweGen L1",
390
- "link": None,
391
- },
392
- "swegen_sva": {
393
- "display_name": "SweGen SVA",
394
- "link": None,
395
- },
396
- "swegen_mei_max": {
397
- "display_name": "SweGen MEI(max)",
398
- "link": None,
399
- },
400
- }
401
- else:
402
- freqs = {
403
- "gnomad_frequency": {
404
- "display_name": "GnomAD",
405
- "link": variant_obj.get("gnomad_link"),
406
- },
407
- "thousand_genomes_frequency": {
408
- "display_name": "1000G",
409
- "link": variant_obj.get("thousandg_link"),
410
- },
411
- "max_thousand_genomes_frequency": {
412
- "display_name": "1000G(max)",
413
- "link": variant_obj.get("thousandg_link"),
414
- },
415
- "exac_frequency": {
416
- "display_name": "ExAC",
417
- "link": variant_obj.get("exac_link"),
418
- },
419
- "max_exac_frequency": {
420
- "display_name": "ExAC(max)",
421
- "link": variant_obj.get("exac_link"),
422
- },
423
- "swegen": {
424
- "display_name": "SweGen",
425
- "link": variant_obj.get("swegen_link"),
426
- },
427
- "gnomad_mt_homoplasmic_frequency": {
428
- "display_name": "GnomAD MT, homoplasmic",
429
- "link": variant_obj.get("gnomad_link"),
430
- },
431
- "gnomad_mt_heteroplasmic_frequency": {
432
- "display_name": "GnomAD MT, heteroplasmic",
433
- "link": variant_obj.get("gnomad_link"),
434
- },
435
- }
436
392
  frequency_list = []
437
- for freq_key in freqs:
438
- display_name = freqs[freq_key]["display_name"]
393
+ for freq_key, (display_name, link) in freqs.items():
439
394
  value = variant_obj.get(freq_key)
440
- link = freqs[freq_key]["link"]
441
- # Always add gnomad for non-mitochondrial variants
395
+
442
396
  if freq_key == "gnomad_frequency":
443
397
  if is_mitochondrial_variant:
444
398
  continue
445
- # If gnomad not found search for exac
446
- if not value:
447
- value = variant_obj.get("exac_frequency")
448
- value = value or "NA"
399
+ value = value or variant_obj.get("exac_frequency") or "NA"
449
400
 
450
- # Always add gnomad MT frequencies for mitochondrial variants
451
- elif freq_key.startswith("gnomad_mt_") and is_mitochondrial_variant:
401
+ if freq_key.startswith("gnomad_mt_") and is_mitochondrial_variant:
452
402
  value = value or "NA"
453
403
 
454
404
  if value:
@@ -474,6 +424,7 @@ def frequency(variant_obj):
474
424
  variant_obj.get("gnomad_frequency") or 0,
475
425
  variant_obj.get("gnomad_mt_homoplasmic_frequency") or 0,
476
426
  variant_obj.get("swegen_mei_max") or 0,
427
+ variant_obj.get("colorsdb_af") or 0,
477
428
  )
478
429
 
479
430
  if most_common_frequency > 0.05:
@@ -47,6 +47,7 @@ def update_tracks_settings():
47
47
  # update user in database with custom tracks info
48
48
  user_obj["igv_tracks"] = selected_tracks
49
49
  store.update_user(user_obj)
50
+ setattr(current_user, "igv_tracks", selected_tracks)
50
51
  return redirect(request.referrer)
51
52
 
52
53
 
@@ -1496,9 +1496,6 @@ def populate_filters_form(store, institute_obj, case_obj, user_obj, category, re
1496
1496
  Returns:
1497
1497
  form: FiltersForm
1498
1498
  """
1499
- form = None
1500
- clinical_filter_panels = []
1501
-
1502
1499
  default_panels = []
1503
1500
  for panel in case_obj.get("panels", []):
1504
1501
  if panel.get("is_default"):
@@ -1520,7 +1517,7 @@ def populate_filters_form(store, institute_obj, case_obj, user_obj, category, re
1520
1517
  }
1521
1518
  )
1522
1519
  clinical_filter = MultiDict(clinical_filter_dict)
1523
- elif category in ("sv", "cancer", "cancer_sv", "mei"):
1520
+ elif category in ("sv", "cancer", "cancer_sv", "mei", "outlier"):
1524
1521
  clinical_filter_dict = FiltersFormClass.clinical_filter_base
1525
1522
  clinical_filter_dict.update(
1526
1523
  {
@@ -23,10 +23,12 @@ from scout.constants import (
23
23
  CLINICAL_FILTER_BASE,
24
24
  CLINICAL_FILTER_BASE_CANCER,
25
25
  CLINICAL_FILTER_BASE_MEI,
26
+ CLINICAL_FILTER_BASE_OUTLIER,
26
27
  CLINICAL_FILTER_BASE_SV,
27
28
  CLINSIG_MAP,
28
29
  FEATURE_TYPES,
29
30
  GENETIC_MODELS,
31
+ OUTLIER_TYPES,
30
32
  SO_TERMS,
31
33
  SPIDEX_LEVELS,
32
34
  SV_TYPES,
@@ -39,6 +41,7 @@ CLINSIG_OPTIONS = list(CLINSIG_MAP.items())
39
41
  FUNC_ANNOTATIONS = [(term, term.replace("_", " ")) for term in SO_TERMS]
40
42
  REGION_ANNOTATIONS = [(term, term.replace("_", " ")) for term in FEATURE_TYPES]
41
43
  SV_TYPE_CHOICES = [(term, term.replace("_", " ").upper()) for term in SV_TYPES]
44
+ OUTLIER_TYPE_CHOICES = [(term, term.replace("_", " ").upper()) for term in OUTLIER_TYPES]
42
45
  SPIDEX_CHOICES = [(term, term.replace("_", " ")) for term in SPIDEX_LEVELS]
43
46
  FUSION_CALLER_CHOICES = [(term.get("id"), term.get("name")) for term in CALLERS.get("fusion")]
44
47
 
@@ -236,6 +239,44 @@ class FusionFiltersForm(VariantFiltersForm):
236
239
  fusion_caller = SelectMultipleField("Fusion Caller", choices=FUSION_CALLER_CHOICES, default=[])
237
240
 
238
241
 
242
+ class OutlierFiltersForm(FlaskForm):
243
+ variant_type = HiddenField(default="clinical")
244
+
245
+ gene_panels = NonValidatingSelectMultipleField(choices=[])
246
+ gene_panels_exclude = BooleanField("Exclude genes")
247
+ hgnc_symbols = TagListField("HGNC Symbols/Ids (case sensitive)")
248
+
249
+ svtype = SelectMultipleField("Type", choices=OUTLIER_TYPE_CHOICES)
250
+
251
+ filters = NonValidatingSelectField(choices=[], validators=[validators.Optional()])
252
+ filter_display_name = StringField(default="")
253
+ save_filter = SubmitField(label="Save filter")
254
+ load_filter = SubmitField(label="Load filter")
255
+ lock_filter = SubmitField(label="Lock filter")
256
+ delete_filter = SubmitField(label="Delete filter")
257
+ audit_filter = SubmitField(label="Audit filter")
258
+ clinical_filter = SubmitField(label="Clinical filter")
259
+
260
+ chrom_pos = StringField(
261
+ "Chromosome position",
262
+ [validators.Optional()],
263
+ render_kw={"placeholder": "<chr>:<start pos>-<end pos>[optional +/-<span>]"},
264
+ )
265
+
266
+ chrom = NonValidatingSelectMultipleField("Chromosome", choices=[], default="")
267
+ start = IntegerField("Start position", [validators.Optional()])
268
+ end = IntegerField("End position", [validators.Optional()])
269
+ cytoband_start = NonValidatingSelectField("Cytoband start", choices=[])
270
+ cytoband_end = NonValidatingSelectField("Cytoband end", choices=[])
271
+
272
+ filter_variants = SubmitField(label="Filter variants")
273
+ export = SubmitField(label="Filter and export")
274
+
275
+ clinical_filter_base = CLINICAL_FILTER_BASE_OUTLIER
276
+
277
+ show_unaffected = BooleanField("Show also variants present only in unaffected", default=False)
278
+
279
+
239
280
  FILTERSFORMCLASS = {
240
281
  "snv": FiltersForm,
241
282
  "str": StrFiltersForm,
@@ -244,4 +285,5 @@ FILTERSFORMCLASS = {
244
285
  "cancer": CancerFiltersForm,
245
286
  "mei": MeiFiltersForm,
246
287
  "fusion": FusionFiltersForm,
288
+ "outlier": OutlierFiltersForm,
247
289
  }
@@ -30,13 +30,17 @@
30
30
 
31
31
  var the_form = document.forms['filters_form'];
32
32
 
33
- document.getElementById('hide_dismissed').onchange = function() {
33
+ var hide_dismissed = document.getElementById('hide_dismissed');
34
+ if (hide_dismissed) {
35
+ hide_dismissed.onchange = function() {
34
36
  the_form.submit();
35
- };
37
+ }}
36
38
 
37
- document.getElementById('show_unaffected').onchange = function() {
39
+ var show_unaffected =document.getElementById('show_unaffected');
40
+ if (show_unaffected) {
41
+ show_unaffected.onchange = function() {
38
42
  the_form.submit();
39
- };
43
+ }}
40
44
 
41
45
  function resetPage(){
42
46
  document.getElementById('page').value = "1";
@@ -137,7 +137,9 @@ def variants(institute_id, case_name):
137
137
  variants_query = store.variants(
138
138
  case_obj["_id"], query=form.data, category=category, build=genome_build
139
139
  )
140
- result_size = store.count_variants(case_obj["_id"], form.data, None, category)
140
+ result_size = store.count_variants(
141
+ case_obj["_id"], form.data, None, category, build=genome_build
142
+ )
141
143
 
142
144
  if request.form.get("export"):
143
145
  return controllers.download_variants(store, case_obj, variants_query)
@@ -236,7 +238,7 @@ def str_variants(institute_id, case_name):
236
238
  ]
237
239
  )
238
240
 
239
- result_size = store.count_variants(case_obj["_id"], query, None, category)
241
+ result_size = store.count_variants(case_obj["_id"], query, None, category, build=genome_build)
240
242
 
241
243
  if request.form.get("export"):
242
244
  return controllers.download_str_variants(case_obj, variants_query)
@@ -312,7 +314,9 @@ def sv_variants(institute_id, case_name):
312
314
  case_obj["_id"], category=category, query=form.data, build=genome_build
313
315
  )
314
316
 
315
- result_size = store.count_variants(case_obj["_id"], form.data, None, category)
317
+ result_size = store.count_variants(
318
+ case_obj["_id"], form.data, None, category, build=genome_build
319
+ )
316
320
 
317
321
  # if variants should be exported
318
322
  if request.form.get("export"):
@@ -406,7 +410,9 @@ def mei_variants(institute_id, case_name):
406
410
  case_obj["_id"], category=category, query=form.data, build=genome_build
407
411
  )
408
412
 
409
- result_size = store.count_variants(case_obj["_id"], form.data, None, category)
413
+ result_size = store.count_variants(
414
+ case_obj["_id"], form.data, None, category, build=genome_build
415
+ )
410
416
 
411
417
  # if variants should be exported
412
418
  if request.form.get("export"):
@@ -515,7 +521,9 @@ def cancer_variants(institute_id, case_name):
515
521
  variants_query = store.variants(
516
522
  case_obj["_id"], category="cancer", query=form.data, build=genome_build
517
523
  )
518
- result_size = store.count_variants(case_obj["_id"], form.data, None, category)
524
+ result_size = store.count_variants(
525
+ case_obj["_id"], form.data, None, category, build=genome_build
526
+ )
519
527
 
520
528
  if request.form.get("export"):
521
529
  return controllers.download_variants(store, case_obj, variants_query)
@@ -596,7 +604,9 @@ def cancer_sv_variants(institute_id, case_name):
596
604
  case_obj["_id"], category=category, query=form.data, build=genome_build
597
605
  )
598
606
 
599
- result_size = store.count_variants(case_obj["_id"], form.data, None, category)
607
+ result_size = store.count_variants(
608
+ case_obj["_id"], form.data, None, category, build=genome_build
609
+ )
600
610
 
601
611
  # if variants should be exported
602
612
  if request.form.get("export"):
@@ -681,7 +691,9 @@ def fusion_variants(institute_id, case_name):
681
691
  case_obj["_id"], category=category, query=form.data, build=genome_build
682
692
  )
683
693
 
684
- result_size = store.count_variants(case_obj["_id"], form.data, None, category)
694
+ result_size = store.count_variants(
695
+ case_obj["_id"], form.data, None, category, build=genome_build
696
+ )
685
697
 
686
698
  # if variants should be exported
687
699
  if request.form.get("export"):
@@ -765,3 +777,12 @@ def toggle_show_dismiss_block():
765
777
  """Endpoint to toggle the show dismiss block session variable."""
766
778
  session["show_dismiss_block"] = not session.get("show_dismiss_block")
767
779
  return f"Toggled to {session['show_dismiss_block']}"
780
+
781
+
782
+ @variants_bp.route("/variants/un-audit_filter", methods=["GET"])
783
+ def unaudit_filter():
784
+ """Un-audit an audited filter."""
785
+ store.unaudit_filter(
786
+ audit_id=request.args.get("audit_id"), user_obj=store.user(current_user.email)
787
+ )
788
+ return redirect(request.referrer)
scout/server/config.py CHANGED
@@ -64,6 +64,10 @@ ACCREDITATION_BADGE = "swedac-1926-iso17025.png"
64
64
  # BEACON_URL = "http://localhost:6000/apiv1.0"
65
65
  # BEACON_TOKEN = "DEMO"
66
66
 
67
+ # ClinVar API URL
68
+ # An alternative URL that will be used to send ClinVar submissions to. Just uncomment the line below to use the test API
69
+ # CLINVAR_API_URL = "https://submit.ncbi.nlm.nih.gov/apitest/v1/submissions/"
70
+
67
71
  # connection details for LoqusDB MongoDB database
68
72
  # Example with 2 instances of LoqusDB, one using a binary file and one instance connected via REST API
69
73
  # When multiple instances are available, admin users can modify which one is in use for a given institute from the admin settings page
@@ -4,7 +4,7 @@ import logging
4
4
  import requests
5
5
  from flask import flash
6
6
 
7
- from scout.constants.clinvar import CLINVAR_API_URL, PRECLINVAR_URL
7
+ from scout.constants.clinvar import CLINVAR_API_URL_DEFAULT, PRECLINVAR_URL
8
8
 
9
9
  LOG = logging.getLogger(__name__)
10
10
 
@@ -15,9 +15,9 @@ class ClinVarApi:
15
15
  the ClinVar submission schema (https://www.ncbi.nlm.nih.gov/clinvar/docs/api_http/) and if valid, can be directly submitted to ClinVar.
16
16
  """
17
17
 
18
- def __init__(self):
18
+ def init_app(self, app):
19
19
  self.convert_service = "/".join([PRECLINVAR_URL, "csv_2_json"])
20
- self.submit_service = CLINVAR_API_URL
20
+ self.submit_service_url = app.config.get("CLINVAR_API_URL") or CLINVAR_API_URL_DEFAULT
21
21
 
22
22
  def set_header(self, api_key) -> dict:
23
23
  """Creates a header to be submitted a in a POST rquest to the CLinVar API
@@ -71,16 +71,16 @@ class ClinVarApi:
71
71
  "actions": [{"type": "AddData", "targetDb": "clinvar", "data": {"content": json_data}}]
72
72
  }
73
73
  try:
74
- resp = requests.post(self.submit_service, data=json.dumps(data), headers=header)
75
- return resp.status_code, resp
74
+ resp = requests.post(self.submit_service_url, data=json.dumps(data), headers=header)
75
+ return self.submit_service_url, resp.status_code, resp
76
76
 
77
77
  except Exception as ex:
78
- return None, ex
78
+ return self.submit_service_url, None, ex
79
79
 
80
80
  def show_submission_status(self, submission_id: str, api_key=None):
81
81
  """Retrieve the status of a ClinVar submission using the https://submit.ncbi.nlm.nih.gov/api/v1/submissions/SUBnnnnnn/actions/ endpoint."""
82
82
 
83
83
  header: dict = self.set_header(api_key)
84
- actions_url = f"{CLINVAR_API_URL}{submission_id}/actions/"
84
+ actions_url = f"{self.submit_service_url}{submission_id}/actions/"
85
85
  actions_resp: requests.models.Response = requests.get(actions_url, headers=header)
86
86
  flash(f"Response from ClinVar: {actions_resp.json()}", "primary")
scout/server/links.py CHANGED
@@ -563,9 +563,9 @@ def decipher_link(variant_obj, build=37):
563
563
  def exac_link(variant_obj):
564
564
  """Compose link to ExAC website for a variant position."""
565
565
  url_template = (
566
- "https://exac.broadinstitute.org/variant/"
566
+ "https://gnomad.broadinstitute.org/variant/"
567
567
  "{this[chromosome]}-{this[position]}-{this[reference]}"
568
- "-{this[alternative]}"
568
+ "-{this[alternative]}?dataset=exac"
569
569
  )
570
570
  return url_template.format(this=variant_obj)
571
571
 
@@ -10,16 +10,13 @@
10
10
 
11
11
  {% block css %}
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
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
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
15
  {% endblock %}
16
16
 
17
17
  {% block css_style %}
18
18
  {% endblock %}
19
19
 
20
- <!-- Adding support for Font Awesome icons version 6 -->
21
- <script src="https://kit.fontawesome.com/bff7dad824.js" integrity="sha512-+ohxkrmvsgaa299uNunuNiobFRMBGoAVR3t/fpqBmZdObzKnfBMKVyIqxrXtHMZDrwQS73ZuOVj8hUqxoJt+Ww==" crossorigin="anonymous"></script>
22
-
23
20
  <style>
24
21
 
25
22
  .spinner {
@@ -12,7 +12,7 @@
12
12
  <td>
13
13
  <small>
14
14
  <strong> {{ comment.user_name }} </strong>
15
- on {{ comment.created_at.date() }}
15
+ on {{ comment.created_at.strftime('%y-%m-%d %H:%M') }}
16
16
  {% if comment.level == 'global' %}
17
17
  <span class='badge bg-info text-white'>GLOBAL</span>
18
18
  {% endif %}
@@ -134,7 +134,7 @@
134
134
  <form method="POST" action="{{ url_for('cases.events', institute_id=institute._id, case_name=case.display_name, event_id=comment._id,_anchor='comments') }}">
135
135
  <small>
136
136
  <strong>{{ comment.user_name }}</strong>
137
- on {{ comment.created_at.date() }}
137
+ on {{ comment.created_at.strftime('%y-%m-%d %H:%M') }}
138
138
  {% if comment.level == 'global' %}
139
139
  <span class="badge bg-info">GLOBAL</span>
140
140
  {% endif %}
@@ -145,7 +145,7 @@
145
145
  <span class='badge bg-secondary'>edited</span>
146
146
  {% endif %}
147
147
  {% if comment.user_id == current_user.email %}
148
- <button class="btn btn-link btn-sm" type="submit" name="remove"><i class="fa fa-remove"></i></button>
148
+ <button class="btn btn-link btn-sm" type="submit" name="remove"><i class="fa fa-times"></i></button>
149
149
  <button class="btn btn-link btn-sm" type="button" data-bs-toggle="modal" data-bs-target="#editComment_{{index}}"><i class="fa fa-edit"></i></button>
150
150
  {% endif %}
151
151
  </small>
@@ -208,7 +208,7 @@
208
208
  ({{ event.hpo_term }})
209
209
  {%- endif %}
210
210
  {%-if event.individuals %}, individuals: {{event.individuals|join(', ')}}{% endif %}
211
- at <span class="timestamp">{{ event.created_at.date() }}</span>
211
+ at <span class="timestamp">{{ event.created_at.strftime('%y-%m-%d %H:%M') }}</span>
212
212
  </li>
213
213
  {% else %}
214
214
  <li class="list-group-item">No activity yet</li>
scout/server/utils.py CHANGED
@@ -269,7 +269,8 @@ def case_has_mt_alignments(case_obj: dict):
269
269
 
270
270
 
271
271
  def case_has_rna_tracks(case_obj: Dict) -> bool:
272
- """Returns True if one of more individuals of the case contain RNA-seq data
272
+ """Returns True if one or more individuals of the case contain RNA-seq data
273
+ Add this info to the case obj dict.
273
274
 
274
275
  Args:
275
276
  case_obj(dict)
@@ -277,10 +278,12 @@ def case_has_rna_tracks(case_obj: Dict) -> bool:
277
278
  True or False (bool)
278
279
  """
279
280
  # Display junctions track if available for any of the individuals
281
+ case_obj["has_rna_tracks"] = False
280
282
  for ind in case_obj.get("individuals", []):
281
283
  # RNA can have three different aln track files
282
284
  for path_name in ["splice_junctions_bed", "rna_coverage_bigwig", "rna_alignment_path"]:
283
285
  if _check_path_name(ind, path_name):
286
+ case_obj["has_rna_tracks"] = True
284
287
  return True
285
288
  return False
286
289
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scout-browser
3
- Version: 4.84
3
+ Version: 4.86
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
@@ -15,8 +15,8 @@ Classifier: Topic :: Software Development :: Libraries
15
15
  Classifier: Programming Language :: Python :: 3.6
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: werkzeug <3
19
- Requires-Dist: Flask >=2.0
18
+ Requires-Dist: werkzeug
19
+ Requires-Dist: Flask>=2.0
20
20
  Requires-Dist: Flask-Bootstrap
21
21
  Requires-Dist: Flask-CORS
22
22
  Requires-Dist: path.py
@@ -26,9 +26,9 @@ Requires-Dist: Flask-WTF
26
26
  Requires-Dist: Flask-Mail
27
27
  Requires-Dist: coloredlogs
28
28
  Requires-Dist: query-phenomizer
29
- Requires-Dist: Flask-Babel >=3
30
- Requires-Dist: livereload
31
- Requires-Dist: tornado <6.3
29
+ Requires-Dist: Flask-Babel>=3
30
+ Requires-Dist: livereload>=2.7
31
+ Requires-Dist: tornado>=6.4.1
32
32
  Requires-Dist: python-dateutil
33
33
  Requires-Dist: pymongo
34
34
  Requires-Dist: pathlib
@@ -47,14 +47,14 @@ Requires-Dist: flask-ldapconn
47
47
  Requires-Dist: cyvcf2
48
48
  Requires-Dist: configobj
49
49
  Requires-Dist: ped-parser
50
- Requires-Dist: pydantic >=2
51
- Requires-Dist: PyYaml >=5.1
52
- Requires-Dist: intervaltree ==3.0.2
50
+ Requires-Dist: pydantic>=2
51
+ Requires-Dist: PyYaml>=5.1
52
+ Requires-Dist: intervaltree==3.0.2
53
53
  Requires-Dist: anytree
54
54
  Requires-Dist: tabulate
55
55
  Provides-Extra: coverage
56
- Requires-Dist: chanjo-report ; extra == 'coverage'
57
- Requires-Dist: pymysql ; extra == 'coverage'
56
+ Requires-Dist: chanjo-report; extra == "coverage"
57
+ Requires-Dist: pymysql; extra == "coverage"
58
58
 
59
59
 
60
60
  <p align="center">