From 1ab6269d89f30e3531604d4e5c93c1e9a0b91bc8 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Thu, 15 Aug 2024 12:20:07 -0400 Subject: [PATCH] merge recent changes + fixes --- .../TxSegmentElementInput.tsx | 31 +++++++++--------- .../GetCoordinates/GetCoordinates.tsx | 8 ++--- client/src/services/ResponseModels.ts | 2 +- client/src/services/main.tsx | 8 ++--- server/src/curfu/routers/constructors.py | 12 +++---- server/src/curfu/routers/demo.py | 2 +- server/src/curfu/routers/lookup.py | 32 ++++++++++++++++++- server/src/curfu/routers/utilities.py | 26 --------------- server/src/curfu/schemas.py | 2 +- server/tests/integration/test_constructors.py | 12 +++---- 10 files changed, 70 insertions(+), 65 deletions(-) diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index c8166a1a..2b684e0a 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -6,8 +6,8 @@ import { } from "../../../../../services/ResponseModels"; import React, { useEffect, useState, KeyboardEvent, useContext } from "react"; import { - getTxSegmentElementECT, - getTxSegmentElementGCG, + getTxSegmentElementEC, + getTxSegmentElementGC, getTxSegmentNomenclature, } from "../../../../../services/main"; import { GeneAutocomplete } from "../../../../main/shared/GeneAutocomplete/GeneAutocomplete"; @@ -26,8 +26,8 @@ interface TxSegmentElementInputProps extends StructuralElementInputProps { export enum InputType { default = "default", - gcg = "genomic_coords", - ect = "exon_coords_tx", + gc = "genomic_coords", + ec = "exon_coords", } const TxSegmentCompInput: React.FC = ({ @@ -56,7 +56,6 @@ const TxSegmentCompInput: React.FC = ({ ); const [txChrom, setTxChrom] = useState(element.inputChr || ""); - const [txChromText, setTxChromText] = useState(""); const [txStartingGenomic, setTxStartingGenomic] = useState( element.inputGenomicStart || "" @@ -100,12 +99,12 @@ const TxSegmentCompInput: React.FC = ({ // programming horror const inputComplete = - (txInputType === InputType.gcg && + (txInputType === InputType.gc && txGene !== "" && txChrom !== "" && selectedTranscript !== "" && (txStartingGenomic !== "" || txEndingGenomic !== "")) || - (txInputType === InputType.ect && + (txInputType === InputType.ec && txAc !== "" && (startingExon !== "" || endingExon !== "")); @@ -212,6 +211,8 @@ const TxSegmentCompInput: React.FC = ({ setEndingExonOffsetText(""); }; + console.log(pendingResponse); + /** * Request construction of tx segment element from server and handle response */ @@ -219,9 +220,9 @@ const TxSegmentCompInput: React.FC = ({ setPendingResponse(true); // fire constructor request switch (txInputType) { - case InputType.gcg: + case InputType.gc: clearGenomicCoordWarnings(); - getTxSegmentElementGCG( + getTxSegmentElementGC( txGene, txChrom, selectedTranscript, @@ -247,8 +248,8 @@ const TxSegmentCompInput: React.FC = ({ } }); break; - case InputType.ect: - getTxSegmentElementECT( + case InputType.ec: + getTxSegmentElementEC( txAc, startingExon as string, endingExon as string, @@ -407,7 +408,7 @@ const TxSegmentCompInput: React.FC = ({ const renderTxOptions = () => { switch (txInputType) { - case InputType.gcg: + case InputType.gc: return ( @@ -444,7 +445,7 @@ const TxSegmentCompInput: React.FC = ({ {genomicCoordinateInfo} ); - case InputType.ect: + case InputType.ec: return ( {txInputField} @@ -583,7 +584,7 @@ const TxSegmentCompInput: React.FC = ({ */ const selectInputType = (selection: InputType) => { if (txInputType !== "default") { - if (selection === "exon_coords_tx") { + if (selection === "exon_coords") { clearGenomicCoordWarnings(); } else { clearExonWarnings(); @@ -624,7 +625,7 @@ const TxSegmentCompInput: React.FC = ({ Select input data Genomic coordinates - + Exon coordinates, transcript diff --git a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx index 385b1b95..03eb336e 100644 --- a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx +++ b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx @@ -109,7 +109,7 @@ const GetCoordinates: React.FC = () => { gene !== "" && chromosome !== "" && (start !== "" || end !== "")) || - (inputType === "exon_coords_tx" && + (inputType === "exon_coords" && txAc !== "" && (exonStart !== "" || exonEnd !== "")); @@ -191,7 +191,7 @@ const GetCoordinates: React.FC = () => { const fetchResults = () => { setIsLoading(true); - if (inputType == "exon_coords_tx") { + if (inputType == "exon_coords") { getGenomicCoords( gene, txAc, @@ -347,7 +347,7 @@ const GetCoordinates: React.FC = () => { ); - case "exon_coords_tx": + case "exon_coords": return ( <> @@ -410,7 +410,7 @@ const GetCoordinates: React.FC = () => { Select input data Genomic coordinates - Exon coordinates + Exon coordinates diff --git a/client/src/services/ResponseModels.ts b/client/src/services/ResponseModels.ts index e8087525..aaea2456 100644 --- a/client/src/services/ResponseModels.ts +++ b/client/src/services/ResponseModels.ts @@ -530,7 +530,7 @@ export interface ClientTranscriptSegmentElement { gene: Gene; elementGenomicStart?: SequenceLocation | null; elementGenomicEnd?: SequenceLocation | null; - inputType: "genomic_coords_gene" | "genomic_coords_tx" | "exon_coords_tx"; + inputType: "genomic_coords_gene" | "genomic_coords_tx" | "exon_coords"; inputTx?: string | null; inputStrand?: Strand | null; inputGene?: string | null; diff --git a/client/src/services/main.tsx b/client/src/services/main.tsx index 6d1ecbf4..04e77ff1 100644 --- a/client/src/services/main.tsx +++ b/client/src/services/main.tsx @@ -130,7 +130,7 @@ export const getTemplatedSequenceElement = async ( return responseJson; }; -export const getTxSegmentElementECT = async ( +export const getTxSegmentElementEC = async ( transcript: string, exonStart: string, exonEnd: string, @@ -153,13 +153,13 @@ export const getTxSegmentElementECT = async ( params.push(`exon_end_offset=${exonEndOffset}`); } const url = - "api/construct/structural_element/tx_segment_ect?" + params.join("&"); + "api/construct/structural_element/tx_segment_ec?" + params.join("&"); const response = await fetch(url); const responseJson = await response.json(); return responseJson; }; -export const getTxSegmentElementGCG = async ( +export const getTxSegmentElementGC = async ( gene: string, chromosome: string, transcript: string, @@ -176,7 +176,7 @@ export const getTxSegmentElementGCG = async ( if (start !== "") params.push(`start=${start}`); if (end !== "") params.push(`end=${end}`); const url = - "api/construct/structural_element/tx_segment_gcg?" + params.join("&"); + "api/construct/structural_element/tx_segment_gc?" + params.join("&"); const response = await fetch(url); const responseJson = await response.json(); return responseJson; diff --git a/server/src/curfu/routers/constructors.py b/server/src/curfu/routers/constructors.py index 1c57fe03..7f67b938 100644 --- a/server/src/curfu/routers/constructors.py +++ b/server/src/curfu/routers/constructors.py @@ -43,13 +43,13 @@ def build_gene_element(request: Request, term: str = Query("")) -> GeneElementRe @router.get( - "/api/construct/structural_element/tx_segment_ect", + "/api/construct/structural_element/tx_segment_ec", operation_id="buildTranscriptSegmentElementECT", response_model=TxSegmentElementResponse, response_model_exclude_none=True, tags=[RouteTag.CONSTRUCTORS], ) -async def build_tx_segment_ect( +async def build_tx_segment_ec( request: Request, transcript: str, exon_start: int | None = Query(None), @@ -81,13 +81,13 @@ async def build_tx_segment_ect( @router.get( - "/api/construct/structural_element/tx_segment_gcg", - operation_id="buildTranscriptSegmentElementGCG", + "/api/construct/structural_element/tx_segment_gc", + operation_id="buildTranscriptSegmentElementGC", response_model=TxSegmentElementResponse, response_model_exclude_none=True, tags=[RouteTag.CONSTRUCTORS], ) -async def build_tx_segment_gcg( +async def build_tx_segment_gc( request: Request, gene: str, chromosome: str, @@ -95,7 +95,7 @@ async def build_tx_segment_gcg( start: int | None = Query(None), end: int | None = Query(None), ) -> TxSegmentElementResponse: - """Construct Transcript Segment element by providing gene and genomic + """Construct Transcript Segment element by providing gene and/or transcript and genomic coordinates (chromosome, start, end positions). \f :param request: the HTTP request context, supplied by FastAPI. Use to access diff --git a/server/src/curfu/routers/demo.py b/server/src/curfu/routers/demo.py index c155b8b3..06c7d2d3 100644 --- a/server/src/curfu/routers/demo.py +++ b/server/src/curfu/routers/demo.py @@ -100,7 +100,7 @@ def clientify_structural_element( if element.type == StructuralElementType.TRANSCRIPT_SEGMENT_ELEMENT: nm = tx_segment_nomenclature(element) element_args["nomenclature"] = nm - element_args["inputType"] = "exon_coords_tx" + element_args["inputType"] = "exon_coords" element_args["inputTx"] = element.transcript.split(":")[1] element_args["inputExonStart"] = str(element.exonStart) element_args["inputExonStartOffset"] = str(element.exonStartOffset) diff --git a/server/src/curfu/routers/lookup.py b/server/src/curfu/routers/lookup.py index 12b22766..33d97274 100644 --- a/server/src/curfu/routers/lookup.py +++ b/server/src/curfu/routers/lookup.py @@ -3,7 +3,12 @@ from fastapi import APIRouter, Query, Request from curfu import LookupServiceError -from curfu.schemas import NormalizeGeneResponse, ResponseDict, RouteTag +from curfu.schemas import ( + GetGeneTranscriptsResponse, + NormalizeGeneResponse, + ResponseDict, + RouteTag, +) router = APIRouter() @@ -37,3 +42,28 @@ def normalize_gene(request: Request, term: str = Query("")) -> NormalizeGeneResp response["symbol"] = None response["cased"] = None return NormalizeGeneResponse(**response) + + +@router.get( + "/api/utilities/get_transcripts_for_gene", + operation_id="getTranscriptsFromGene", + response_model=GetGeneTranscriptsResponse, + response_model_exclude_none=True, +) +async def get_transcripts_for_gene(request: Request, gene: str) -> dict: + """Get all transcripts for gene term. + \f + :param Request request: the HTTP request context, supplied by FastAPI. Use to access + FUSOR and UTA-associated tools. + :param str gene: gene term provided by user + :return: Dict containing transcripts if lookup succeeds, or warnings upon failure + """ + normalized = request.app.state.fusor.gene_normalizer.normalize(gene) + symbol = normalized.gene.label + transcripts = await request.app.state.fusor.cool_seq_tool.uta_db.get_transcripts( + gene=symbol + ) + tx_for_gene = list(transcripts.rows_by_key("tx_ac")) + if transcripts.is_empty(): + return {"warnings": [f"No matching transcripts: {gene}"], "transcripts": []} + return {"transcripts": tx_for_gene} diff --git a/server/src/curfu/routers/utilities.py b/server/src/curfu/routers/utilities.py index 21940604..ca5a1f53 100644 --- a/server/src/curfu/routers/utilities.py +++ b/server/src/curfu/routers/utilities.py @@ -12,7 +12,6 @@ from curfu import logger from curfu.schemas import ( CoordsUtilsResponse, - GetGeneTranscriptsResponse, GetTranscriptsResponse, RouteTag, SequenceIDResponse, @@ -50,31 +49,6 @@ def get_mane_transcripts(request: Request, term: str) -> dict: return {"transcripts": transcripts} -@router.get( - "/api/utilities/get_transcripts_for_gene", - operation_id="getTranscriptsFromGene", - response_model=GetGeneTranscriptsResponse, - response_model_exclude_none=True, -) -async def get_transcripts_for_gene(request: Request, gene: str) -> dict: - """Get all transcripts for gene term. - \f - :param Request request: the HTTP request context, supplied by FastAPI. Use to access - FUSOR and UTA-associated tools. - :param str gene: gene term provided by user - :return: Dict containing transcripts if lookup succeeds, or warnings upon failure - """ - normalized = request.app.state.fusor.gene_normalizer.normalize(gene) - symbol = normalized.gene.label - transcripts = await request.app.state.fusor.cool_seq_tool.uta_db.get_transcripts( - gene=symbol - ) - tx_for_gene = list(transcripts.rows_by_key("tx_ac")) - if transcripts.is_empty(): - return {"warnings": [f"No matching transcripts: {gene}"], "transcripts": []} - return {"transcripts": tx_for_gene} - - @router.get( "/api/utilities/get_genomic", operation_id="getGenomicCoords", diff --git a/server/src/curfu/schemas.py b/server/src/curfu/schemas.py index 192f5145..8c8e5667 100644 --- a/server/src/curfu/schemas.py +++ b/server/src/curfu/schemas.py @@ -54,7 +54,7 @@ class ClientTranscriptSegmentElement(TranscriptSegmentElement, ClientStructuralE inputType: ( Literal["genomic_coords_gene"] | Literal["genomic_coords_tx"] - | Literal["exon_coords_tx"] + | Literal["exon_coords"] ) inputTx: str | None = None inputStrand: Strand | None = None diff --git a/server/tests/integration/test_constructors.py b/server/tests/integration/test_constructors.py index a6568433..c94ed85d 100644 --- a/server/tests/integration/test_constructors.py +++ b/server/tests/integration/test_constructors.py @@ -124,28 +124,28 @@ def check_temp_seq_response(response: dict, expected_response: dict): @pytest.mark.asyncio() -async def test_build_tx_segment_ect( +async def test_build_tx_segment_ec( check_response, check_tx_element_response, ntrk1_tx_element_start ): """Test correct functioning of transcript segment element construction using exon coordinates and transcript. """ await check_response( - "/api/construct/structural_element/tx_segment_ect?transcript=NM_002529.3&exon_start=2&exon_start_offset=1", + "/api/construct/structural_element/tx_segment_ec?transcript=NM_002529.3&exon_start=2&exon_start_offset=1", {"element": ntrk1_tx_element_start}, check_tx_element_response, ) # test require exonStart or exonEnd await check_response( - "/api/construct/structural_element/tx_segment_ect?transcript=NM_002529.3", + "/api/construct/structural_element/tx_segment_ec?transcript=NM_002529.3", {"warnings": ["Must provide either `exon_start` or `exon_end`"]}, check_tx_element_response, ) # test handle invalid transcript await check_response( - "/api/construct/structural_element/tx_segment_ect?transcript=NM_0012529.3&exon_start=3", + "/api/construct/structural_element/tx_segment_ec?transcript=NM_0012529.3&exon_start=3", {"warnings": ["Unable to get exons for NM_0012529.3"]}, check_tx_element_response, ) @@ -171,14 +171,14 @@ async def test_build_segment_gct( @pytest.mark.asyncio() -async def test_build_segment_gcg( +async def test_build_segment_gc( check_response, check_tx_element_response, tpm3_tx_g_element ): """Test correct functioning of transcript segment element construction using genomic coordinates and gene name. """ await check_response( - "/api/construct/structural_element/tx_segment_gcg?gene=TPM3&chromosome=NC_000001.11&start=154171416&end=154171417", + "/api/construct/structural_element/tx_segment_gc?gene=TPM3&chromosome=NC_000001.11&start=154171416&end=154171417", {"element": tpm3_tx_g_element}, check_tx_element_response, )