Exemple #1
0
def get_sanger_unevaluated(store, institute_id, user_id):
    """Get all variants for an institute having Sanger validations ordered but still not evaluated

    Args:
        store(scout.adapter.MongoAdapter)
        institute_id(str)

    Returns:
        unevaluated: a list that looks like this: [ {'case1': [varID_1, varID_2, .., varID_n]}, {'case2' : [varID_1, varID_2, .., varID_n]} ],
                     where the keys are case_ids and the values are lists of variants with Sanger ordered but not yet validated

    """

    # Retrieve a list of ids for variants with Sanger ordered grouped by case from the 'event' collection
    # This way is much faster than querying over all variants in all cases of an institute
    sanger_ordered_by_case = store.sanger_ordered(institute_id, user_id)
    unevaluated = []

    # for each object where key==case and value==[variant_id with Sanger ordered]
    for item in sanger_ordered_by_case:
        case_id = item["_id"]
        # Get the case to collect display name
        case_obj = store.case(case_id=case_id)

        if not case_obj:  # the case might have been removed
            continue

        case_display_name = case_obj.get("display_name")

        # List of variant document ids
        varid_list = item["vars"]

        unevaluated_by_case = {}
        unevaluated_by_case[case_display_name] = []

        for var_id in varid_list:
            # For each variant with sanger validation ordered
            variant_obj = store.variant(document_id=var_id, case_id=case_id)

            # Double check that Sanger was ordered (and not canceled) for the variant
            if (
                variant_obj is None
                or variant_obj.get("sanger_ordered") is None
                or variant_obj.get("sanger_ordered") is False
            ):
                continue

            validation = variant_obj.get("validation", "not_evaluated")

            # Check that the variant is not evaluated
            if validation in ["True positive", "False positive"]:
                continue

            unevaluated_by_case[case_display_name].append(variant_obj["_id"])

        # If for a case there is at least one Sanger validation to evaluate add the object to the unevaluated objects list
        if len(unevaluated_by_case[case_display_name]) > 0:
            unevaluated.append(unevaluated_by_case)

    return unevaluated
Exemple #2
0
def mark_causative(institute_id,
                   case_name,
                   variant_id,
                   partial_causative=False):
    """Mark a variant as confirmed causative."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = url_for("variant.variant",
                   institute_id=institute_id,
                   case_name=case_name,
                   variant_id=variant_id)
    if request.form["action"] == "ADD":
        if "partial_causative" in request.form:
            omim_terms = request.form.getlist("omim_select")
            hpo_terms = request.form.getlist("hpo_select")
            store.mark_partial_causative(institute_obj, case_obj, user_obj,
                                         link, variant_obj, omim_terms,
                                         hpo_terms)
        else:
            store.mark_causative(institute_obj, case_obj, user_obj, link,
                                 variant_obj)
    elif request.form["action"] == "DELETE":
        if partial_causative == "True":
            store.unmark_partial_causative(institute_obj, case_obj, user_obj,
                                           link, variant_obj)
        else:
            store.unmark_causative(institute_obj, case_obj, user_obj, link,
                                   variant_obj)

    # send the user back to the case that was marked as solved
    case_url = url_for(".case", institute_id=institute_id, case_name=case_name)
    return redirect(request.referrer)
Exemple #3
0
def verify(institute_id, case_name, variant_id, variant_category, order):
    """Start procedure to validate variant using other techniques."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)

    comment = request.form.get('verification_comment')

    try:
        controllers.variant_verification(
            store=store,
            mail=mail,
            institute_obj=institute_obj,
            case_obj=case_obj,
            user_obj=user_obj,
            comment=comment,
            variant_obj=variant_obj,
            sender=current_app.config['MAIL_USERNAME'],
            variant_url=request.referrer,
            order=order,
            url_builder=url_for)
    except controllers.MissingVerificationRecipientError:
        flash('No verification recipients added to institute.', 'danger')

    return redirect(request.referrer)
Exemple #4
0
def marrvel_link(build, variant_id):
    """Redirect to MARRVEL when user clicks on the relative button on variant page"""
    variant_obj = store.variant(document_id=variant_id)
    build = "38" if "38" in str(build) else "37"

    url_template = "http://marrvel.org/human/variant/{}:{} {}>{}"
    chrom = variant_obj["chromosome"]
    start = variant_obj["position"]
    ref = variant_obj["reference"]
    alt = variant_obj["alternative"]

    if build == "38":  # liftover is necessary before returning link
        client = EnsemblRestApiClient()
        mapped_coords = client.liftover(
            build,
            chrom,
            start,
        )
        if mapped_coords:
            chrom = mapped_coords[0]["mapped"].get("seq_region_name")
            start = mapped_coords[0]["mapped"].get("start")
        else:
            flash(
                "MARRVEL requires variant coordinates in genome build 37, but variant liftover failed",
                "warning",
            )
            return redirect(request.referrer)

    return redirect(url_template.format(chrom, start, ref, alt), code=302)
Exemple #5
0
def variant_update(institute_id, case_name, variant_id):
    """Update user-defined information about a variant: manual rank & ACMG."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = request.referrer

    manual_rank = request.form.get('manual_rank')
    if manual_rank:
        new_manual_rank = int(manual_rank) if manual_rank != '-1' else None
        store.update_manual_rank(institute_obj, case_obj, user_obj, link,
                                 variant_obj, new_manual_rank)
        if new_manual_rank:
            flash("updated variant tag: {}".format(new_manual_rank), 'info')
        else:
            flash("reset variant tag: {}".format(variant_obj['manual_rank']),
                  'info')
    elif request.form.get('acmg_classification'):
        new_acmg = request.form['acmg_classification']
        acmg_classification = variant_obj.get('acmg_classification')
        if isinstance(acmg_classification,
                      int) and (new_acmg == ACMG_MAP[acmg_classification]):
            new_acmg = None
        store.update_acmg(institute_obj, case_obj, user_obj, link, variant_obj,
                          new_acmg)
        flash("updated ACMG classification: {}".format(new_acmg), 'info')
    return redirect(request.referrer)
Exemple #6
0
def events(institute_id, case_name, event_id=None):
    """Handle events."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    link = request.form.get("link")
    content = request.form.get("content")
    variant_id = request.args.get("variant_id")
    user_obj = store.user(current_user.email)

    if event_id:
        # delete the event
        store.delete_event(event_id)
    else:
        if variant_id:
            # create a variant comment
            variant_obj = store.variant(variant_id)
            level = request.form.get("level", "specific")
            store.comment(
                institute_obj,
                case_obj,
                user_obj,
                link,
                variant=variant_obj,
                content=content,
                comment_level=level,
            )
        else:
            # create a case comment
            store.comment(institute_obj,
                          case_obj,
                          user_obj,
                          link,
                          content=content)

    return redirect(request.referrer)
def test_causatives(app, user_obj, institute_obj, case_obj):
    # GIVEN an initialized app
    # GIVEN a valid user and institute
    # There should be no causative variants for test case:
    assert "causatives" not in case_obj
    var1_id = "4c7d5c70d955875504db72ef8e1abe77"  # in POT1 gene
    var2_id = "e24b65bf27feacec6a81c8e9e19bd5f1"  # in TBX1 gene
    var_ids = [var1_id, var2_id]

    # for each variant
    for var_id in var_ids:
        # update case by marking variant as causative:
        variant_obj = store.variant(document_id=var_id)
        store.mark_causative(
            institute=institute_obj,
            case=case_obj,
            user=user_obj,
            link="causative_var_link/{}".format(variant_obj["_id"]),
            variant=variant_obj,
        )
    updated_case = store.case_collection.find_one({"_id": case_obj["_id"]})
    # The above variants should be registered as causatives in case object
    assert updated_case["causatives"] == var_ids

    # Call scout causatives view and check if the above causatives are displayed
    with app.test_client() as client:

        # GIVEN that the user could be logged in
        resp = client.get(url_for("auto_login"))
        assert resp.status_code == 200

        # WHEN accessing the case page
        resp = client.get(
            url_for("overview.causatives",
                    institute_id=institute_obj["internal_id"]))

        # THEN it should return a page
        assert resp.status_code == 200
        # with variant 1
        assert var1_id in str(resp.data)
        # and variant 2
        assert var2_id in str(resp.data)

        # Filter causatives by gene (POT1)
        resp = client.get(
            url_for(
                "overview.causatives",
                institute_id=institute_obj["internal_id"],
                query="17284 | POT1 (DKFZp586D211, hPot1, POT1)",
            ))
        # THEN it should return a page
        assert resp.status_code == 200
        # with variant 1
        assert var1_id in str(resp.data)
        # but NOT variant 2
        assert var2_id not in str(resp.data)
Exemple #8
0
def mark_validation(institute_id, case_name, variant_id):
    """Mark a variant as sanger validated."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    validate_type = request.form['type'] or None
    link = url_for('variants.variant', institute_id=institute_id, case_name=case_name,
                   variant_id=variant_id)
    store.validate(institute_obj, case_obj, user_obj, link, variant_obj, validate_type)
    return redirect(request.referrer or link)
Exemple #9
0
def mark_validation(institute_id, case_name, variant_id):
    """Mark a variant as sanger validated."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    validate_type = request.form['type'] or None
    link = url_for('variants.variant', institute_id=institute_id, case_name=case_name,
                   variant_id=variant_id)
    store.validate(institute_obj, case_obj, user_obj, link, variant_obj, validate_type)
    return redirect(request.referrer or link)
Exemple #10
0
def manual_rank(institute_id, case_name, variant_id):
    """Update the manual variant rank for a variant."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    new_manual_rank = int(request.form['manual_rank'])
    link = request.referrer
    store.update_manual_rank(institute_obj, case_obj, user_obj, link,
                             variant_obj, new_manual_rank)
    return redirect(request.referrer)
Exemple #11
0
def variant_update(institute_id, case_name, variant_id):
    """Update user-defined information about a variant: manual rank & ACMG."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = request.referrer

    manual_rank = request.form.get('manual_rank')
    if manual_rank:
        new_manual_rank = int(manual_rank) if manual_rank != '-1' else None
        store.update_manual_rank(institute_obj, case_obj, user_obj, link, variant_obj,
                                 new_manual_rank)
        if new_manual_rank:
            flash("updated variant tag: {}".format(new_manual_rank), 'info')
        else:
            flash("reset variant tag: {}".format(variant_obj.get('manual_rank', 'NA')), 'info')
    elif request.form.get('acmg_classification'):
        new_acmg = request.form['acmg_classification']
        acmg_classification = variant_obj.get('acmg_classification')
        if isinstance(acmg_classification, int) and (new_acmg == ACMG_MAP[acmg_classification]):
            new_acmg = None
        store.update_acmg(institute_obj, case_obj, user_obj, link, variant_obj, new_acmg)
        flash("updated ACMG classification: {}".format(new_acmg), 'info')

    new_dismiss = request.form.getlist('dismiss_variant')
    if request.form.getlist('dismiss_variant'):
        store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj,
                                     new_dismiss)
        if new_dismiss:
            flash("Dismissed variant: {}".format(new_dismiss), 'info')

    if variant_obj.get('dismiss_variant') and not new_dismiss:
        if 'dismiss' in request.form:
            store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj,
                                     new_dismiss)
            flash("Reset variant dismissal: {}".format(variant_obj.get('dismiss_variant')), 'info')
        else:
            log.debug("DO NOT reset variant dismissal: {}".format(variant_obj.get('dismiss_variant')), 'info')

    mosaic_tags = request.form.getlist('mosaic_tags')
    if mosaic_tags:
        store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj,
                                     mosaic_tags)
        if new_dismiss:
            flash("Added mosaic tags: {}".format(mosaic_tags), 'info')

    if variant_obj.get('mosaic_tags') and not mosaic_tags:
        if 'mosaic' in request.form:
            store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj,
                                     mosaic_tags)
            flash("Reset mosaic tags: {}".format(variant_obj.get('mosaic_tags')), 'info')

    return redirect(request.referrer)
Exemple #12
0
def pin_variant(institute_id, case_name, variant_id):
    """Pin and unpin variants to/from the list of suspects."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = url_for('variants.variant', institute_id=institute_id, case_name=case_name,
                   variant_id=variant_id)
    if request.form['action'] == 'ADD':
        store.pin_variant(institute_obj, case_obj, user_obj, link, variant_obj)
    elif request.form['action'] == 'DELETE':
        store.unpin_variant(institute_obj, case_obj, user_obj, link, variant_obj)
    return redirect(request.referrer or link)
Exemple #13
0
def variant_update(institute_id, case_name, variant_id):
    """Update user-defined information about a variant: manual rank & ACMG."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = request.referrer

    manual_rank = request.form.get('manual_rank')
    if manual_rank:
        new_manual_rank = int(manual_rank) if manual_rank != '-1' else None
        store.update_manual_rank(institute_obj, case_obj, user_obj, link, variant_obj,
                                 new_manual_rank)
        if new_manual_rank:
            flash("updated variant tag: {}".format(new_manual_rank), 'info')
        else:
            flash("reset variant tag: {}".format(variant_obj.get('manual_rank', 'NA')), 'info')
    elif request.form.get('acmg_classification'):
        new_acmg = request.form['acmg_classification']
        acmg_classification = variant_obj.get('acmg_classification')
        if isinstance(acmg_classification, int) and (new_acmg == ACMG_MAP[acmg_classification]):
            new_acmg = None
        store.update_acmg(institute_obj, case_obj, user_obj, link, variant_obj, new_acmg)
        flash("updated ACMG classification: {}".format(new_acmg), 'info')

    new_dismiss = request.form.getlist('dismiss_variant')
    if request.form.getlist('dismiss_variant'):
        store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj,
                                     new_dismiss)
        if new_dismiss:
            flash("Dismissed variant: {}".format(new_dismiss), 'info')

    if variant_obj.get('dismiss_variant') and not new_dismiss:
        if 'dismiss' in request.form:
            store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj,
                                     new_dismiss)
            flash("Reset variant dismissal: {}".format(variant_obj.get('dismiss_variant')), 'info')
        else:
            log.debug("DO NOT reset variant dismissal: {}".format(variant_obj.get('dismiss_variant')), 'info')

    mosaic_tags = request.form.getlist('mosaic_tags')
    if mosaic_tags:
        store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj,
                                     mosaic_tags)
        if new_dismiss:
            flash("Added mosaic tags: {}".format(mosaic_tags), 'info')

    if variant_obj.get('mosaic_tags') and not mosaic_tags:
        if 'mosaic' in request.form:
            store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj,
                                     mosaic_tags)
            flash("Reset mosaic tags: {}".format(variant_obj.get('mosaic_tags')), 'info')

    return redirect(request.referrer)
Exemple #14
0
def pin_variant(institute_id, case_name, variant_id):
    """Pin and unpin variants to/from the list of suspects."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = url_for('variants.variant', institute_id=institute_id, case_name=case_name,
                   variant_id=variant_id)
    if request.form['action'] == 'ADD':
        store.pin_variant(institute_obj, case_obj, user_obj, link, variant_obj)
    elif request.form['action'] == 'DELETE':
        store.unpin_variant(institute_obj, case_obj, user_obj, link, variant_obj)
    return redirect(request.referrer or link)
Exemple #15
0
def sanger(institute_id, case_name, variant_id):
    """Send Sanger email for confirming a variant."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    try:
        controllers.sanger(store, mail, institute_obj, case_obj, user_obj,
                           variant_obj, current_app.config['MAIL_USERNAME'])
    except controllers.MissingSangerRecipientError:
        flash('No sanger recipients added to institute.', 'danger')
    return redirect(request.referrer)
Exemple #16
0
def mark_causative(institute_id, case_name, variant_id):
    """Mark a variant as confirmed causative."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = url_for('variants.variant', institute_id=institute_id, case_name=case_name,
                   variant_id=variant_id)
    if request.form['action'] == 'ADD':
        store.mark_causative(institute_obj, case_obj, user_obj, link, variant_obj)
    elif request.form['action'] == 'DELETE':
        store.unmark_causative(institute_obj, case_obj, user_obj, link, variant_obj)

    # send the user back to the case that was marked as solved
    case_url = url_for('.case', institute_id=institute_id, case_name=case_name)
    return redirect(case_url)
Exemple #17
0
def mark_causative(institute_id, case_name, variant_id):
    """Mark a variant as confirmed causative."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = url_for('variants.variant', institute_id=institute_id, case_name=case_name,
                   variant_id=variant_id)
    if request.form['action'] == 'ADD':
        store.mark_causative(institute_obj, case_obj, user_obj, link, variant_obj)
    elif request.form['action'] == 'DELETE':
        store.unmark_causative(institute_obj, case_obj, user_obj, link, variant_obj)

    # send the user back to the case that was marked as solved
    case_url = url_for('.case', institute_id=institute_id, case_name=case_name)
    return redirect(case_url)
Exemple #18
0
def verify(institute_id, case_name, variant_id, variant_category, order):
    """Start procedure to validate variant using other techniques."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)

    comment = request.form.get('verification_comment')
    
    try:
        controllers.variant_verification(store=store, mail=mail, institute_obj=institute_obj, case_obj=case_obj, user_obj=user_obj, comment=comment,
                           variant_obj=variant_obj, sender=current_app.config['MAIL_USERNAME'], variant_url=request.referrer, order=order, url_builder=url_for)
    except controllers.MissingVerificationRecipientError:
        flash('No verification recipients added to institute.', 'danger')

    return redirect(request.referrer)
Exemple #19
0
def events(institute_id, case_name, event_id=None):
    """Handle events."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    link = request.form.get('link')
    content = request.form.get('content')
    variant_id = request.args.get('variant_id')
    user_obj = store.user(current_user.email)

    if event_id:
        # delete the event
        store.delete_event(event_id)
    else:
        if variant_id:
            # create a variant comment
            variant_obj = store.variant(variant_id)
            level = request.form.get('level', 'specific')
            store.comment(institute_obj, case_obj, user_obj, link,
                          variant=variant_obj, content=content, comment_level=level)
        else:
            # create a case comment
            store.comment(institute_obj, case_obj, user_obj, link, content=content)

    return redirect(request.referrer)
Exemple #20
0
def variant(institute_id, case_name, variant_id):
    """Display a specific SNV variant."""
    institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
    variant_obj = store.variant(variant_id)
    return Response(json_util.dumps(variant_obj), mimetype='application/json')
def make_sashimi_tracks(case_obj, variant_id):
    """Create a dictionary containing the required tracks for a splice junction plot

    Args:
        case_obj(scout.models.Case)
        variant_id(str) _id of a variant
    Returns:
        display_obj(dict): A display object containing case name, list of genes, lucus and tracks
    """
    build = "38"  # This feature is only available for RNA tracks in build 38

    variant_obj = store.variant(document_id=variant_id)

    # Initialize locus coordinates it with variant coordinates so it won't crash if variant gene(s) no longer exist in database
    locus_start_coords = []
    locus_end_coords = []

    # Check if variant coordinates are in genome build 38
    # Otherwise do variant coords liftover
    if build not in str(case_obj.get("genome_build")):
        client = EnsemblRestApiClient()
        mapped_coords = client.liftover(
            case_obj.get("genome_build"),
            variant_obj.get("chromosome"),
            variant_obj.get("position"),
            variant_obj.get("end"),
        )
        if mapped_coords:
            mapped_start = mapped_coords[0]["mapped"].get("start")
            mapped_end = mapped_coords[0]["mapped"].get("end") or mapped_start
            locus_start_coords.append(mapped_start)
            locus_end_coords.append(mapped_end)

    # Use original coordinates only genome build was already 38 or liftover didn't work
    if not locus_start_coords:
        locus_start_coords.append(variant_obj.get("position"))
    if not locus_end_coords:
        locus_end_coords.append(variant_obj.get("end"))

    # Collect locus coordinates. Take into account that variant can hit multiple genes
    variant_genes_ids = [
        gene["hgnc_id"] for gene in variant_obj.get("genes", [])
    ]
    for gene_id in variant_genes_ids:
        gene_caption = store.hgnc_gene_caption(hgnc_identifier=gene_id,
                                               build=build)
        if gene_caption is None:
            continue
        locus_start_coords.append(gene_caption["start"])
        locus_end_coords.append(gene_caption["end"])

    locus_start = min(locus_start_coords)
    locus_end = max(locus_end_coords)

    locus = f"{variant_obj['chromosome']}:{locus_start}-{locus_end}"  # Locus will span all genes the variant falls into
    display_obj = {"locus": locus, "tracks": []}

    # Add Genes and reference tracks to display object
    set_common_tracks(display_obj, build)

    # Populate tracks for each individual with splice junction track data
    for ind in case_obj.get("individuals", []):
        if not all(
            [ind.get("splice_junctions_bed"),
             ind.get("rna_coverage_bigwig")]):
            continue

        coverage_wig = ind["rna_coverage_bigwig"]
        splicej_bed = ind["splice_junctions_bed"]
        splicej_bed_index = f"{splicej_bed}.tbi" if os.path.isfile(
            f"{splicej_bed}.tbi") else None
        if splicej_bed_index is None:
            flash(
                f"Missing bed file index for individual {ind['display_name']}")

        track = {
            "name": ind["display_name"],
            "coverage_wig": coverage_wig,
            "splicej_bed": splicej_bed,
            "splicej_bed_index": splicej_bed_index,
        }
        display_obj["tracks"].append(track)

    display_obj["case"] = case_obj["display_name"]

    return display_obj
Exemple #22
0
def variant_update(institute_id, case_name, variant_id):
    """Update user-defined information about a variant: manual rank & ACMG."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    user_obj = store.user(current_user.email)
    link = request.referrer

    manual_rank = request.form.get("manual_rank")
    cancer_tier = request.form.get("cancer_tier")
    if manual_rank:
        try:
            new_manual_rank = int(manual_rank) if manual_rank != "-1" else None
        except ValueError:
            LOG.warning(
                "Attempt to update manual rank with invalid value {}".format(
                    manual_rank))
            manual_rank = "-1"
            new_manual_rank = -1

        store.update_manual_rank(institute_obj, case_obj, user_obj, link,
                                 variant_obj, new_manual_rank)
        if new_manual_rank:
            flash("updated variant tag: {}".format(new_manual_rank), "info")
        else:
            flash(
                "reset variant tag: {}".format(
                    variant_obj.get("manual_rank", "NA")),
                "info",
            )
    elif cancer_tier:
        try:
            new_cancer_tier = cancer_tier if cancer_tier != "-1" else None
        except ValueError:
            LOG.warning(
                "Attempt to update cancer tier with invalid value {}".format(
                    cancer_tier))
            cancer_tier = "-1"
            new_cancer_tier = "-1"

        store.update_cancer_tier(institute_obj, case_obj, user_obj, link,
                                 variant_obj, new_cancer_tier)
        if new_cancer_tier:
            flash("updated variant tag: {}".format(new_cancer_tier), "info")
        else:
            flash(
                "reset variant tag: {}".format(
                    variant_obj.get("cancer_tier", "NA")),
                "info",
            )
    elif request.form.get("acmg_classification"):
        new_acmg = request.form["acmg_classification"]
        acmg_classification = variant_obj.get("acmg_classification")
        # If there already is a classification and the same one is sent again this means that
        # We want to remove the classification
        if isinstance(acmg_classification,
                      int) and (new_acmg == ACMG_MAP[acmg_classification]):
            new_acmg = None

        store.submit_evaluation(
            variant_obj=variant_obj,
            user_obj=user_obj,
            institute_obj=institute_obj,
            case_obj=case_obj,
            link=link,
            classification=new_acmg,
        )
        flash("updated ACMG classification: {}".format(new_acmg), "info")

    new_dismiss = request.form.getlist("dismiss_variant")
    if new_dismiss:
        store.update_dismiss_variant(institute_obj, case_obj, user_obj, link,
                                     variant_obj, new_dismiss)
        flash("Dismissed variant: {}".format(new_dismiss), "info")

    variant_dismiss = variant_obj.get("dismiss_variant")
    if variant_dismiss and not new_dismiss:
        if "dismiss" in request.form:
            store.update_dismiss_variant(institute_obj, case_obj, user_obj,
                                         link, variant_obj, new_dismiss)
            flash(
                "Reset variant dismissal: {}".format(
                    variant_obj.get("dismiss_variant")),
                "info",
            )
        else:
            LOG.debug("DO NOT reset variant dismissal: {}".format(
                ",".join(variant_dismiss), "info"))

    mosaic_tags = request.form.getlist("mosaic_tags")
    if mosaic_tags:
        store.update_mosaic_tags(institute_obj, case_obj, user_obj, link,
                                 variant_obj, mosaic_tags)
        flash("Added mosaic tags: {}".format(mosaic_tags), "info")

    variant_mosaic = variant_obj.get("mosaic_tags")
    if variant_mosaic and not mosaic_tags:
        if "mosaic" in request.form:
            store.update_mosaic_tags(institute_obj, case_obj, user_obj, link,
                                     variant_obj, mosaic_tags)
            flash("Reset mosaic tags: {}".format(",".join(variant_mosaic),
                                                 "info"))

    return redirect(request.referrer)
Exemple #23
0
def variant(institute_id, case_name, variant_id):
    """Display a specific SNV variant."""
    institute_obj, case_obj = institute_and_case(store, institute_id,
                                                 case_name)
    variant_obj = store.variant(variant_id)
    return Response(json_util.dumps(variant_obj), mimetype='application/json')
def make_igv_tracks(case_obj, variant_id, chrom=None, start=None, stop=None):
    """Create a dictionary containing the required tracks for displaying IGV tracks for case or a group of cases

    Args:
        institute_id(str): institute _id
        case_obj(scout.models.Case)
        variant_id(str): _id of a variant
        chrom(str/None): requested chromosome [1-22], X, Y, [M-MT]
        start(int/None): start of the genomic interval to be displayed
        stop(int/None): stop of the genomic interval to be displayed

    Returns:
        display_obj(dict): A display object containing case name, list of genes, lucus and tracks
    """
    display_obj = {}
    variant_obj = store.variant(document_id=variant_id)

    if variant_obj:
        # Set display locus
        start = start or variant_obj["position"]
        stop = stop or variant_obj["end"]

        chromosome = chrom or variant_obj.get("chromosome")
        chromosome = chromosome.replace("MT", "M")
        display_obj["locus"] = "chr{0}:{1}-{2}".format(chromosome, start, stop)
    else:
        chromosome = "All"

    # Set genome build for displaying alignments:
    if "38" in str(case_obj.get("genome_build", "37")) or chromosome == "M":
        build = "38"
    else:
        build = "37"

    # Set general tracks (Genes, Clinvar and ClinVar SNVs are shown according to user preferences)
    set_common_tracks(display_obj, build)

    # Build tracks for main case and all connected cases (cases grouped with main case)
    grouped_cases = []
    for group in case_obj.get("group", []):
        group_cases = list(store.cases(group=group))
        for case in group_cases:
            case_append_alignments(
                case)  # Add track data to connected case dictionary
            grouped_cases.append(case)

    if not grouped_cases:  # Display case individuals tracks only
        case_append_alignments(
            case_obj)  # Add track data to main case dictionary
        grouped_cases.append(case_obj)

    # Set up bam/cram alignments for case group samples:
    set_sample_tracks(display_obj, grouped_cases, chromosome)

    # When chrom != MT, set up case-specific tracks (might be present according to the pipeline)
    if chrom != "M":
        set_case_specific_tracks(display_obj, case_obj)

    # Set up custom cloud public tracks, if available
    set_cloud_public_tracks(display_obj, build)

    display_obj["display_center_guide"] = True

    return display_obj
def case_report_variants(store, case_obj, institute_obj, data):
    """Gather evaluated variants info to include in case report

    Args:
        store(adapter.MongoAdapter)
        case_obj(dict): case dictionary
        data(dict): data dictionary containing case report information
    """
    evaluated_variants = {vt: [] for vt in CASE_REPORT_VARIANT_TYPES}
    # We collect all causatives (including the partial ones) and suspected variants
    # These are handeled in separate since they are on case level
    for var_type in ["causatives", "suspects", "partial_causatives"]:
        # These include references to variants
        vt = "_".join([var_type, "detailed"])
        for var_id in case_obj.get(var_type, []):
            variant_obj = store.variant(var_id)
            if not variant_obj:
                continue
            if var_type == "partial_causatives":  # Collect associated phenotypes
                variant_obj["phenotypes"] = [
                    value for key, value in case_obj["partial_causatives"].items() if key == var_id
                ][0]
            evaluated_variants[vt].append(variant_obj)

    ## get variants for this case that are either classified, commented, tagged or dismissed.
    for var_obj in store.evaluated_variants(
        case_id=case_obj["_id"], institute_id=institute_obj["_id"]
    ):
        # Check which category it belongs to
        for vt in CASE_REPORT_VARIANT_TYPES:
            keyword = CASE_REPORT_VARIANT_TYPES[vt]
            # When found we add it to the category
            # Each variant can belong to multiple categories
            if keyword not in var_obj:
                continue
            evaluated_variants[vt].append(var_obj)

    data["variants"] = {}

    for var_type in evaluated_variants:
        decorated_variants = []
        for var_obj in evaluated_variants[var_type]:
            # We decorate the variant with some extra information
            filtered_var_obj = {}
            for feat in VARIANT_REPORT_VARIANT_FEATURES:
                filtered_var_obj[feat] = var_obj.get(feat)

            variant_category = var_obj["category"]

            populate_individual_callers(filtered_var_obj, var_obj)

            decorated_info = variant_decorator(
                store=store,
                institute_id=institute_obj["_id"],
                case_name=case_obj["display_name"],
                variant_id=None,
                variant_obj=filtered_var_obj,
                add_case=False,
                add_other=False,
                get_overlapping=False,
                variant_type=variant_category,
                institute_obj=institute_obj,
                case_obj=case_obj,
            )
            decorated_variants.append(decorated_info["variant"])
        # Add the decorated variants to the case
        data["variants"][var_type] = decorated_variants
def case(store, institute_obj, case_obj):
    """Preprocess a single case.

    Prepare the case to be displayed in the case view.

    Args:
        store(adapter.MongoAdapter)
        institute_obj(models.Institute)
        case_obj(models.Case)

    Returns:
        data(dict): includes the cases, how many there are and the limit.

    """
    # Convert individual information to more readable format
    case_obj["individual_ids"] = []
    for individual in case_obj["individuals"]:
        try:
            sex = int(individual.get("sex", 0))
        except ValueError as err:
            sex = 0
        individual["sex_human"] = SEX_MAP[sex]

        pheno_map = PHENOTYPE_MAP
        if case_obj.get("track", "rare") == "cancer":
            pheno_map = CANCER_PHENOTYPE_MAP

        individual["phenotype_human"] = pheno_map.get(individual["phenotype"])
        case_obj["individual_ids"].append(individual["individual_id"])

    case_obj["assignees"] = [store.user(user_email) for user_email in case_obj.get("assignees", [])]

    # Provide basic info on alignment files availability for this case
    case_has_alignments(case_obj)
    case_has_mt_alignments(case_obj)

    case_groups = {}
    case_group_label = {}
    _populate_case_groups(store, case_obj, case_groups, case_group_label)

    # Fetch the variant objects for suspects and causatives
    suspects = [
        store.variant(variant_id) or variant_id for variant_id in case_obj.get("suspects", [])
    ]
    _populate_assessments(suspects)
    causatives = [
        store.variant(variant_id) or variant_id for variant_id in case_obj.get("causatives", [])
    ]
    _populate_assessments(causatives)

    # get evaluated variants
    evaluated_variants = store.evaluated_variants(case_obj["_id"], case_obj["owner"])
    _populate_assessments(evaluated_variants)

    # check for partial causatives and associated phenotypes
    partial_causatives = []
    if case_obj.get("partial_causatives"):
        for var_id, values in case_obj["partial_causatives"].items():
            causative_obj = {
                "variant": store.variant(var_id) or var_id,
                "omim_terms": values.get("diagnosis_phenotypes"),
                "hpo_terms": values.get("phenotype_terms"),
            }
            partial_causatives.append(causative_obj)
    _populate_assessments(partial_causatives)

    # Set of all unique genes in the default gene panels
    distinct_genes = set()
    case_obj["panel_names"] = []
    case_obj["outdated_panels"] = {}
    for panel_info in case_obj.get("panels", []):
        if not panel_info.get("is_default"):
            continue
        panel_name = panel_info["panel_name"]
        panel_version = panel_info.get("version")
        panel_obj = store.gene_panel(panel_name, version=panel_version)
        latest_panel = store.gene_panel(panel_name)
        panel_info["removed"] = False if latest_panel is None else latest_panel.get("hidden", False)
        if not panel_obj:
            panel_obj = latest_panel
            if not panel_obj:
                flash(f"Case default panel '{panel_name}' could not be found.", "warning")
                continue
            flash(
                f"Case default panel '{panel_name}' version {panel_version} could not be found, using latest existing version",
                "warning",
            )

        # Check if case-specific panel is up-to-date with latest version of the panel
        if panel_obj["version"] < latest_panel["version"]:
            extra_genes, missing_genes = _check_outdated_gene_panel(panel_obj, latest_panel)
            if extra_genes or missing_genes:
                case_obj["outdated_panels"][panel_name] = {
                    "missing_genes": missing_genes,
                    "extra_genes": extra_genes,
                }

        distinct_genes.update([gene["hgnc_id"] for gene in panel_obj.get("genes", [])])
        full_name = "{} ({})".format(panel_obj["display_name"], panel_obj["version"])
        case_obj["panel_names"].append(full_name)

    case_obj["default_genes"] = list(distinct_genes)

    for hpo_term in itertools.chain(
        case_obj.get("phenotype_groups", []), case_obj.get("phenotype_terms", [])
    ):
        hpo_term["hpo_link"] = "http://hpo.jax.org/app/browse/term/{}".format(
            hpo_term["phenotype_id"]
        )

    if case_obj.get("rank_model_version"):
        rank_model_link = "".join(
            [
                current_app.config.get("RANK_MODEL_LINK_PREFIX", ""),
                str(case_obj["rank_model_version"]),
                current_app.config.get("RANK_MODEL_LINK_POSTFIX", ""),
            ]
        )
        case_obj["rank_model_link"] = rank_model_link

    if case_obj.get("sv_rank_model_version"):
        case_obj["sv_rank_model_link"] = "".join(
            [
                current_app.config.get("SV_RANK_MODEL_LINK_PREFIX", ""),
                str(case_obj["sv_rank_model_version"]),
                current_app.config.get("SV_RANK_MODEL_LINK_POSTFIX", ""),
            ]
        )

    # other collaborators than the owner of the case
    o_collaborators = []
    for collab_id in case_obj.get("collaborators", []):
        if collab_id != case_obj["owner"] and store.institute(collab_id):
            o_collaborators.append(store.institute(collab_id))
    case_obj["o_collaborators"] = [
        (collab_obj["_id"], collab_obj["display_name"]) for collab_obj in o_collaborators
    ]

    collab_ids = None
    if institute_obj.get("collaborators"):
        collab_ids = [
            (collab["_id"], collab["display_name"])
            for collab in store.institutes()
            if institute_obj.get("collaborators")
            and collab["_id"] in institute_obj.get("collaborators")
        ]

    events = list(store.events(institute_obj, case=case_obj))