scout-browser 4.90__py3-none-any.whl → 4.91__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 (63) hide show
  1. scout/__version__.py +1 -1
  2. scout/adapter/mongo/case.py +27 -38
  3. scout/commands/export/variant.py +14 -4
  4. scout/commands/load/panel.py +2 -1
  5. scout/commands/update/panelapp.py +11 -3
  6. scout/commands/view/case.py +2 -2
  7. scout/constants/__init__.py +1 -2
  8. scout/constants/acmg.py +15 -15
  9. scout/constants/case_tags.py +0 -46
  10. scout/constants/clnsig.py +2 -1
  11. scout/constants/gene_tags.py +0 -6
  12. scout/constants/panels.py +16 -0
  13. scout/constants/variants_export.py +2 -0
  14. scout/demo/__init__.py +4 -1
  15. scout/demo/panelapp_panel.json +463 -0
  16. scout/demo/panelapp_panels_reduced.json +37 -0
  17. scout/load/panel.py +3 -142
  18. scout/load/panelapp.py +138 -0
  19. scout/models/case/case_loading_models.py +5 -4
  20. scout/parse/matchmaker.py +18 -6
  21. scout/parse/panel.py +3 -117
  22. scout/parse/panelapp.py +112 -0
  23. scout/parse/variant/clnsig.py +26 -21
  24. scout/parse/variant/genotype.py +6 -5
  25. scout/server/blueprints/alignviewers/controllers.py +7 -5
  26. scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
  27. scout/server/blueprints/cases/templates/cases/case_sma.html +49 -42
  28. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +27 -12
  29. scout/server/blueprints/cases/views.py +18 -7
  30. scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +7 -7
  31. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +2 -2
  32. scout/server/blueprints/dashboard/controllers.py +128 -165
  33. scout/server/blueprints/dashboard/forms.py +3 -13
  34. scout/server/blueprints/dashboard/templates/dashboard/dashboard_general.html +17 -22
  35. scout/server/blueprints/institutes/forms.py +1 -2
  36. scout/server/blueprints/institutes/templates/overview/cases.html +2 -133
  37. scout/server/blueprints/institutes/templates/overview/utils.html +135 -0
  38. scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +5 -0
  39. scout/server/blueprints/panels/templates/panels/panel.html +5 -1
  40. scout/server/blueprints/panels/templates/panels/panel_pdf_simple.html +5 -1
  41. scout/server/blueprints/variant/controllers.py +6 -1
  42. scout/server/blueprints/variant/templates/variant/buttons.html +11 -10
  43. scout/server/blueprints/variant/templates/variant/components.html +63 -44
  44. scout/server/blueprints/variant/templates/variant/str-variant-reviewer.html +1 -1
  45. scout/server/blueprints/variant/templates/variant/utils.html +38 -10
  46. scout/server/blueprints/variant/templates/variant/variant.html +1 -1
  47. scout/server/blueprints/variants/controllers.py +9 -4
  48. scout/server/blueprints/variants/templates/variants/cancer-sv-variants.html +9 -5
  49. scout/server/blueprints/variants/templates/variants/cancer-variants.html +6 -17
  50. scout/server/blueprints/variants/templates/variants/str-variants.html +2 -2
  51. scout/server/blueprints/variants/templates/variants/sv-variants.html +8 -1
  52. scout/server/blueprints/variants/templates/variants/utils.html +14 -0
  53. scout/server/extensions/__init__.py +2 -0
  54. scout/server/extensions/panelapp_extension.py +75 -0
  55. scout/server/links.py +19 -1
  56. scout/server/utils.py +25 -33
  57. {scout_browser-4.90.dist-info → scout_browser-4.91.dist-info}/METADATA +1 -1
  58. {scout_browser-4.90.dist-info → scout_browser-4.91.dist-info}/RECORD +62 -58
  59. {scout_browser-4.90.dist-info → scout_browser-4.91.dist-info}/WHEEL +1 -1
  60. scout/demo/panelapp_test_panel.json +0 -79
  61. {scout_browser-4.90.dist-info → scout_browser-4.91.dist-info}/LICENSE +0 -0
  62. {scout_browser-4.90.dist-info → scout_browser-4.91.dist-info}/entry_points.txt +0 -0
  63. {scout_browser-4.90.dist-info → scout_browser-4.91.dist-info}/top_level.txt +0 -0
@@ -92,7 +92,7 @@
92
92
  <div id="accordion">
93
93
  <div class="row">
94
94
  <div class="col-4 d-flex align-items-center">
95
- <span><a data-bs-toggle="collapse" data-bs-parent="#accordion" href="#track_settings" class="text-secondary">Settings DNA <i class="fas fa-cogs text-secondary"></i></a></span>
95
+ <span><a data-bs-toggle="collapse" data-bs-parent="#accordion" href="#track_settings" class="text-secondary"><i class="fas fa-cogs text-secondary me-1"></i>Settings IGV DNA</a></span>
96
96
  </div>
97
97
  <div id="track_settings" class="col-8 collapse">
98
98
  <form action="{{url_for('variant.update_tracks_settings')}}" method="POST">
@@ -235,16 +235,24 @@
235
235
  {{ gene.common.hgnc_symbol if gene.common else gene.hgnc_id }}
236
236
  </a>
237
237
  </td>
238
- <td class="d-flex justify-content-around align-items-center">
239
- <a target="_blank" href="{{ transcript.ensembl_link }}">
238
+ <td class="d-flex align-items-center">
239
+ <a target="_blank" class="float-start" href="{{ transcript.ensembl_link }}">
240
240
  {{ transcript.transcript_id }}
241
241
  </a>
242
+ {% if transcript.transcript_id in variant.mane_transcripts %}
243
+ {% if variant.mane_transcripts[transcript.transcript_id].mane %}
244
+ <a href="#" data-bs-toggle="tooltip" title="MANE Select - {{variant.mane_transcripts[transcript.transcript_id].mane}}"><span class="badge bg-success ms-3" title="MANE Select">M</span></a>
245
+ {% endif %}
246
+ {% if variant.mane_transcripts[transcript.transcript_id].mane_plus %}
247
+ <a href="#" data-bs-toggle="tooltip" title="MANE Plus Clinical - {{variant.mane_transcripts[transcript.transcript_id].mane_plus}}"><span class="badge bg-success ms-3" title="MANE Plus Clinical">M+</span></a>
248
+ {% endif %}
249
+ {% endif %}
242
250
  {% if transcript.is_canonical %}
243
- <span class="badge bg-info">C</span>
251
+ <span class="badge bg-info ms-3">C</span>
244
252
  {% endif %}
245
253
  </td>
246
254
  <td>
247
- {{ transcript.refseq_identifiers|join(',') }}
255
+ {{ transcript.refseq_identifiers|join(', ') }}
248
256
  </td>
249
257
  <td>{{ transcript.biotype or '' }}</td>
250
258
  <td data-bs-toggle="tooltip" data-bs-placement="right" title="{{ transcript.functional_annotations|join(', ') }}">
@@ -347,11 +355,31 @@
347
355
  {% endif %}
348
356
  </div>
349
357
  <div class="col-3">
350
- {% if variant.is_mitochondrial and case.mt_bams or case.bam_files %}
351
- <span><a class="btn btn-secondary btn-sm text-white" href="{{url_for('alignviewers.igv', institute_id=case['owner'], case_name=case['display_name'], variant_id=variant['_id'], chrom=chrom, start=align_start, stop=align_end) }}" target="_blank">IGV viewer</a></span>
352
- {% else %}
353
- - BAM file(s) missing
354
- {% endif %}
358
+ {% if variant.is_mitochondrial and not case.mt_bams %}
359
+ <span data-bs-toggle="tooltip" title="Alignment file(s) missing">
360
+ <a href="{{url_for('alignviewers.igv', institute_id=case['owner'], case_name=case['display_name'], variant_id=variant['_id'], chrom=chrom, start=align_start, stop=align_end)}}"
361
+ target="_blank"
362
+ class="btn btn-secondary btn-sm text-white
363
+ disabled" title="Alignment file(s) missing" data-bs-toggle="tooltip" aria-disabled="true"><span class="fa fa-times-circle fa-fw me-1"></span>IGV mtDNA
364
+ </a>
365
+ </span>
366
+ {% elif not case.bam_files and not variant.is_mitochondrial%}
367
+ <span data-bs-toggle="tooltip" title="Alignment file(s) missing">
368
+ <a href="{{url_for('alignviewers.igv', institute_id=case['owner'], case_name=case['display_name'], variant_id=variant['_id'], chrom=chrom, start=align_start, stop=align_end)}}"
369
+ target="_blank"
370
+ class="btn btn-secondary btn-sm text-white
371
+ disabled" title="Alignment file(s) missing" data-bs-toggle="tooltip" aria-disabled="true"><span class="fa fa-times-circle fa-fw me-1"></span>IGV gDNA
372
+ </a>
373
+ </span>
374
+ {% else %}
375
+ <span>
376
+ <a href="{{url_for('alignviewers.igv', institute_id=case['owner'], case_name=case['display_name'], variant_id=variant['_id'], chrom=chrom, start=align_start, stop=align_end)}}"
377
+ target="_blank"
378
+ class="btn btn-secondary btn-sm text-white"><span class="fa fa-magnifying-glass fa-fw me-1"></span>
379
+ IGV {% if variant.is_mitochondrial %}mt{% else %}g{% endif %}DNA
380
+ </a>
381
+ </span>
382
+ {% endif %}
355
383
  </div>
356
384
  <div class="col-1">
357
385
  <!--Define build variable to be used in the UCSC link-->
@@ -21,7 +21,7 @@
21
21
 
22
22
  {% block top_nav %}
23
23
  {{ super() }}
24
- <li class="nav-item">
24
+ <li class="nav-item">
25
25
  <a class="nav-link" href="{{ url_for('cases.index') }}">Institutes</a>
26
26
  </li>
27
27
  <li class="nav-item">
@@ -969,8 +969,6 @@ def get_str_mc(variant_obj: dict) -> Optional[int]:
969
969
  alt_mc = int(alt_num.group())
970
970
  return alt_mc
971
971
 
972
- return None
973
-
974
972
 
975
973
  def download_str_variants(case_obj, variant_objs):
976
974
  """Download filtered STR variants for a case to a CSV file
@@ -1004,11 +1002,11 @@ def download_str_variants(case_obj, variant_objs):
1004
1002
  for variant in variant_objs.limit(EXPORTED_VARIANTS_LIMIT):
1005
1003
  variant_line = []
1006
1004
  variant_line.append(str(variant.get("variant_rank", ""))) # index
1007
- variant_line.append(variant.get("str_repid")) # Repeat locus
1005
+ variant_line.append(variant.get("str_repid", variant.get("str_trid", ""))) # Repeat locus
1008
1006
  variant_line.append(
1009
1007
  variant.get("str_display_ru", variant.get("str_ru", ""))
1010
1008
  ) # Reference repeat unit
1011
- variant_line.append(get_str_mc(variant) or ".") # Estimated size
1009
+ variant_line.append(str(get_str_mc(variant) or ".")) # Estimated size
1012
1010
  variant_line.append(str(variant.get("str_ref", ""))) # Reference size
1013
1011
  variant_line.append(str(variant.get("str_status", ""))) # Status
1014
1012
  gt_cell = ""
@@ -1078,6 +1076,13 @@ def variant_export_lines_common(store: MongoAdapter, variant: dict, case_obj: di
1078
1076
  position = variant["position"]
1079
1077
  change = variant["reference"] + ">" + variant["alternative"]
1080
1078
  variant_line.append(variant.get("rank_score", "N/A"))
1079
+ cat = (
1080
+ variant.get("sub_category")
1081
+ if variant["category"] in ["sv", "cancer_sv"]
1082
+ else variant.get("category")
1083
+ )
1084
+ variant_line.append(cat.upper() if cat else "")
1085
+ variant_line.append(" ".join([f"{name}:{caller}" for name, caller in callers(variant)]))
1081
1086
  variant_line.append(variant["chromosome"])
1082
1087
  variant_line.append(position)
1083
1088
  variant_line.append(change)
@@ -1,5 +1,5 @@
1
1
  {% extends "layout.html" %}
2
- {% from "variants/utils.html" import cancer_sv_filters,cell_rank, pagination_footer, pagination_hidden_div, filter_form_footer, filter_script_main, update_stash_filter_button_status, dismiss_variants_block %}
2
+ {% from "variants/utils.html" import cancer_sv_filters,cell_rank, pagination_footer, pagination_hidden_div, filter_form_footer, filter_script_main, update_stash_filter_button_status, dismiss_variants_block, callers_cell %}
3
3
  {% from "variants/components.html" import external_scripts, external_stylesheets, frequency_cell_general, observed_cell_general, variant_gene_symbols_cell, variant_funct_anno_cell %}
4
4
 
5
5
  {% block title %}
@@ -38,7 +38,7 @@
38
38
  {% endblock %}
39
39
 
40
40
  {% block content_main %}
41
- <form method="POST" id="filters_form" action="{{url_for('variants.cancer_sv_variants', institute_id=institute._id, case_name=case.display_name)}}" >
41
+ <form method="POST" id="filters_form" action="{{url_for('variants.cancer_sv_variants', institute_id=institute._id, case_name=case.display_name)}}" enctype="multipart/form-data" onsubmit="return validateForm()">
42
42
  <div class="container-float">
43
43
  {{ pagination_hidden_div(page) }}
44
44
  <div class="card panel-default" id="accordion">
@@ -57,8 +57,9 @@
57
57
  <thead class="thead table-light">
58
58
  <tr>
59
59
  <th style="width:2%"></th>
60
- <th style="width:9%">Index</th>
60
+ <th style="width:3%">Index</th>
61
61
  <th>Type</th>
62
+ <th style="width:9%">Callers</th>
62
63
  <th style="width:5%">Chr</th>
63
64
  <th>Start</th>
64
65
  <th>End</th>
@@ -103,8 +104,11 @@
103
104
  <td>
104
105
  {{ cell_rank(variant, institute, case, form, manual_rank_options) }}
105
106
  </td>
106
- <td><span data-bs-toggle="tooltip" data-bs-html="true" title="{% for name, caller in variant.callers %}{{ name }}: {{ caller }}<br>{% endfor %}">
107
- {{ variant.sub_category|upper }}</span>
107
+ <td>
108
+ {{ variant.sub_category|upper }}
109
+ </td>
110
+ <td>
111
+ {{ callers_cell(variant) }}
108
112
  </td>
109
113
  <td>{{ variant.chromosome if variant.chromosome == variant.end_chrom else variant.chromosome+'-'+variant.end_chrom }}</td>
110
114
  <td class="col-2"><span style="white-space: nowrap;">{{ variant.position|human_longint|safe }}</span></td>
@@ -1,7 +1,7 @@
1
1
  {% extends "layout.html" %}
2
2
 
3
- {% from "variants/components.html" import external_scripts, external_stylesheets, gene_cell, frequency_cell_general, observed_cell_general %}
4
- {% from "variants/utils.html" import cancer_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status %}
3
+ {% from "variants/components.html" import external_scripts, external_stylesheets, gene_cell, frequency_cell_general, observed_cell_general, variant_funct_anno_cell %}
4
+ {% from "variants/utils.html" import cancer_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status, callers_cell %}
5
5
  {% from "variants/indicators.html" import pin_indicator, causative_badge, clinical_assessments_badge, comments_badge, dismissals_badge, evaluations_badge, group_assessments_badge, matching_manual_rank, other_tiered_variants, research_assessments_badge %}
6
6
 
7
7
  {% block title %}
@@ -56,14 +56,14 @@
56
56
  <th title="Gene">Gene</th>
57
57
  <th title="Variant" style="width:12%">HGVS[c/p]</th>
58
58
  <th title="Assessments including variant tier" style="width:8%">Assessment</th>
59
- <th title="Quality markers" style="width:6%">Qual</th>
60
59
  <th title="Rank scores" style="width:4%">Rank</th>
61
60
  <th title="CADD scores" style="width:4%">CADD</th>
62
61
  <th title="Genomic coordinate" style="width:8%">Chr pos</th>
63
62
  <th title="Population frequency">Pop Freq</th>
64
63
  <th title="Observed" style="width:7%">Observed</th>
65
64
  <th title="Variant type">Type</th>
66
- <th title="Functional consequence annotation" style="width:18%">Consequence</th>
65
+ <th title="Callers" style="width:8%">Callers</th>
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>
69
69
  </tr>
@@ -110,18 +110,14 @@
110
110
  {{ causative_badge(variant, case) }}
111
111
  {{ other_tiered_variants(variant) }}
112
112
  </td>
113
- <td>{{ quality_cell(variant) }}</td>
114
113
  <td>{{ rank_cell(variant) }}</td>
115
114
  <td>{{ cadd_cell(variant) }}</td>
116
115
  <td>{{ position_cell(variant) }}</td>
117
116
  <td class="text-end">{{ frequency_cell_general(variant) }}</td>
118
117
  <td>{{ observed_cell_general(variant) }}</td>
119
118
  <td>{{ variant.sub_category }}</td>
120
- <td>
121
- {% for annotation in variant.functional_annotations %}
122
- <div>{{ annotation }}</div>
123
- {% endfor %}
124
- </td>
119
+ <td>{{ callers_cell(variant) }}</td>
120
+ <td>{{ variant_funct_anno_cell(variant) }}</td>
125
121
  <td>{{ allele_cell(variant.tumor or {}) }}</td>
126
122
  <td>{{ allele_cell(variant.normal or {}) }}</td>
127
123
  </tr>
@@ -177,13 +173,6 @@
177
173
  {% endif %}
178
174
  {% endmacro %}
179
175
 
180
- {% macro quality_cell(variant) %}
181
- {% for filter in variant.filters %}
182
- <div data-bs-toggle="tooltip" data-bs-placement="top" title="{{ filter.description }}" class="badge bg-{{ filter.label_class }}">{{ filter.label }}</div>
183
- {% endfor %}
184
- {% endmacro %}
185
-
186
-
187
176
  {% macro position_cell(variant) %}
188
177
  {{ variant.chromosome }}<span class="text-muted">:{{ variant.position }}</span>
189
178
  {% endmacro %}
@@ -108,9 +108,9 @@
108
108
  {{ variant.position|human_longint|safe }}</span>
109
109
  {{ reviewer_button(case,variant,case_groups,institute._id) }}
110
110
  {% if case.bam_files %}
111
- <a class="btn btn-secondary btn-sm text-white" href="{{url_for('alignviewers.igv', institute_id=institute['_id'], case_name=case['display_name'], variant_id=variant['_id'])}}" rel="noopener" target="_blank">IGV viewer</a>
111
+ <span><a class="btn btn-secondary btn-sm text-white" href="{{url_for('alignviewers.igv', institute_id=institute['_id'], case_name=case['display_name'], variant_id=variant['_id'])}}" rel="noopener" target="_blank"><i class="fa fa-magnifying-glass fa-fw me-1"></i>IGV gDNA</a></span>
112
112
  {% else %}
113
- <button title="BAM file(s) missing" class="btn btn-secondary btn-sm" disabled>IGV viewer</button>
113
+ <span data-bs-toggle="tooltip" title="BAM file(s) missing"><button class="btn btn-secondary btn-sm" disabled><i class="fa fa-times-circle fa-fw me-1"></i>IGV gDNA</button></span>
114
114
  {% endif %}
115
115
 
116
116
  </td>
@@ -1,5 +1,5 @@
1
1
  {% extends "layout.html" %}
2
- {% from "variants/utils.html" import sv_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status %}
2
+ {% from "variants/utils.html" import sv_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status, callers_cell %}
3
3
  {% from "variants/components.html" import external_scripts, external_stylesheets, frequency_cell_general, observed_cell_general, variant_gene_symbols_cell, variant_funct_anno_cell %}
4
4
 
5
5
  {% block title %}
@@ -60,6 +60,7 @@ onsubmit="return validateForm()">
60
60
  <th>Rank</th>
61
61
  <th>Score</th>
62
62
  <th>Type</th>
63
+ <th>Callers</th>
63
64
  <th>Chr</th>
64
65
  <th>Start</th>
65
66
  <th>End</th>
@@ -102,6 +103,12 @@ onsubmit="return validateForm()">
102
103
  {{ cell_rank(variant, institute, case, form, manual_rank_options) }}
103
104
  </td>
104
105
  <td class="text-end">{{ variant.rank_score|int }}</td>
106
+ <td>
107
+ {{ variant.sub_category|upper }}
108
+ </td>
109
+ <td>
110
+ {{ callers_cell(variant) }}
111
+ </td>
105
112
  <td><span data-bs-toggle="tooltip" data-bs-html="true" title="{% for name, caller in variant.callers %}{{ name }}: {{ caller }}<br>{% endfor %}">
106
113
  {{ variant.sub_category|upper }}</span></td>
107
114
  <td>{{ variant.chromosome if variant.chromosome == variant.end_chrom else variant.chromosome+'-'+variant.end_chrom }}</td>
@@ -48,6 +48,20 @@
48
48
  </script>
49
49
  {% endmacro %}
50
50
 
51
+
52
+ {% macro callers_cell(variant) %}
53
+ {% for filter in variant.filters %} <!-- collect info from variant's filters (PASS) -->
54
+ <span class="badge bg-{{ filter.label_class }}" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ filter.description }}">
55
+ {{ filter.label }}
56
+ </span>
57
+ {% endfor %}
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}}">
60
+ {{ name }}
61
+ </span>
62
+ {% endfor %}
63
+ {% endmacro %}
64
+
51
65
  {% macro mark_heteroplasmic_mt(individuals, samples) %}
52
66
  {% for ind in individuals if ind.phenotype == 2 %}
53
67
  {% for gt in samples|selectattr("sample_id", "equalto", ind.individual_id) %}
@@ -18,6 +18,7 @@ from .ldap_extension import LdapManager
18
18
  from .loqus_extension import LoqusDB
19
19
  from .matchmaker_extension import MatchMaker
20
20
  from .mongo_extension import MongoDB
21
+ from .panelapp_extension import PanelAppClient
21
22
  from .phenopacket_extension import PhenopacketAPI
22
23
  from .rerunner_extension import RerunnerError, RerunnerService
23
24
 
@@ -39,3 +40,4 @@ config_igv_tracks = AlignTrackHandler()
39
40
  bionano_access = BioNanoAccessAPI()
40
41
  chanjo_report = ChanjoReport()
41
42
  chanjo2 = Chanjo2Client()
43
+ panelapp = PanelAppClient()
@@ -0,0 +1,75 @@
1
+ import logging
2
+ from typing import Optional
3
+
4
+ import requests
5
+
6
+ API_PANELS_URL = "https://panelapp.genomicsengland.co.uk/api/v1/panels/"
7
+
8
+ LOG = logging.getLogger(__name__)
9
+
10
+
11
+ class PanelAppClient:
12
+ """Class that retrieves PanelAll green genes using the NHS-NGS/panelapp library."""
13
+
14
+ def __init__(self):
15
+ self.panels_page = 1
16
+ self.panel_types = set()
17
+ self.panel_ids = []
18
+
19
+ def get_panel_types(self) -> list:
20
+ """Returns available panel types, collected from processed panels"""
21
+ return sorted(list(self.panel_types))
22
+
23
+ def get_panels(self, page: int, signed_off: bool = False) -> Optional[dict]:
24
+ """Return a dictionary {panel_id: Panelapp.Panel} with all panels, signed off or not."""
25
+
26
+ panels_url = f"{API_PANELS_URL}?page={page}"
27
+ if signed_off:
28
+ panels_url = f"{API_PANELS_URL}signedoff/?page={page}"
29
+
30
+ resp = requests.get(panels_url, headers={"Content-Type": "application/json"})
31
+ if not resp.ok:
32
+ resp.raise_for_status()
33
+ return
34
+
35
+ return resp.json()
36
+
37
+ def set_panel_types(self, json_panels: dict):
38
+ """Collect available panel types from a page of panels and add them to the self.panel_types variable."""
39
+
40
+ for panel in json_panels.get("results", []):
41
+ for type in panel.get("types", []):
42
+ self.panel_types.add(type["slug"])
43
+
44
+ def get_panel_ids(self, signed_off: bool) -> list[int]:
45
+ """Returns a list of panel ids contained in a json document with gene panels data."""
46
+
47
+ def get_ids(json_panels):
48
+ LOG.info(f"Retrieving IDs from API page {self.panels_page}")
49
+ for panel in json_panels.get("results", []):
50
+ self.panel_ids.append(panel["id"])
51
+ self.panels_page += 1
52
+
53
+ json_panels: dict = self.get_panels(
54
+ signed_off=signed_off, page=self.panels_page
55
+ ) # first page of results
56
+ get_ids(json_panels=json_panels)
57
+ self.set_panel_types(json_panels=json_panels)
58
+
59
+ # Iterate over remaining pages of results
60
+ while json_panels["next"] is not None:
61
+ json_panels = self.get_panels(signed_off=signed_off, page=self.panels_page)
62
+ get_ids(json_panels=json_panels)
63
+ self.set_panel_types(json_panels=json_panels)
64
+
65
+ return self.panel_ids
66
+
67
+ def get_panel(self, panel_id: str) -> Optional[dict]:
68
+ """Retrieve a gene_panel. Apply filters on panel type, if available."""
69
+ panel_url = f"{API_PANELS_URL}{panel_id}"
70
+ resp = requests.get(panel_url, headers={"Content-Type": "application/json"})
71
+ if not resp.ok:
72
+ resp.raise_for_status()
73
+ return
74
+
75
+ return resp.json()
scout/server/links.py CHANGED
@@ -355,7 +355,7 @@ def add_tx_links(tx_obj, build=37, hgnc_symbol=None):
355
355
  return tx_obj
356
356
 
357
357
 
358
- ## Transcript links
358
+ # Transcript links
359
359
  def refseq(refseq_id):
360
360
  link = "http://www.ncbi.nlm.nih.gov/nuccore/{}"
361
361
  if not refseq_id:
@@ -480,6 +480,7 @@ def get_variant_links(institute_obj: dict, variant_obj: dict, build: int = None)
480
480
  swegen_link=swegen_link(variant_obj),
481
481
  cosmic_links=cosmic_links(variant_obj),
482
482
  beacon_link=beacon_link(variant_obj, build),
483
+ franklin_link=franklin_link(variant_obj, build),
483
484
  ucsc_link=ucsc_link(variant_obj, build),
484
485
  decipher_link=decipher_link(variant_obj, build),
485
486
  ensembl_link=ensembl_link(variant_obj, build),
@@ -633,6 +634,23 @@ def swegen_link(variant_obj):
633
634
  return url_template.format(this=variant_obj)
634
635
 
635
636
 
637
+ def franklin_link(variant_obj: dict, build: int = 37):
638
+ """Compose link to Franklin Variant Frequency Database."""
639
+ if variant_obj["category"] in ["cancer", "cancer_sv"]:
640
+ url_template = (
641
+ "https://franklin.genoox.com/clinical-db/variant/snpTumor/chr{this[chromosome]}-"
642
+ "{this[position]}-{this[reference]}-{this[alternative]}"
643
+ )
644
+ else:
645
+ url_template = (
646
+ "https://franklin.genoox.com/clinical-db/variant/snp/chr{this[chromosome]}-"
647
+ "{this[position]}-{this[reference]}-{this[alternative]}"
648
+ )
649
+ if build == 38:
650
+ url_template += "-hg38"
651
+ return url_template.format(this=variant_obj)
652
+
653
+
636
654
  def cosmic_links(variant_obj):
637
655
  """Compose link to COSMIC Database.
638
656
 
scout/server/utils.py CHANGED
@@ -297,51 +297,43 @@ def _check_path_name(ind: Dict, path_name: str) -> bool:
297
297
  return False
298
298
 
299
299
 
300
- def case_append_alignments(case_obj):
300
+ def case_append_alignments(case_obj: dict):
301
301
  """Deconvolute information about files to case_obj.
302
302
 
303
- This function prepares the bam/cram files in a certain way so that they are easily accessed in
304
- the templates.
305
-
306
- Loops over the the individuals and gather bam/cram files, indexes and sample display names in
307
- lists
308
-
309
- Args:
310
- case_obj(scout.models.Case)
303
+ This function prepares bam/cram files and their indexes for easy access in templates.
311
304
  """
312
305
  unwrap_settings = [
313
306
  {"path": "bam_file", "append_to": "bam_files", "index": "bai_files"},
314
307
  {"path": "mt_bam", "append_to": "mt_bams", "index": "mt_bais"},
315
- {"path": "rhocall_bed", "append_to": "rhocall_beds", "index": "no_index"},
316
- {"path": "rhocall_wig", "append_to": "rhocall_wigs", "index": "no_index"},
317
- {
318
- "path": "upd_regions_bed",
319
- "append_to": "upd_regions_beds",
320
- "index": "no_index",
321
- },
322
- {"path": "upd_sites_bed", "append_to": "upd_sites_beds", "index": "no_index"},
323
- {
324
- "path": "tiddit_coverage_wig",
325
- "append_to": "tiddit_coverage_wigs",
326
- "index": "no_index",
327
- },
308
+ {"path": "rhocall_bed", "append_to": "rhocall_beds", "index": None},
309
+ {"path": "rhocall_wig", "append_to": "rhocall_wigs", "index": None},
310
+ {"path": "upd_regions_bed", "append_to": "upd_regions_beds", "index": None},
311
+ {"path": "upd_sites_bed", "append_to": "upd_sites_beds", "index": None},
312
+ {"path": "tiddit_coverage_wig", "append_to": "tiddit_coverage_wigs", "index": None},
328
313
  ]
329
314
 
330
- for individual in case_obj["individuals"]:
315
+ def process_file(case_obj, individual, setting):
316
+ """Process a single file and its optional index."""
317
+ file_path = individual.get(setting["path"])
331
318
  append_safe(
332
319
  case_obj,
333
- "sample_names",
334
- case_obj.get("display_name", "") + " - " + individual.get("display_name", ""),
320
+ setting["append_to"],
321
+ file_path if file_path and os.path.exists(file_path) else "missing",
335
322
  )
323
+ if setting["index"]:
324
+ index_path = (
325
+ find_index(file_path) if file_path and os.path.exists(file_path) else "missing"
326
+ )
327
+ append_safe(case_obj, setting["index"], index_path)
328
+
329
+ for individual in case_obj["individuals"]:
330
+ # Add sample name
331
+ sample_name = f"{case_obj.get('display_name', '')} - {individual.get('display_name', '')}"
332
+ append_safe(case_obj, "sample_names", sample_name)
333
+
334
+ # Process all file settings
336
335
  for setting in unwrap_settings:
337
- file_path = individual.get(setting["path"])
338
- if not (file_path and os.path.exists(file_path)):
339
- continue
340
- append_safe(case_obj, setting["append_to"], file_path)
341
- if not setting["index"] == "no_index":
342
- append_safe(
343
- case_obj, setting["index"], find_index(file_path)
344
- ) # either bai_files or mt_bais
336
+ process_file(case_obj, individual, setting)
345
337
 
346
338
 
347
339
  def append_safe(obj, obj_index, elem):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scout-browser
3
- Version: 4.90
3
+ Version: 4.91
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