def causatives(institute_id): institute_obj = institute_and_case(store, institute_id) query = request.args.get('query', '') hgnc_id = None if '|' in query: # filter accepts an array of IDs. Provide an array with one ID element try: hgnc_id = [int(query.split(' | ', 1)[0])] except ValueError: flash('Provided gene info could not be parsed!', 'warning') variants = store.check_causatives(institute_obj=institute_obj, limit_genes=hgnc_id) if variants: variants.sort("hgnc_symbols", pymongo.ASCENDING) all_variants = {} all_cases = {} for variant_obj in variants: if variant_obj['case_id'] not in all_cases: case_obj = store.case(variant_obj['case_id']) all_cases[variant_obj['case_id']] = case_obj else: case_obj = all_cases[variant_obj['case_id']] if variant_obj['variant_id'] not in all_variants: # capture ACMG classification for this variant if isinstance(variant_obj.get('acmg_classification'), int): acmg_code = ACMG_MAP[variant_obj['acmg_classification']] variant_obj['acmg_classification'] = ACMG_COMPLETE_MAP[ acmg_code] all_variants[variant_obj['variant_id']] = [] all_variants[variant_obj['variant_id']].append((case_obj, variant_obj)) return dict(institute=institute_obj, variant_groups=all_variants)
def panel(panel_id): """Display (and add pending updates to) a specific gene panel.""" panel_obj = store.gene_panel(panel_id) or store.panel(panel_id) if request.method == 'POST': raw_hgnc_id = request.form['hgnc_id'] if '|' in raw_hgnc_id: raw_hgnc_id = raw_hgnc_id.split(' | ', 1)[0] hgnc_id = int(raw_hgnc_id) action = request.form['action'] if action == 'add': panel_gene = controllers.existing_gene(store, panel_obj, hgnc_id) if panel_gene: flash("gene already in panel: {}".format(panel_gene['symbol']), 'warning') else: # ask user to fill-in more information about the gene return redirect( url_for('.gene_edit', panel_id=panel_id, hgnc_id=hgnc_id)) elif action == 'delete': log.debug("marking gene to be deleted: %s", hgnc_id) store.add_pending(panel_obj, hgnc_id, action='delete') data = controllers.panel(store, panel_obj) if request.args.get('case_id'): data['case'] = store.case(request.args['case_id']) if request.args.get('institute_id'): data['institute'] = store.institute(request.args['institute_id']) return data
def get_timeline_data(limit): """Retrieve chronologially ordered events from the database to display them in the timeline page Args: limit(str): for instance "50" to display last 50 events. "-1" to display all events Returns: timeline_results(dict): dictionary containing timeline data """ timeline_results = [] results = store.user_timeline(current_user.email, int(limit)) for eventg in results: # Add links to cases pages case_obj = store.case(case_id=eventg["_id"]["case_id"]) if case_obj is None: continue # Some events are captured both for case and variant. Display them only once (for the variant) if (eventg["_id"].get("category") == "case" and eventg["_id"].get("verb") in VAR_SPECIFIC_EVENTS): continue # Build link to case page eventg["_id"]["case_name"] = case_obj.get("display_name") eventg["_id"]["link"] = url_for( "cases.case", institute_id=eventg["_id"]["institute"], case_name=case_obj["display_name"], ) timeline_results.append(eventg) return timeline_results
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 gene_variants(store, pymongo_cursor, variant_count, institute_id, page=1, per_page=50): """Pre-process list of variants.""" skip_count = per_page * max(page - 1, 0) more_variants = True if variant_count > (skip_count + per_page) else False variant_res = pymongo_cursor.skip(skip_count).limit(per_page) my_institutes = set(inst["_id"] for inst in user_institutes(store, current_user)) variants = [] for variant_obj in variant_res: # Populate variant case_display_name variant_case_obj = store.case(case_id=variant_obj["case_id"]) if not variant_case_obj: # A variant with missing case was encountered continue case_display_name = variant_case_obj.get("display_name") variant_obj["case_display_name"] = case_display_name # hide other institutes for now other_institutes = set([variant_case_obj.get("owner")]) other_institutes.update(set(variant_case_obj.get("collaborators", []))) if my_institutes.isdisjoint(other_institutes): # If the user does not have access to the information we skip it continue genome_build = get_genome_build(variant_case_obj) variant_genes = variant_obj.get("genes") gene_object = update_HGNC_symbols(store, variant_genes, genome_build) # Populate variant HGVS and predictions variant_genes = variant_obj.get("genes") hgvs_c = [] hgvs_p = [] if variant_genes is not None: for gene_obj in variant_genes: hgnc_id = gene_obj["hgnc_id"] gene_symbol = gene(store, hgnc_id)["symbol"] gene_symbols = [gene_symbol] # gather HGVS info from gene transcripts (hgvs_nucleotide, hgvs_protein) = get_hgvs(gene_obj) hgvs_c.append(hgvs_nucleotide) hgvs_p.append(hgvs_protein) if len(gene_symbols) == 1: variant_obj["hgvs"] = hgvs_str(gene_symbols, hgvs_p, hgvs_c) # populate variant predictions for display variant_obj.update(predictions(variant_genes)) variants.append(variant_obj) return {"variants": variants, "more_variants": more_variants}
def panel(panel_id): """Display (and add pending updates to) a specific gene panel.""" panel_obj = store.gene_panel(panel_id) or store.panel(panel_id) if not panel_obj: flash("Panel with id {} not found.".format(panel_id), "warning") return redirect(url_for("panels.panels")) if request.method == "POST": if request.form.get("update_description"): panel_obj["description"] = request.form["panel_description"] if controllers.panel_write_granted(panel_obj, current_user): store.update_panel(panel_obj=panel_obj) else: flash( "Permission denied: please ask a panel maintainer or admin for help.", "danger", ) return redirect(url_for("panels.panel", panel_id=panel_obj["_id"])) raw_hgnc_id = request.form["hgnc_id"] if "|" in raw_hgnc_id: raw_hgnc_id = raw_hgnc_id.split(" | ", 1)[0] hgnc_id = 0 try: hgnc_id = int(raw_hgnc_id) except ValueError: flash("Provided HGNC is not valid : '{}'".format(raw_hgnc_id), "danger") return redirect(request.referrer) action = request.form["action"] gene_obj = store.hgnc_gene_caption( hgnc_identifier=hgnc_id, build="37") or store.hgnc_gene_caption( hgnc_identifier=hgnc_id, build="38") if gene_obj is None: flash("HGNC id not found: {}".format(hgnc_id), "warning") return redirect(request.referrer) if action == "add": panel_gene = controllers.existing_gene(store, panel_obj, hgnc_id) if panel_gene: flash("gene already in panel: {}".format(panel_gene["symbol"]), "warning") else: # ask user to fill-in more information about the gene return redirect( url_for(".gene_edit", panel_id=panel_id, hgnc_id=hgnc_id)) elif action == "delete": LOG.debug("marking gene to be deleted: %s", hgnc_id) panel_obj = store.add_pending(panel_obj, gene_obj, action="delete") data = controllers.panel(store, panel_obj) if request.args.get("case_id"): data["case"] = store.case(request.args["case_id"]) if request.args.get("institute_id"): data["institute"] = store.institute(request.args["institute_id"]) return data
def causatives(institute_obj, request): """Create content to be displayed on institute causatives page Args: institute_obj(dict) An institute object request(flask.request) request sent by user's browser Returns: data(dict) """ # Retrieve variants grouped by case query = request.args.get("query", "") hgnc_id = None if "|" in query: # filter accepts an array of IDs. Provide an array with one ID element try: hgnc_id = [int(query.split(" | ", 1)[0])] except ValueError: flash("Provided gene info could not be parsed!", "warning") variants = list( store.check_causatives(institute_obj=institute_obj, limit_genes=hgnc_id)) if variants: variants = sorted( variants, key=lambda k: k.get("hgnc_symbols", [None])[0] or k.get("str_repid" ) or "", ) all_variants = {} all_cases = {} for variant_obj in variants: if variant_obj["category"] in ["snv", "cancer"]: update_representative_gene(variant_obj, variant_obj.get( "genes", [])) # required to display cDNA and protein change if variant_obj["case_id"] not in all_cases: case_obj = store.case(variant_obj["case_id"]) all_cases[variant_obj["case_id"]] = case_obj else: case_obj = all_cases[variant_obj["case_id"]] if variant_obj["variant_id"] not in all_variants: all_variants[variant_obj["variant_id"]] = [] all_variants[variant_obj["variant_id"]].append((case_obj, variant_obj)) data = dict( institute=institute_obj, variant_groups=all_variants, acmg_map={ key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items() }, ) return data
def causatives(institute_id): institute_obj = institute_and_case(store, institute_id) variants = store.check_causatives(institute_obj=institute_obj) all_variants = {} all_cases = {} for variant_obj in variants: if variant_obj['case_id'] not in all_cases: case_obj = store.case(variant_obj['case_id']) all_cases[variant_obj['case_id']] = case_obj else: case_obj = all_cases[variant_obj['case_id']] if variant_obj['variant_id'] not in all_variants: all_variants[variant_obj['variant_id']] = [] all_variants[variant_obj['variant_id']].append((case_obj, variant_obj)) return dict(institute=institute_obj, variant_groups=all_variants)
def causatives(institute_id): institute_obj = institute_and_case(store, institute_id) variants = store.check_causatives(institute_obj=institute_obj) all_variants = {} all_cases = {} for variant_obj in variants: if variant_obj['case_id'] not in all_cases: case_obj = store.case(variant_obj['case_id']) all_cases[variant_obj['case_id']] = case_obj else: case_obj = all_cases[variant_obj['case_id']] if variant_obj['variant_id'] not in all_variants: all_variants[variant_obj['variant_id']] = [] all_variants[variant_obj['variant_id']].append((case_obj, variant_obj)) return dict(institute=institute_obj, variant_groups=all_variants)
def panel(panel_id): """Display (and add pending updates to) a specific gene panel.""" panel_obj = store.gene_panel(panel_id) or store.panel(panel_id) if request.method == 'POST': if request.form.get('update_description'): panel_obj['description'] = request.form['panel_description'] store.update_panel(panel_obj=panel_obj) return redirect( url_for('panels.panel', panel_id=panel_obj['_id']) ) raw_hgnc_id = request.form['hgnc_id'] if '|' in raw_hgnc_id: raw_hgnc_id = raw_hgnc_id.split(' | ', 1)[0] hgnc_id = 0 try: hgnc_id = int(raw_hgnc_id) except: flash("Provided HGNC is not valid : '{}'". format(raw_hgnc_id), 'danger') return redirect(request.referrer) action = request.form['action'] gene_obj = store.hgnc_gene(hgnc_id) if gene_obj is None: flash("HGNC id not found: {}".format(hgnc_id), 'warning') return redirect(request.referrer) if action == 'add': panel_gene = controllers.existing_gene(store, panel_obj, hgnc_id) if panel_gene: flash("gene already in panel: {}".format(panel_gene['symbol']), 'warning') else: # ask user to fill-in more information about the gene return redirect(url_for('.gene_edit', panel_id=panel_id, hgnc_id=hgnc_id)) elif action == 'delete': log.debug("marking gene to be deleted: %s", hgnc_id) panel_obj = store.add_pending(panel_obj, gene_obj, action='delete') data = controllers.panel(store, panel_obj) if request.args.get('case_id'): data['case'] = store.case(request.args['case_id']) if request.args.get('institute_id'): data['institute'] = store.institute(request.args['institute_id']) return data
def individual(case_id, ind, key, value): """Update information on individual level in Scout""" case_obj = store.case(case_id) if not case_obj: click.echo(f"Could not find case {case_id}") return individuals = { ind_info["display_name"]: ind_info for ind_info in case_obj["individuals"] } # If ind name is empty, print available individual names for this case to help the user to build the command if ind is None: click.echo( f"Please specify individual name with '-n' option. Available individuals for this case:{list(individuals.keys())}" ) return if ind not in individuals: click.echo( f"Could not find individual '{ind}' in case individuals. Available individuals for this case: {list(individuals.keys())}" ) return # If key is null or non-valid, print a list of all the keys that can be updated using this function if key is None or not key in UPDATE_KEYS: click.echo( f"Please specify a valid key to update. Valid keys:{ UPDATE_KEYS }" ) return if value is None: click.echo(f"Please specify a file path for key {key}") return file_path = Path(value) # If file is not found on the server, ask if user wants to update the key anyway if file_path.exists() is False: click.confirm( "The provided path was not found on the server, update key anyway?", abort=True, ) # perform the update for ind_obj in case_obj["individuals"]: if ind_obj["display_name"] == ind: ind_obj[key] = value store.update_case(case_obj)
def gene_variants(store, pymongo_cursor, variant_count, page=1, per_page=50): """Pre-process list of variants.""" skip_count = per_page * max(page - 1, 0) more_variants = True if variant_count > (skip_count + per_page) else False variant_res = pymongo_cursor.skip(skip_count).limit(per_page) variants = [] for variant_obj in variant_res: # Populate variant case_display_name variant_case_obj = store.case(case_id=variant_obj["case_id"]) case_display_name = variant_case_obj.get("display_name") variant_obj["case_display_name"] = case_display_name genome_build = get_genome_build(variant_case_obj) variant_genes = variant_obj.get("genes") update_HGNC_symbols(store, variant_genes, genome_build) # Populate variant HGVS and predictions variant_genes = variant_obj.get("genes") hgvs_c = [] hgvs_p = [] if variant_genes is not None: for gene_obj in variant_genes: hgnc_id = gene_obj["hgnc_id"] gene_caption = store.hgnc_gene_caption(hgnc_id) gene_symbols = [gene_caption["hgnc_symbol"]] # gather HGVS info from gene transcripts (hgvs_nucleotide, hgvs_protein) = get_hgvs(gene_obj) hgvs_c.append(hgvs_nucleotide) hgvs_p.append(hgvs_protein) if len(gene_symbols) == 1: variant_obj["hgvs"] = hgvs_str(gene_symbols, hgvs_p, hgvs_c) # populate variant predictions for display variant_obj.update(predictions(variant_genes)) variants.append(variant_obj) return {"variants": variants, "more_variants": more_variants}
def panel(panel_id): """Display (and add pending updates to) a specific gene panel.""" panel_obj = store.gene_panel(panel_id) or store.panel(panel_id) if request.method == 'POST': raw_hgnc_id = request.form['hgnc_id'] if '|' in raw_hgnc_id: raw_hgnc_id = raw_hgnc_id.split(' | ', 1)[0] hgnc_id = 0 try: hgnc_id = int(raw_hgnc_id) except: flash("Provided HGNC is not valid : '{}'". format(raw_hgnc_id), 'danger') return redirect(request.referrer) action = request.form['action'] gene_obj = store.hgnc_gene(hgnc_id) if gene_obj is None: flash("HGNC id not found: {}".format(hgnc_id), 'warning') return redirect(request.referrer) if action == 'add': panel_gene = controllers.existing_gene(store, panel_obj, hgnc_id) if panel_gene: flash("gene already in panel: {}".format(panel_gene['symbol']), 'warning') else: # ask user to fill-in more information about the gene return redirect(url_for('.gene_edit', panel_id=panel_id, hgnc_id=hgnc_id)) elif action == 'delete': log.debug("marking gene to be deleted: %s", hgnc_id) panel_obj = store.add_pending(panel_obj, gene_obj, action='delete') data = controllers.panel(store, panel_obj) if request.args.get('case_id'): data['case'] = store.case(request.args['case_id']) if request.args.get('institute_id'): data['institute'] = store.institute(request.args['institute_id']) return data
def causatives(institute_id): institute_obj = institute_and_case(store, institute_id) query = request.args.get("query", "") hgnc_id = None if "|" in query: # filter accepts an array of IDs. Provide an array with one ID element try: hgnc_id = [int(query.split(" | ", 1)[0])] except ValueError: flash("Provided gene info could not be parsed!", "warning") variants = store.check_causatives(institute_obj=institute_obj, limit_genes=hgnc_id) if variants: variants.sort("hgnc_symbols", pymongo.ASCENDING) all_variants = {} all_cases = {} for variant_obj in variants: if variant_obj["case_id"] not in all_cases: case_obj = store.case(variant_obj["case_id"]) all_cases[variant_obj["case_id"]] = case_obj else: case_obj = all_cases[variant_obj["case_id"]] if variant_obj["variant_id"] not in all_variants: all_variants[variant_obj["variant_id"]] = [] all_variants[variant_obj["variant_id"]].append((case_obj, variant_obj)) acmg_map = { key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items() } return dict(institute=institute_obj, variant_groups=all_variants, acmg_map=acmg_map)