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
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 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
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)
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))