Esempio n. 1
0
def cases(institute_id):
    """Display a list of cases for an institute."""

    institute_obj = institute_and_case(store, institute_id)
    query = request.args.get("query")

    limit = 100
    if request.args.get("limit"):
        limit = int(request.args.get("limit"))

    skip_assigned = request.args.get("skip_assigned")
    is_research = request.args.get("is_research")
    all_cases = store.cases(
        collaborator=institute_id,
        name_query=query,
        skip_assigned=skip_assigned,
        is_research=is_research,
    )

    sort_by = request.args.get("sort")
    sort_order = request.args.get("order") or "asc"
    if sort_by:
        pymongo_sort = pymongo.ASCENDING
        if sort_order == "desc":
            pymongo_sort = pymongo.DESCENDING
        if sort_by == "analysis_date":
            all_cases.sort("analysis_date", pymongo_sort)
        elif sort_by == "track":
            all_cases.sort("track", pymongo_sort)
        elif sort_by == "status":
            all_cases.sort("status", pymongo_sort)

    LOG.debug("Prepare all cases")

    prioritized_cases = store.prioritized_cases(institute_id=institute_id)

    data = controllers.cases(store, all_cases, prioritized_cases, limit)
    data["sort_order"] = sort_order
    data["sort_by"] = sort_by
    data["nr_cases"] = store.nr_cases(institute_id=institute_id)

    sanger_unevaluated = controllers.get_sanger_unevaluated(
        store, institute_id, current_user.email)
    if len(sanger_unevaluated) > 0:
        data["sanger_unevaluated"] = sanger_unevaluated

    return dict(institute=institute_obj,
                skip_assigned=skip_assigned,
                is_research=is_research,
                query=query,
                **data)
Esempio n. 2
0
def caselist(institute_id):
    """Search for cases for autocompletion"""
    query = request.args.get("query")
    if query is None:
        return abort(500)
    display_names = sorted([
        case["display_name"]
        for case in store.cases(owner=institute_id, name_query="case:" + query)
    ])
    json_terms = [{
        "name": "{}".format(display_name)
    } for display_name in display_names]

    return jsonify(json_terms)
Esempio n. 3
0
def cases(institute_id):
    """Display a list of cases for an institute."""
    institute_obj = institute_and_case(store, institute_id)
    query = request.args.get('query')

    limit = 100
    if request.args.get('limit'):
        limit = int(request.args.get('limit'))

    skip_assigned = request.args.get('skip_assigned')
    all_cases = store.cases(institute_id,
                            name_query=query,
                            skip_assigned=skip_assigned)
    data = controllers.cases(store, all_cases, limit)
    return dict(institute=institute_obj,
                skip_assigned=skip_assigned,
                query=query,
                **data)
Esempio n. 4
0
def _populate_case_groups(store, case_obj, case_groups, case_group_label):
    """Case groups allow display of information about user linked cases together on one case.
    Notably variantS lists show shared annotations and alignment views show all alignments
    available for the group.

    Each case may belong to any of a list of groups. Groups have human readable labels
    that need to be fetched separately. Alignments for each case, that belongs to
    a group that the present case also belongs to, are added to the present case.

    Args:
         store(adapter.MongoAdapter)
         case_obj(models.Case)
         case_group(dict) - keys group ids, values list(case_ids)
         case_group_label(dict) - keys group ids, values case_group_labels(str)
    """
    if case_obj.get("group"):
        for group in case_obj.get("group"):
            case_groups[group] = list(store.cases(group=group))
            case_group_label[group] = store.case_group_label(group)
Esempio n. 5
0
def cases(institute_id):
    """Display a list of cases for an institute."""
    institute_obj = institute_and_case(store, institute_id)
    query = request.args.get('query')

    limit = 100
    if request.args.get('limit'):
        limit = int(request.args.get('limit'))

    skip_assigned = request.args.get('skip_assigned')
    is_research = request.args.get('is_research')
    all_cases = store.cases(collaborator=institute_id, name_query=query,
                        skip_assigned=skip_assigned, is_research=is_research)
    data = controllers.cases(store, all_cases, limit)

    sanger_unevaluated = controllers.get_sanger_unevaluated(store, institute_id, current_user.email)
    if len(sanger_unevaluated)> 0:
        data['sanger_unevaluated'] = sanger_unevaluated

    return dict(institute=institute_obj, skip_assigned=skip_assigned,
                is_research=is_research, query=query, **data)
Esempio n. 6
0
def cases(institute_id):
    """Display a list of cases for an institute."""

    institute_obj = institute_and_case(store, institute_id)
    query = request.args.get('query')

    limit = 500
    if request.args.get('limit'):
        limit = int(request.args.get('limit'))

    skip_assigned = request.args.get('skip_assigned')
    is_research = request.args.get('is_research')
    all_cases = store.cases(collaborator=institute_id,
                            name_query=query,
                            skip_assigned=skip_assigned,
                            is_research=is_research)

    LOG.info(type(all_cases))
    sort_by = request.args.get('sort')
    if sort_by:
        if sort_by == 'analysis_date':
            all_cases.sort('analysis_date', pymongo.DESCENDING)
        elif sort_by == 'track':
            all_cases.sort('track', pymongo.ASCENDING)
        elif sort_by == 'status':
            all_cases.sort('status', pymongo.ASCENDING)

    LOG.debug("Prepare all cases")
    data = controllers.cases(store, all_cases, limit)

    sanger_unevaluated = controllers.get_sanger_unevaluated(
        store, institute_id, current_user.email)
    if len(sanger_unevaluated) > 0:
        data['sanger_unevaluated'] = sanger_unevaluated

    return dict(institute=institute_obj,
                skip_assigned=skip_assigned,
                is_research=is_research,
                query=query,
                **data)
Esempio n. 7
0
def cases(store, request, institute_id):
    """Preprocess case objects.

    Add all the necessary information to display the 'cases' view

    Args:
        store(adapter.MongoAdapter)
        request(flask.request) request sent by browser to the api_institutes endpoint
        institute_id(str): An _id of an institute

    Returns:
        data(dict): includes the cases, how many there are and the limit.
    """
    data = {"search_terms": CASE_SEARCH_TERMS}
    institute_obj = institute_and_case(store, institute_id)
    data["institute"] = institute_obj
    name_query = None
    if request.args.get("search_term"):
        name_query = "".join([
            request.args.get("search_type"),
            re.escape(request.args["search_term"].strip())
        ])
    data["name_query"] = name_query
    limit = int(request.args.get("search_limit")) if request.args.get(
        "search_limit") else 100
    skip_assigned = request.args.get("skip_assigned")
    data["form"] = populate_case_filter_form(request.args)
    data["skip_assigned"] = skip_assigned
    is_research = request.args.get("is_research")
    data["is_research"] = is_research
    prioritized_cases = store.prioritized_cases(institute_id=institute_id)
    all_cases = store.cases(
        collaborator=institute_id,
        name_query=name_query,
        skip_assigned=skip_assigned,
        is_research=is_research,
    )
    all_cases = _sort_cases(data, request, all_cases)

    data["nr_cases"] = store.nr_cases(institute_id=institute_id)

    sanger_unevaluated = get_sanger_unevaluated(store, institute_id,
                                                current_user.email)
    if len(sanger_unevaluated) > 0:
        data["sanger_unevaluated"] = sanger_unevaluated

    case_groups = {status: [] for status in CASE_STATUSES}
    nr_cases = 0

    # local function to add info to case obj
    def populate_case_obj(case_obj):
        analysis_types = set(ind["analysis_type"]
                             for ind in case_obj["individuals"])
        LOG.debug("Analysis types found in %s: %s", case_obj["_id"],
                  ",".join(analysis_types))
        if len(analysis_types) > 1:
            LOG.debug("Set analysis types to {'mixed'}")
            analysis_types = set(["mixed"])

        case_obj["analysis_types"] = list(analysis_types)
        case_obj["assignees"] = [
            store.user(user_email)
            for user_email in case_obj.get("assignees", [])
        ]
        # Check if case was re-runned
        analyses = case_obj.get("analyses", [])
        now = datetime.datetime.now()
        case_obj["is_rerun"] = (len(analyses) > 1
                                or analyses and analyses[0].get("date", now) <
                                case_obj.get("analysis_date", now))
        case_obj["clinvar_variants"] = store.case_to_clinVars(case_obj["_id"])
        case_obj["display_track"] = TRACKS[case_obj.get("track", "rare")]
        return case_obj

    for nr_cases, case_obj in enumerate(all_cases.limit(limit), 1):
        case_obj = populate_case_obj(case_obj)
        case_groups[case_obj["status"]].append(case_obj)

    if prioritized_cases:
        extra_prioritized = 0
        for case_obj in prioritized_cases:
            if any(
                    group_obj.get("display_name") == case_obj.get(
                        "display_name")
                    for group_obj in case_groups[case_obj["status"]]):
                continue
            else:
                extra_prioritized += 1
                case_obj = populate_case_obj(case_obj)
                case_groups[case_obj["status"]].append(case_obj)
        # extra prioritized cases are potentially shown in addition to the case query limit
        nr_cases += extra_prioritized

    data["cases"] = [(status, case_groups[status]) for status in CASE_STATUSES]
    data["found_cases"] = nr_cases
    data["limit"] = limit
    return data
Esempio n. 8
0
def variants(
    user: str,
    case_id: str,
    status: list,
    older_than: int,
    analysis_type: list,
    rank_threshold: int,
    variants_threshold: int,
    keep_ctg: list,
    dry_run: bool,
) -> None:
    """Delete variants for one or more cases"""

    user_obj = store.user(user)
    if user_obj is None:
        click.echo(f"Could not find a user with email '{user}' in database")
        return

    total_deleted = 0
    items_name = "deleted variants"
    if dry_run:
        click.echo("--------------- DRY RUN COMMAND ---------------")
        items_name = "estimated deleted variants"
    else:
        click.confirm("Variants are going to be deleted from database. Continue?", abort=True)

    case_query = store.build_case_query(case_id, status, older_than, analysis_type)
    # Estimate the average size of a variant document in database
    avg_var_size = store.collection_stats("variant").get("avgObjSize", 0)  # in bytes

    # Get all cases where case_query applies
    n_cases = store.case_collection.count_documents(case_query)
    cases = store.cases(query=case_query)
    filters = (
        f"Rank-score threshold:{rank_threshold}, case n. variants threshold:{variants_threshold}."
    )
    click.echo("\t".join(DELETE_VARIANTS_HEADER))
    for nr, case in enumerate(cases, 1):
        case_id = case["_id"]
        case_n_variants = store.variant_collection.count_documents({"case_id": case_id})
        # Skip case if user provided a number of variants to keep and this number is less than total number of case variants
        if variants_threshold and case_n_variants < variants_threshold:
            continue
        # Get evaluated variants for the case that haven't been dismissed
        case_evaluated = store.evaluated_variants(case_id=case_id)
        evaluated_not_dismissed = [
            variant["_id"] for variant in case_evaluated if "dismiss_variant" not in variant
        ]
        # Do not remove variants that are either pinned, causative or evaluated not dismissed
        variants_to_keep = (
            case.get("suspects", []) + case.get("causatives", []) + evaluated_not_dismissed or []
        )
        variants_query = store.delete_variants_query(
            case_id, variants_to_keep, rank_threshold, keep_ctg
        )

        if dry_run:
            # Just print how many variants would be removed for this case
            remove_n_variants = store.variant_collection.count_documents(variants_query)
            total_deleted += remove_n_variants
            click.echo(
                "\t".join(
                    [
                        str(nr),
                        str(n_cases),
                        case["owner"],
                        case["display_name"],
                        case_id,
                        case.get("track", ""),
                        str(case["analysis_date"]),
                        case.get("status", ""),
                        str(case.get("is_research", "")),
                        str(case_n_variants),
                        str(remove_n_variants),
                    ]
                )
            )
            continue

        # delete variants specified by variants_query
        result = store.variant_collection.delete_many(variants_query)
        click.echo(f"Deleted {result.deleted_count} / {case_n_variants} total variants")
        total_deleted += result.deleted_count
        click.echo(
            "\t".join(
                [
                    str(nr),
                    str(n_cases),
                    case["owner"],
                    case["display_name"],
                    case_id,
                    case.get("track", ""),
                    str(case["analysis_date"]),
                    case.get("status", ""),
                    str(case.get("is_research", "")),
                    str(case_n_variants),
                    str(result.deleted_count),
                ]
            )
        )

        # Create event in database
        institute_obj = store.institute(case["owner"])
        with current_app.test_request_context("/cases"):
            url = url_for(
                "cases.case", institute_id=institute_obj["_id"], case_name=case["display_name"]
            )
            store.remove_variants_event(
                institute=institute_obj, case=case, user=user_obj, link=url, content=filters
            )

    click.echo(f"Total {items_name}: {total_deleted}")
    click.echo(
        f"Estimated space freed (GB): {round((total_deleted * avg_var_size) / BYTES_IN_ONE_GIGABYTE, 4)}"
    )
Esempio n. 9
0
def index():
    """Display a list of all user institutes."""
    institute_objs = user_institutes(store, current_user)
    institutes_count = ((institute_obj, store.cases(collaborator=institute_obj['_id']).count())
                        for institute_obj in institute_objs if institute_obj)
    return dict(institutes=institutes_count)
Esempio n. 10
0
def index():
    """Display a list of all user institutes."""
    institute_objs = user_institutes(store, current_user)
    institutes_count = ((institute_obj, store.cases(collaborator=institute_obj['_id']).count())
                        for institute_obj in institute_objs if institute_obj)
    return dict(institutes=institutes_count)
Esempio n. 11
0
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