scout-browser 4.102.0__py3-none-any.whl → 4.103.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scout/adapter/mongo/case.py +26 -122
- scout/adapter/mongo/clinvar.py +91 -25
- scout/adapter/mongo/event.py +0 -47
- scout/adapter/mongo/variant_loader.py +7 -3
- scout/build/variant/variant.py +1 -0
- scout/commands/load/variants.py +1 -1
- scout/commands/update/user.py +87 -49
- scout/constants/__init__.py +3 -0
- scout/constants/clinvar.py +10 -0
- scout/constants/variant_tags.py +18 -0
- scout/demo/NIST.trgt.stranger.vcf.gz +0 -0
- scout/demo/NIST.trgt.stranger.vcf.gz.tbi +0 -0
- scout/demo/__init__.py +1 -0
- scout/models/clinvar.py +86 -0
- scout/parse/variant/coordinates.py +5 -1
- scout/parse/variant/gene.py +5 -9
- scout/parse/variant/genotype.py +66 -42
- scout/parse/variant/variant.py +2 -0
- scout/server/app.py +71 -2
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +2 -0
- scout/server/blueprints/cases/controllers.py +1 -1
- scout/server/blueprints/cases/templates/cases/case_report.html +19 -2
- scout/server/blueprints/cases/templates/cases/utils.html +8 -29
- scout/server/blueprints/clinvar/controllers.py +233 -53
- scout/server/blueprints/clinvar/form.py +38 -1
- scout/server/blueprints/clinvar/static/form_style.css +8 -1
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_onc_submissions.html +200 -0
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +3 -2
- scout/server/blueprints/clinvar/templates/clinvar/components.html +198 -0
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_onc_variant.html +187 -0
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +9 -348
- scout/server/blueprints/clinvar/templates/clinvar/scripts.html +193 -0
- scout/server/blueprints/clinvar/views.py +90 -13
- scout/server/blueprints/institutes/controllers.py +44 -5
- scout/server/blueprints/institutes/forms.py +1 -0
- scout/server/blueprints/institutes/templates/overview/gene_variants.html +15 -6
- scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +28 -2
- scout/server/blueprints/institutes/templates/overview/utils.html +1 -1
- scout/server/blueprints/institutes/views.py +17 -4
- scout/server/blueprints/mme/templates/mme/mme_submissions.html +2 -2
- scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +2 -2
- scout/server/blueprints/variant/controllers.py +1 -1
- scout/server/blueprints/variant/templates/variant/cancer-variant.html +2 -1
- scout/server/blueprints/variant/templates/variant/components.html +0 -1
- scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -1
- scout/server/blueprints/variant/templates/variant/variant.html +2 -2
- scout/server/blueprints/variant/templates/variant/variant_details.html +33 -25
- scout/server/blueprints/variants/templates/variants/cancer-variants.html +5 -3
- scout/server/blueprints/variants/templates/variants/str-variants.html +4 -1
- scout/server/blueprints/variants/templates/variants/sv-variants.html +3 -3
- scout/server/blueprints/variants/templates/variants/utils.html +4 -0
- scout/server/blueprints/variants/templates/variants/variants.html +4 -4
- scout/server/extensions/clinvar_extension.py +2 -2
- scout/server/templates/layout.html +1 -1
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.1.dist-info}/METADATA +1 -1
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.1.dist-info}/RECORD +59 -53
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.1.dist-info}/WHEEL +0 -0
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.1.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.1.dist-info}/licenses/LICENSE +0 -0
@@ -617,42 +617,21 @@
|
|
617
617
|
</li>
|
618
618
|
{% endfor %}
|
619
619
|
</ul>
|
620
|
-
{{ clinvar_vars_summary(suspects, case, institute) }}
|
621
620
|
</div>
|
622
621
|
</div>
|
623
622
|
{% endmacro %}
|
624
623
|
|
625
624
|
{% macro clinvar_var_status(variant, case, institute) %}
|
626
|
-
{% if
|
625
|
+
{% if case.clinvar_variants and variant._id in case.clinvar_variants.keys() %}
|
626
|
+
(included in a ClinVar submission)
|
627
|
+
{% elif variant._id and variant.category in ["snv", "sv"] %}
|
627
628
|
<form id="clinvar_submit" class="d-flex justify-content-center" action="{{ url_for('clinvar.clinvar_add_variant', institute_id=institute._id, case_name=case.display_name) }}" method="POST">
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
<button type="submit" name="var_id" value="{{variant._id}}" class="btn btn-secondary btn-sm" style="float: right;">Add to ClinVar submission</button>
|
634
|
-
{% endif %}
|
629
|
+
<button type="submit" name="var_id" value="{{variant._id}}" class="btn btn-secondary btn-sm" style="float: right;">Add to ClinVar submission</button>
|
630
|
+
</form>
|
631
|
+
{% elif variant.category in ('cancer') %}
|
632
|
+
<form id="clinvar_onc_submit" class="d-flex justify-content-center" action="{{ url_for('clinvar.clinvar_add_onc_variant', institute_id=institute._id, case_name=case.display_name) }}" method="POST">
|
633
|
+
<button type="submit" name="var_id" value="{{variant._id}}" class="btn btn-secondary btn-sm" style="float: right;">Add to ClinVar submission</button>
|
635
634
|
</form>
|
636
|
-
{% endif %}
|
637
|
-
{% endmacro %}
|
638
|
-
|
639
|
-
{% macro clinvar_vars_summary(suspects, case, institute) %}
|
640
|
-
{% if case.clinvar_variants %}
|
641
|
-
{% if case.clinvar_variants_not_in_suspects | length >0 %}
|
642
|
-
<div class="d-flex align-content-center flex-wrap">
|
643
|
-
<div class="col-auto d-flex align-items-center wrap">
|
644
|
-
<h6 class="m-2"> Variants present in a ClinVar submission, no longer pinned:</h6>
|
645
|
-
</div>
|
646
|
-
{% for entry in case.clinvar_variants_not_in_suspects %}
|
647
|
-
<div class="m-2">{{ pretty_link_variant(entry, case) }}</div>
|
648
|
-
{% endfor %}
|
649
|
-
</div>
|
650
|
-
{% endif %}
|
651
|
-
<div class="card-footer d-flex justify-content-center pb-0" style="background-color:inherit;">
|
652
|
-
<a href="{{url_for('clinvar.clinvar_submissions', institute_id=institute._id)}}"
|
653
|
-
class="btn btn-secondary btn-sm text-white mx-3" target="_blank" rel="noopener noreferrer">View ClinVar
|
654
|
-
submissions <i class="fas fa-arrow-circle-right"></i></a>
|
655
|
-
</div>
|
656
635
|
{% endif %}
|
657
636
|
{% endmacro %}
|
658
637
|
|
@@ -2,13 +2,15 @@ import csv
|
|
2
2
|
import logging
|
3
3
|
from datetime import datetime
|
4
4
|
from tempfile import NamedTemporaryFile
|
5
|
-
from typing import List, Optional, Tuple
|
5
|
+
from typing import List, Optional, Tuple, Union
|
6
6
|
|
7
|
-
from flask import flash
|
7
|
+
from flask import flash, request
|
8
8
|
from flask_login import current_user
|
9
|
+
from pydantic_core._pydantic_core import ValidationError
|
9
10
|
from werkzeug.datastructures import ImmutableMultiDict
|
10
11
|
|
11
12
|
from scout.constants.acmg import ACMG_MAP
|
13
|
+
from scout.constants.ccv import CCV_MAP
|
12
14
|
from scout.constants.clinvar import (
|
13
15
|
CASEDATA_HEADER,
|
14
16
|
CLINVAR_HEADER,
|
@@ -16,14 +18,19 @@ from scout.constants.clinvar import (
|
|
16
18
|
SCOUT_CLINVAR_SV_TYPES_MAP,
|
17
19
|
)
|
18
20
|
from scout.constants.variant_tags import MANUAL_RANK_OPTIONS
|
19
|
-
from scout.models.clinvar import clinvar_variant
|
21
|
+
from scout.models.clinvar import OncogenicitySubmissionItem, clinvar_variant
|
20
22
|
from scout.server.blueprints.variant.utils import add_gene_info
|
21
23
|
from scout.server.extensions import clinvar_api, store
|
22
|
-
from scout.server.utils import get_case_genome_build
|
24
|
+
from scout.server.utils import get_case_genome_build, safe_redirect_back
|
23
25
|
from scout.utils.hgvs import validate_hgvs
|
24
26
|
from scout.utils.scout_requests import fetch_refseq_version
|
25
27
|
|
26
|
-
from .form import
|
28
|
+
from .form import (
|
29
|
+
CancerSNVariantForm,
|
30
|
+
CaseDataForm,
|
31
|
+
SNVariantForm,
|
32
|
+
SVariantForm,
|
33
|
+
)
|
27
34
|
|
28
35
|
LOG = logging.getLogger(__name__)
|
29
36
|
|
@@ -76,6 +83,7 @@ def _set_var_form_common_fields(var_form, variant_obj, case_obj):
|
|
76
83
|
var_form.case_id.data = case_obj["_id"]
|
77
84
|
var_form.local_id.data = variant_obj["_id"]
|
78
85
|
var_form.linking_id.data = variant_obj["_id"]
|
86
|
+
var_form.assembly.data = "GRCh38" if get_case_genome_build(case_obj) == "38" else "GRCh37"
|
79
87
|
var_form.chromosome.data = variant_obj.get("chromosome")
|
80
88
|
var_form.ref.data = variant_obj.get("reference")
|
81
89
|
var_form.alt.data = variant_obj.get("alternative")
|
@@ -101,7 +109,7 @@ def _set_var_form_common_fields(var_form, variant_obj, case_obj):
|
|
101
109
|
]
|
102
110
|
|
103
111
|
|
104
|
-
def _get_snv_var_form(variant_obj, case_obj):
|
112
|
+
def _get_snv_var_form(variant_obj: dict, case_obj: dict):
|
105
113
|
"""Sets up values for a SNV variant form
|
106
114
|
Args:
|
107
115
|
variant_obj(dict) scout.models.Variant
|
@@ -110,7 +118,10 @@ def _get_snv_var_form(variant_obj, case_obj):
|
|
110
118
|
Returns:
|
111
119
|
var_form(scout.server.blueprints.clinvar.form.SNVariantForm)
|
112
120
|
"""
|
113
|
-
|
121
|
+
if case_obj.get("track") == "cancer":
|
122
|
+
var_form = CancerSNVariantForm()
|
123
|
+
else:
|
124
|
+
var_form = SNVariantForm()
|
114
125
|
_set_var_form_common_fields(var_form, variant_obj, case_obj)
|
115
126
|
var_form.tx_hgvs.choices = _get_var_tx_hgvs(case_obj, variant_obj)
|
116
127
|
var_ids = variant_obj.get("dbsnp_id") or ""
|
@@ -145,25 +156,18 @@ def _get_sv_var_form(variant_obj, case_obj):
|
|
145
156
|
return var_form
|
146
157
|
|
147
158
|
|
148
|
-
def _populate_variant_form(
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
variant_obj(dict) scout.models.Variant
|
153
|
-
case_obj(dict) scout.models.Case
|
154
|
-
|
155
|
-
Return:
|
156
|
-
var_form(scout.server.blueprints.clinvar.form.SVariantForm or
|
157
|
-
scout.server.blueprints.clinvar.form.SNVariantForm )
|
158
|
-
|
159
|
-
"""
|
160
|
-
if variant_obj["category"] in ["snv", "cancer"]:
|
161
|
-
var_form = _get_snv_var_form(variant_obj, case_obj)
|
162
|
-
var_form.category.data = "snv"
|
159
|
+
def _populate_variant_form(
|
160
|
+
variant_obj: dict, case_obj: dict
|
161
|
+
) -> Union[SNVariantForm, SVariantForm, CancerSNVariantForm]:
|
162
|
+
"""Populate the Flaskform associated to a variant. This form will be used in the multistep ClinVar submission form."""
|
163
163
|
|
164
|
-
|
165
|
-
|
166
|
-
|
164
|
+
form_getters = {
|
165
|
+
"snv": _get_snv_var_form,
|
166
|
+
"sv": _get_sv_var_form,
|
167
|
+
"cancer": _get_snv_var_form,
|
168
|
+
}
|
169
|
+
category = variant_obj["category"]
|
170
|
+
var_form = form_getters[category](variant_obj, case_obj)
|
167
171
|
|
168
172
|
return var_form
|
169
173
|
|
@@ -188,11 +192,14 @@ def _populate_case_data_form(variant_obj, case_obj):
|
|
188
192
|
ind_form.include_ind.data = affected
|
189
193
|
ind_form.individual_id.data = ind.get("display_name")
|
190
194
|
ind_form.linking_id.data = variant_obj["_id"]
|
195
|
+
ind_form.allele_of_origin.data = (
|
196
|
+
"somatic" if case_obj.get("track") == "cancer" else "germline"
|
197
|
+
)
|
191
198
|
cdata_form_list.append(ind_form)
|
192
199
|
return cdata_form_list
|
193
200
|
|
194
201
|
|
195
|
-
def _variant_classification(var_obj):
|
202
|
+
def _variant_classification(var_obj: dict):
|
196
203
|
"""Set a 'classified_as' key/header_value in the variant object, to be displayed on
|
197
204
|
form page with the aim of aiding setting the mandatory 'clinsig' form field
|
198
205
|
|
@@ -204,6 +211,8 @@ def _variant_classification(var_obj):
|
|
204
211
|
"""
|
205
212
|
if "acmg_classification" in var_obj:
|
206
213
|
return ACMG_MAP[var_obj["acmg_classification"]]
|
214
|
+
elif "ccv_classification" in var_obj:
|
215
|
+
return CCV_MAP[var_obj["ccv_classification"]]
|
207
216
|
elif "manual_rank" in var_obj:
|
208
217
|
return MANUAL_RANK_OPTIONS[var_obj["manual_rank"]]["name"]
|
209
218
|
|
@@ -256,7 +265,9 @@ def _set_conditions(clinvar_var: dict, form: ImmutableMultiDict):
|
|
256
265
|
[f"{condition_prefix}{condition_id}" for condition_id in form.getlist("conditions")]
|
257
266
|
)
|
258
267
|
if bool(form.get("multiple_condition_explanation")):
|
259
|
-
clinvar_var["explanation_for_multiple_conditions"] = form
|
268
|
+
clinvar_var["explanation_for_multiple_conditions"] = form.get(
|
269
|
+
"multiple_condition_explanation"
|
270
|
+
)
|
260
271
|
|
261
272
|
|
262
273
|
def parse_variant_form_fields(form):
|
@@ -379,20 +390,22 @@ def update_clinvar_submission_status(request_obj, institute_id, submission_id):
|
|
379
390
|
send_api_submission(institute_id, submission_id, submitter_key)
|
380
391
|
|
381
392
|
|
382
|
-
def json_api_submission(submission_id):
|
383
|
-
"""
|
384
|
-
|
393
|
+
def json_api_submission(submission_id: str) -> Tuple[int, dict]:
|
394
|
+
"""Returns an integer and a json submission object as a dict. If the submission is of type "oncogenocity" there is no need for conversion and can be used as is.
|
395
|
+
Germline submission objects (Variant and Casedata database documents) are converted to a json submission using
|
396
|
+
the PreClinVar service.
|
397
|
+
"""
|
385
398
|
|
386
|
-
|
387
|
-
submission_id
|
399
|
+
json_submission: dict = store.get_onc_submission_json(
|
400
|
+
submission=submission_id
|
401
|
+
) # Oncogenocity submissions are already saved in the desired format
|
402
|
+
if json_submission:
|
403
|
+
return 200, json_submission
|
388
404
|
|
389
|
-
|
390
|
-
|
391
|
-
"""
|
392
|
-
variant_data = store.clinvar_objs(submission_id, "variant_data")
|
393
|
-
obs_data = store.clinvar_objs(submission_id, "case_data")
|
405
|
+
variant_data: list = store.clinvar_objs(submission_id, "variant_data")
|
406
|
+
obs_data: list = store.clinvar_objs(submission_id, "case_data")
|
394
407
|
|
395
|
-
if
|
408
|
+
if not variant_data or not obs_data:
|
396
409
|
return (400, "Submission must contain both Variant and CaseData info")
|
397
410
|
|
398
411
|
# Retrieve eventual assertion criteria for the submission
|
@@ -569,6 +582,24 @@ def _clinvar_submission_header(submission_objs, csv_type):
|
|
569
582
|
return custom_header
|
570
583
|
|
571
584
|
|
585
|
+
def add_clinvar_events(institute_obj: dict, case_obj: dict, variant_id: str):
|
586
|
+
"""Create case and variant-related events when a variants gets added to a ClinVar submission object."""
|
587
|
+
|
588
|
+
variant_obj: dict = store.variant(document_id=variant_id)
|
589
|
+
user_obj: dict = store.user(user_id=current_user._id)
|
590
|
+
for category in ["case", "variant"]:
|
591
|
+
store.create_event(
|
592
|
+
institute=institute_obj,
|
593
|
+
case=case_obj,
|
594
|
+
user=user_obj,
|
595
|
+
link=f"/{institute_obj['_id']}/{case_obj['display_name']}/{variant_obj['_id']}",
|
596
|
+
category=category,
|
597
|
+
verb="clinvar_add",
|
598
|
+
variant=variant_obj,
|
599
|
+
subject=variant_obj["display_name"],
|
600
|
+
)
|
601
|
+
|
602
|
+
|
572
603
|
def add_variant_to_submission(institute_obj: dict, case_obj: dict, form: ImmutableMultiDict):
|
573
604
|
"""It is invoked by the 'clinvar_save' endpoint. Adds one variant with eventual CaseData observations to an open (or new) ClinVar submission."""
|
574
605
|
|
@@ -576,8 +607,8 @@ def add_variant_to_submission(institute_obj: dict, case_obj: dict, form: Immutab
|
|
576
607
|
casedata_list: List[dict] = parse_casedata_form_fields(form)
|
577
608
|
institute_id = institute_obj["_id"]
|
578
609
|
|
579
|
-
# retrieve or create an open ClinVar submission:
|
580
|
-
subm: dict = store.
|
610
|
+
# retrieve or create an open germline ClinVar submission:
|
611
|
+
subm: dict = store.get_open_germline_clinvar_submission(institute_id, current_user._id)
|
581
612
|
# save submission objects in submission:
|
582
613
|
result: Optional[dict] = store.add_to_submission(subm["_id"], (variant_data, casedata_list))
|
583
614
|
if result:
|
@@ -585,20 +616,11 @@ def add_variant_to_submission(institute_obj: dict, case_obj: dict, form: Immutab
|
|
585
616
|
"An open ClinVar submission was updated correctly with submitted data",
|
586
617
|
"success",
|
587
618
|
)
|
619
|
+
|
588
620
|
# Create user-related events
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
store.create_event(
|
593
|
-
institute=institute_obj,
|
594
|
-
case=case_obj,
|
595
|
-
user=user_obj,
|
596
|
-
link=f"/{institute_id}/{case_obj['display_name']}/{variant_obj['_id']}",
|
597
|
-
category=category,
|
598
|
-
verb="clinvar_add",
|
599
|
-
variant=variant_obj,
|
600
|
-
subject=variant_obj["display_name"],
|
601
|
-
)
|
621
|
+
add_clinvar_events(
|
622
|
+
institute_obj=institute_obj, case_obj=case_obj, variant_id=form.get("linking_id")
|
623
|
+
)
|
602
624
|
|
603
625
|
|
604
626
|
def remove_item_from_submission(submission: str, object_type: str, subm_variant_id: str):
|
@@ -632,3 +654,161 @@ def remove_item_from_submission(submission: str, object_type: str, subm_variant_
|
|
632
654
|
variant=variant_obj,
|
633
655
|
subject=variant_obj["display_name"],
|
634
656
|
)
|
657
|
+
|
658
|
+
|
659
|
+
### ClinVar oncogenicity variants submissions controllers
|
660
|
+
|
661
|
+
|
662
|
+
def set_onc_clinvar_form(var_id: str, data: dict):
|
663
|
+
"""Adds form key/values to the form used in ClinVar to create a multistep submission page for an oncogenic variant."""
|
664
|
+
|
665
|
+
var_obj = store.variant(var_id)
|
666
|
+
if not var_obj:
|
667
|
+
return
|
668
|
+
|
669
|
+
var_obj["classification"] = _variant_classification(var_obj)
|
670
|
+
|
671
|
+
var_form = _populate_variant_form(var_obj, data["case"]) # variant-associated form
|
672
|
+
cdata_forms = _populate_case_data_form(var_obj, data["case"]) # CaseData form
|
673
|
+
variant_data = {
|
674
|
+
"var_id": var_id,
|
675
|
+
"var_obj": var_obj,
|
676
|
+
"var_form": var_form,
|
677
|
+
"cdata_forms": cdata_forms,
|
678
|
+
}
|
679
|
+
data["variant_data"] = variant_data
|
680
|
+
|
681
|
+
|
682
|
+
def _parse_onc_classification(onc_item: dict, form: ImmutableMultiDict):
|
683
|
+
"""Assigns an oncogenicity classification to a submission item based on the user form."""
|
684
|
+
onc_item["oncogenicityClassification"] = {
|
685
|
+
"oncogenicityClassificationDescription": form.get("onc_classification"),
|
686
|
+
"dateLastEvaluated": form.get("last_evaluated"),
|
687
|
+
}
|
688
|
+
if form.get("clinsig_comment"):
|
689
|
+
onc_item["oncogenicityClassification"]["comment"] = form.get("clinsig_comment")
|
690
|
+
|
691
|
+
|
692
|
+
def _parse_onc_assertion(onc_item: dict, form: ImmutableMultiDict):
|
693
|
+
"""Adds to an oncogenicity classification item the specifics of the user classification."""
|
694
|
+
|
695
|
+
if form.get("assertion_method_cit_id"):
|
696
|
+
onc_item["oncogenicityClassification"]["citation"] = [
|
697
|
+
{
|
698
|
+
"db": form.get("assertion_method_cit_db"),
|
699
|
+
"id": form.get("assertion_method_cit_id"),
|
700
|
+
}
|
701
|
+
]
|
702
|
+
|
703
|
+
|
704
|
+
def _parse_variant_set(onc_item: dict, form: ImmutableMultiDict):
|
705
|
+
"""Parse variant specifics from the ClinVar user form. It's an array but we support oonly one variant per oncogenic item."""
|
706
|
+
|
707
|
+
variant = {}
|
708
|
+
if form.get("tx_hgvs") not in [None, "Do not specify"]:
|
709
|
+
variant["hgvs"] = form["tx_hgvs"]
|
710
|
+
else: # Use coordinates
|
711
|
+
variant["chromosomeCoordinates"] = {
|
712
|
+
"assembly": form.get("assembly"),
|
713
|
+
"chromosome": "MT" if form.get("chromosome") == "M" else form.get("chromosome"),
|
714
|
+
"start": int(form.get("start")),
|
715
|
+
"stop": int(form.get("stop")),
|
716
|
+
"alternateAllele": form.get("alt"),
|
717
|
+
}
|
718
|
+
|
719
|
+
if form.get("gene_symbol"):
|
720
|
+
variant["gene"] = [{"symbol": form["gene_symbol"]}]
|
721
|
+
|
722
|
+
onc_item["variantSet"] = {"variant": [variant]}
|
723
|
+
|
724
|
+
|
725
|
+
def _parse_condition_set(onc_item: dict, form: ImmutableMultiDict):
|
726
|
+
"""Associate one or more phenotype conditions to a variant of a ClinVar submission."""
|
727
|
+
onc_item["conditionSet"] = {"condition": []}
|
728
|
+
selected_db = form.get("condition_type")
|
729
|
+
selected_conditions: List[str] = form.getlist("conditions")
|
730
|
+
for cond in selected_conditions:
|
731
|
+
onc_item["conditionSet"]["condition"].append({"db": selected_db, "id": cond})
|
732
|
+
if form.get("multiple_condition_explanation"):
|
733
|
+
onc_item["conditionSet"]["multipleConditionExplanation"] = form.get(
|
734
|
+
"multiple_condition_explanation"
|
735
|
+
)
|
736
|
+
|
737
|
+
|
738
|
+
def _parse_observations(onc_item: dict, form: ImmutableMultiDict):
|
739
|
+
"""Associates observations to a variant of a ClinVar submission."""
|
740
|
+
onc_item["observedIn"] = []
|
741
|
+
include_inds = form.getlist("include_ind")
|
742
|
+
ind_list = form.getlist("individual_id")
|
743
|
+
affected_status_list = form.getlist("affected_status")
|
744
|
+
allele_origin_list = form.getlist("allele_of_origin")
|
745
|
+
collection_method_list = form.getlist("collection_method")
|
746
|
+
somatic_fraction = form.getlist("somatic_allele_fraction")
|
747
|
+
somatic_in_normal = form.getlist("somatic_allele_in_normal")
|
748
|
+
|
749
|
+
for idx, ind_id in enumerate(ind_list):
|
750
|
+
if ind_id not in include_inds:
|
751
|
+
continue
|
752
|
+
|
753
|
+
obs = {
|
754
|
+
"alleleOrigin": allele_origin_list[idx],
|
755
|
+
"affectedStatus": affected_status_list[idx],
|
756
|
+
"collectionMethod": collection_method_list[idx],
|
757
|
+
"numberOfIndividuals": 1,
|
758
|
+
"presenceOfSomaticVariantInNormalTissue": somatic_in_normal[idx],
|
759
|
+
}
|
760
|
+
if somatic_fraction[idx]:
|
761
|
+
obs["somaticVariantAlleleFraction"] = int(somatic_fraction[idx])
|
762
|
+
|
763
|
+
onc_item["observedIn"].append(obs)
|
764
|
+
|
765
|
+
|
766
|
+
def parse_clinvar_onc_item(form: ImmutableMultiDict) -> dict:
|
767
|
+
"""Parse form fields for an oncogenic classication of a variant and converts it into the format extected by ClinVar (json dict)."""
|
768
|
+
onc_item = {"recordStatus": "novel"}
|
769
|
+
_parse_onc_classification(onc_item, form)
|
770
|
+
_parse_onc_assertion(onc_item, form)
|
771
|
+
_parse_variant_set(onc_item, form)
|
772
|
+
_parse_condition_set(onc_item, form)
|
773
|
+
_parse_observations(onc_item, form)
|
774
|
+
|
775
|
+
return onc_item
|
776
|
+
|
777
|
+
|
778
|
+
def add_onc_variant_to_submission(institute_obj: dict, case_obj: dict, form: ImmutableMultiDict):
|
779
|
+
"""Adds a somatic variant to a pre-existing open oncogeginicty seubmission. If the latter doesn't exists it creates it."""
|
780
|
+
|
781
|
+
onc_item: dict = parse_clinvar_onc_item(form) # The variant item to add to an open submission
|
782
|
+
|
783
|
+
# Add case specifics to the submission item
|
784
|
+
onc_item["institute_id"] = institute_obj["_id"]
|
785
|
+
onc_item["case_id"] = case_obj["_id"]
|
786
|
+
onc_item["case_name"] = case_obj.get("display_name", "_id")
|
787
|
+
onc_item["variant_id"] = form.get("linking_id")
|
788
|
+
|
789
|
+
# Validate oncogenicity item model
|
790
|
+
try:
|
791
|
+
OncogenicitySubmissionItem(**onc_item)
|
792
|
+
except ValidationError as ve:
|
793
|
+
LOG.error(ve)
|
794
|
+
flash(str(ve), "warning")
|
795
|
+
return
|
796
|
+
|
797
|
+
# retrieve or create an open ClinVar submission:
|
798
|
+
onc_subm: dict = store.get_open_onc_clinvar_submission(
|
799
|
+
institute_id=institute_obj["_id"], user_id=current_user._id
|
800
|
+
)
|
801
|
+
# Add variant to submission object
|
802
|
+
onc_subm.setdefault("oncogenicitySubmission", []).append(onc_item)
|
803
|
+
onc_subm["updated_at"] = datetime.now()
|
804
|
+
store.clinvar_submission_collection.find_one_and_replace({"_id": onc_subm["_id"]}, onc_subm)
|
805
|
+
|
806
|
+
# update case with submission info
|
807
|
+
add_clinvar_events(
|
808
|
+
institute_obj=institute_obj, case_obj=case_obj, variant_id=form.get("linking_id")
|
809
|
+
)
|
810
|
+
|
811
|
+
flash(
|
812
|
+
"An open ClinVar submission was updated correctly with the variant details.",
|
813
|
+
"success",
|
814
|
+
)
|
@@ -28,6 +28,12 @@ from scout.constants import (
|
|
28
28
|
GERMLINE_CLASSIF_TERMS,
|
29
29
|
MULTIPLE_CONDITION_EXPLANATION,
|
30
30
|
)
|
31
|
+
from scout.constants.clinvar import (
|
32
|
+
CITATION_DBS_API,
|
33
|
+
CONDITION_DBS_API,
|
34
|
+
ONCOGENIC_CLASSIF_TERMS,
|
35
|
+
PRESENCE_IN_NORMAL_TISSUE,
|
36
|
+
)
|
31
37
|
|
32
38
|
LOG = logging.getLogger(__name__)
|
33
39
|
|
@@ -47,6 +53,7 @@ class ClinVarVariantForm(FlaskForm):
|
|
47
53
|
linking_id = HiddenField()
|
48
54
|
ref = HiddenField()
|
49
55
|
alt = HiddenField()
|
56
|
+
assembly = HiddenField()
|
50
57
|
gene_symbol = StringField("Gene symbols, comma-separated")
|
51
58
|
inheritance_mode = SelectField(
|
52
59
|
"Inheritance model",
|
@@ -123,7 +130,7 @@ class CaseDataForm(FlaskForm):
|
|
123
130
|
Schema available here: https://github.com/Clinical-Genomics/preClinVar/blob/718905521590196dc84fd576bc43d9fac418b97a/preClinVar/resources/submission_schema.json#L288
|
124
131
|
"""
|
125
132
|
|
126
|
-
include_ind = BooleanField("Include
|
133
|
+
include_ind = BooleanField("Include")
|
127
134
|
individual_id = StringField("Individual ID")
|
128
135
|
linking_id = HiddenField()
|
129
136
|
affected_status = SelectField(
|
@@ -137,3 +144,33 @@ class CaseDataForm(FlaskForm):
|
|
137
144
|
default="clinical testing",
|
138
145
|
choices=[(item, item) for item in COLLECTION_METHOD],
|
139
146
|
)
|
147
|
+
somatic_allele_fraction = IntegerField("Somatic allele fraction")
|
148
|
+
somatic_allele_in_normal = SelectField( # Overriding default values
|
149
|
+
"Allele present in normal tissue",
|
150
|
+
default="absent",
|
151
|
+
choices=[(item, item) for item in PRESENCE_IN_NORMAL_TISSUE],
|
152
|
+
)
|
153
|
+
|
154
|
+
|
155
|
+
### Cancer variant - related forms
|
156
|
+
|
157
|
+
|
158
|
+
class CancerSNVariantForm(SNVariantForm):
|
159
|
+
"""Contains the form element to add a cancer variant to a ClinVar oncogenicity submission object."""
|
160
|
+
|
161
|
+
# Form step 1: Oncogenicity classification
|
162
|
+
record_status = HiddenField(default="novel")
|
163
|
+
onc_classification = SelectField(
|
164
|
+
"Oncogenicity classification",
|
165
|
+
choices=[(item, item) for item in ONCOGENIC_CLASSIF_TERMS],
|
166
|
+
)
|
167
|
+
assertion_method_cit_db = SelectField( # Overriding default values
|
168
|
+
"Citation DB",
|
169
|
+
default="clinical testing",
|
170
|
+
choices=[(item, item) for item in CITATION_DBS_API],
|
171
|
+
)
|
172
|
+
assertion_method_cit_id = StringField("Citation ID") # Overriding default values
|
173
|
+
|
174
|
+
condition_type = SelectField(
|
175
|
+
"Condition ID type", choices=[(item, item) for item in CONDITION_DBS_API]
|
176
|
+
)
|
@@ -126,12 +126,19 @@ padding: 0;
|
|
126
126
|
color: white;
|
127
127
|
text-transform: uppercase;
|
128
128
|
font-size: 12px;
|
129
|
-
width: 14.28%;
|
130
129
|
float: left;
|
131
130
|
position: relative;
|
132
131
|
letter-spacing: 1px;
|
133
132
|
}
|
134
133
|
|
134
|
+
#progressbar.steps-5 li {
|
135
|
+
width: 20%;
|
136
|
+
}
|
137
|
+
|
138
|
+
#progressbar.steps-7 li {
|
139
|
+
width: 14.28%;
|
140
|
+
}
|
141
|
+
|
135
142
|
#progressbar li:before {
|
136
143
|
content: counter(step);
|
137
144
|
counter-increment: step;
|