From fa8c93c1f5328e3967adff9bd436e91ec10a8cdb Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Mon, 12 Aug 2024 13:12:50 -0400 Subject: [PATCH 01/17] feat!: update tx segment element with updated cool-seq-tool structure changes --- .../TxSegmentElementInput.tsx | 3 +- .../GetCoordinates/GetCoordinates.tsx | 13 +++---- client/src/services/ResponseModels.ts | 35 +++++++++---------- client/src/services/main.tsx | 6 +--- server/src/curfu/routers/constructors.py | 34 +++--------------- server/src/curfu/routers/utilities.py | 21 +++-------- server/src/curfu/schemas.py | 12 +++---- server/tests/integration/test_constructors.py | 6 ++-- server/tests/integration/test_utilities.py | 3 +- 9 files changed, 44 insertions(+), 89 deletions(-) diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index cabeb193..72691a95 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -267,8 +267,7 @@ const TxSegmentCompInput: React.FC = ({ txAc, txChrom, txStartingGenomic, - txEndingGenomic, - txStrand + txEndingGenomic ).then((txSegmentResponse) => { if ( txSegmentResponse.warnings && diff --git a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx index 7e8f7431..75ce75b8 100644 --- a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx +++ b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx @@ -193,12 +193,12 @@ const GetCoordinates: React.FC = () => { exonEndOffset ).then((coordsResponse) => handleResponse(coordsResponse)); } else if (inputType == "genomic_coords_gene") { - getExonCoords(chromosome, start, end, strand, gene).then( - (coordsResponse) => handleResponse(coordsResponse) + getExonCoords(chromosome, start, end, gene).then((coordsResponse) => + handleResponse(coordsResponse) ); } else if (inputType == "genomic_coords_tx") { - getExonCoords(chromosome, start, end, strand, "", txAc).then( - (coordsResponse) => handleResponse(coordsResponse) + getExonCoords(chromosome, start, end, "", txAc).then((coordsResponse) => + handleResponse(coordsResponse) ); } }; @@ -250,10 +250,7 @@ const GetCoordinates: React.FC = () => { const genomicCoordinateInfo = ( <> - + => { const params: Array = [ `transcript=${transcript}`, `chromosome=${chromosome}`, - `strand=${strand === "+" ? "%2B" : "-"}`, ]; if (start !== "") params.push(`start=${start}`); if (end !== "") params.push(`end=${end}`); @@ -251,13 +249,11 @@ export const getExonCoords = async ( chromosome: string, start: string, end: string, - strand: string, gene?: string, txAc?: string ): Promise => { const argsArray = [ `chromosome=${chromosome}`, - `strand=${strand === "+" ? "%2B" : "-"}`, gene && gene !== "" ? `gene=${gene}` : "", txAc && txAc !== "" ? `transcript=${txAc}` : "", start && start !== "" ? `start=${start}` : "", diff --git a/server/src/curfu/routers/constructors.py b/server/src/curfu/routers/constructors.py index 13366249..c7367978 100644 --- a/server/src/curfu/routers/constructors.py +++ b/server/src/curfu/routers/constructors.py @@ -15,7 +15,7 @@ TemplatedSequenceElementResponse, TxSegmentElementResponse, ) -from curfu.sequence_services import InvalidInputError, get_strand +from curfu.sequence_services import get_strand router = APIRouter() @@ -93,7 +93,6 @@ async def build_tx_segment_gct( chromosome: str, start: int | None = Query(None), end: int | None = Query(None), - strand: str | None = Query(None), ) -> TxSegmentElementResponse: """Construct Transcript Segment element by providing transcript and genomic coordinates (chromosome, start, end positions). @@ -107,23 +106,12 @@ async def build_tx_segment_gct( :return: Pydantic class with TranscriptSegment element if successful, and warnings otherwise. """ - if strand is not None: - try: - strand_validated = get_strand(strand) - except InvalidInputError: - warning = f"Received invalid strand value: {strand}" - logger.warning(warning) - return TxSegmentElementResponse(warnings=[warning], element=None) - else: - strand_validated = strand tx_segment, warnings = await request.app.state.fusor.transcript_segment_element( tx_to_genomic_coords=False, transcript=parse_identifier(transcript), chromosome=parse_identifier(chromosome), - start=start, - end=end, - strand=strand_validated, - residue_mode="inter-residue", + genomic_start=start, + genomic_end=end, ) return TxSegmentElementResponse(element=tx_segment, warnings=warnings) @@ -141,7 +129,6 @@ async def build_tx_segment_gcg( chromosome: str, start: int | None = Query(None), end: int | None = Query(None), - strand: str | None = Query(None), ) -> TxSegmentElementResponse: """Construct Transcript Segment element by providing gene and genomic coordinates (chromosome, start, end positions). @@ -155,23 +142,12 @@ async def build_tx_segment_gcg( :return: Pydantic class with TranscriptSegment element if successful, and warnings otherwise. """ - if strand is not None: - try: - strand_validated = get_strand(strand) - except InvalidInputError: - warning = f"Received invalid strand value: {strand}" - logger.warning(warning) - return TxSegmentElementResponse(warnings=[warning], element=None) - else: - strand_validated = strand tx_segment, warnings = await request.app.state.fusor.transcript_segment_element( tx_to_genomic_coords=False, gene=gene, chromosome=parse_identifier(chromosome), - strand=strand_validated, - start=start, - end=end, - residue_mode="inter-residue", + genomic_start=start, + genomic_end=end, ) return TxSegmentElementResponse(element=tx_segment, warnings=warnings) diff --git a/server/src/curfu/routers/utilities.py b/server/src/curfu/routers/utilities.py index c221fe1c..6203a7a4 100644 --- a/server/src/curfu/routers/utilities.py +++ b/server/src/curfu/routers/utilities.py @@ -16,7 +16,6 @@ RouteTag, SequenceIDResponse, ) -from curfu.sequence_services import InvalidInputError, get_strand router = APIRouter() @@ -107,7 +106,7 @@ async def get_genome_coords( if exon_end is not None and exon_end_offset is None: exon_end_offset = 0 - response = await request.app.state.fusor.cool_seq_tool.ex_g_coords_mapper.transcript_to_genomic_coordinates( + response = await request.app.state.fusor.cool_seq_tool.ex_g_coords_mapper.tx_segment_to_genomic( transcript=transcript, gene=gene, exon_start=exon_start, @@ -134,7 +133,6 @@ async def get_exon_coords( chromosome: str, start: int | None = None, end: int | None = None, - strand: str | None = None, gene: str | None = None, transcript: str | None = None, ) -> CoordsUtilsResponse: @@ -145,7 +143,6 @@ async def get_exon_coords( :param chromosome: chromosome, either as a number/X/Y or as an accession :param start: genomic start position :param end: genomic end position - :param strand: strand of genomic position :param gene: gene symbol or ID :param transcript: transcript accession ID :return: response with exon coordinates if successful, or warnings if failed @@ -155,23 +152,15 @@ async def get_exon_coords( warnings.append("Must provide start and/or end coordinates") if transcript is None and gene is None: warnings.append("Must provide gene and/or transcript") - if strand is not None: - try: - strand_validated = get_strand(strand) - except InvalidInputError: - warnings.append(f"Received invalid strand value: {strand}") - else: - strand_validated = strand if warnings: for warning in warnings: logger.warning(warning) return CoordsUtilsResponse(warnings=warnings, coordinates_data=None) - response = await request.app.state.fusor.cool_seq_tool.ex_g_coords_mapper.genomic_to_transcript_exon_coordinates( - alt_ac=chromosome, - start=start, - end=end, - strand=strand_validated, + response = await request.app.state.fusor.cool_seq_tool.ex_g_coords_mapper.genomic_to_tx_segment( + genomic_ac=chromosome, + genomic_start=start, + genomic_end=end, transcript=transcript, gene=gene, ) diff --git a/server/src/curfu/schemas.py b/server/src/curfu/schemas.py index b5818ee3..ad2eaabe 100644 --- a/server/src/curfu/schemas.py +++ b/server/src/curfu/schemas.py @@ -3,13 +3,13 @@ from enum import Enum from typing import Literal -from cool_seq_tool.schemas import GenomicData +from cool_seq_tool.schemas import GenomicTxData from fusor.models import ( Assay, AssayedFusion, - AssayedFusionElements, + AssayedFusionElement, CategoricalFusion, - CategoricalFusionElements, + CategoricalFusionElement, CausativeEvent, FunctionalDomain, Fusion, @@ -213,7 +213,7 @@ def validate_number(cls, v) -> int: class CoordsUtilsResponse(Response): """Response model for genomic coordinates retrieval""" - coordinates_data: GenomicData | None + coordinates_data: GenomicTxData | None class SequenceIDResponse(Response): @@ -301,7 +301,7 @@ class FormattedAssayedFusion(BaseModel): """ fusion_type: FusionType.ASSAYED_FUSION = FusionType.ASSAYED_FUSION - structure: AssayedFusionElements + structure: list[AssayedFusionElement] causative_event: CausativeEvent | None = None assay: Assay | None = None regulatory_element: RegulatoryElement | None = None @@ -315,7 +315,7 @@ class FormattedCategoricalFusion(BaseModel): """ fusion_type: FusionType.CATEGORICAL_FUSION = FusionType.CATEGORICAL_FUSION - structure: CategoricalFusionElements + structure: list[CategoricalFusionElement] regulatory_element: RegulatoryElement | None = None critical_functional_domains: list[FunctionalDomain] | None = None reading_frame_preserved: bool | None = None diff --git a/server/tests/integration/test_constructors.py b/server/tests/integration/test_constructors.py index ef6db0be..a6568433 100644 --- a/server/tests/integration/test_constructors.py +++ b/server/tests/integration/test_constructors.py @@ -159,12 +159,12 @@ async def test_build_segment_gct( genomic coordinates and transcript. """ await check_response( - "/api/construct/structural_element/tx_segment_gct?transcript=NM_152263.4&chromosome=NC_000001.11&start=154171416&end=154171417&strand=-", + "/api/construct/structural_element/tx_segment_gct?transcript=NM_152263.4&chromosome=NC_000001.11&start=154171416&end=154171417", {"element": tpm3_tx_t_element}, check_tx_element_response, ) await check_response( - "/api/construct/structural_element/tx_segment_gct?transcript=refseq%3ANM_152263.4&chromosome=NC_000001.11&start=154171416&end=154171417&strand=-", + "/api/construct/structural_element/tx_segment_gct?transcript=refseq%3ANM_152263.4&chromosome=NC_000001.11&start=154171416&end=154171417", {"element": tpm3_tx_t_element}, check_tx_element_response, ) @@ -178,7 +178,7 @@ async def test_build_segment_gcg( 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&strand=-", + "/api/construct/structural_element/tx_segment_gcg?gene=TPM3&chromosome=NC_000001.11&start=154171416&end=154171417", {"element": tpm3_tx_g_element}, check_tx_element_response, ) diff --git a/server/tests/integration/test_utilities.py b/server/tests/integration/test_utilities.py index a74428d1..6a98c611 100644 --- a/server/tests/integration/test_utilities.py +++ b/server/tests/integration/test_utilities.py @@ -136,7 +136,7 @@ def check_coords_response(response: dict, expected_response: dict): assert response["coordinates_data"] == expected_response["coordinates_data"] await check_response( - "/api/utilities/get_exon?chromosome=1&transcript=NM_152263.3&start=154192135&strand=-", + "/api/utilities/get_exon?chromosome=1&transcript=NM_152263.3&start=154192135", { "coordinates_data": { "gene": "TPM3", @@ -145,7 +145,6 @@ def check_coords_response(response: dict, expected_response: dict): "exon_start": 1, "exon_start_offset": 1, "transcript": "NM_152263.3", - "strand": -1, } }, check_coords_response, From 9a6281da7a7c3fd60714f1b899498d81c5d60948 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Mon, 12 Aug 2024 14:16:27 -0400 Subject: [PATCH 02/17] fix: tx segment element bugs --- .../GetCoordinates/GetCoordinates.tsx | 35 +++++++++++++------ server/src/curfu/routers/utilities.py | 8 ++--- server/src/curfu/schemas.py | 4 +-- server/tests/conftest.py | 4 +-- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx index 75ce75b8..b9fd2428 100644 --- a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx +++ b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx @@ -215,25 +215,38 @@ const GetCoordinates: React.FC = () => { const renderResults = (): React.ReactFragment => { if (inputValid) { if (results) { + const txSegStart = results.seg_start; + const txSegEnd = results.seg_end; + + const genomicStart = + txSegStart?.genomic_location.start || + txSegStart?.genomic_location.end; + const genomicEnd = + txSegEnd?.genomic_location.start || txSegEnd?.genomic_location.end; + return ( {renderRow("Gene", results.gene)} - {renderRow("Chromosome", results.chr)} - {results.start ? renderRow("Genomic start", results.start) : null} - {results.end ? renderRow("Genomic end", results.end) : null} + {renderRow("Chromosome", results.genomic_ac)} + {genomicStart != null + ? renderRow("Genomic start", genomicStart) + : null} + {genomicEnd != null ? renderRow("Genomic end", genomicEnd) : null} {results.strand ? renderRow("Strand", results.strand === 1 ? "+" : "-") : null} - {renderRow("Transcript", results.transcript)} - {results.exon_start - ? renderRow("Exon start", results.exon_start) + {renderRow("Transcript", results.tx_ac)} + {txSegStart?.exon_ord != null + ? renderRow("Exon start", txSegStart.exon_ord) + : null} + {txSegStart?.offset != null + ? renderRow("Exon start offset", txSegStart.offset) : null} - {results.exon_start_offset - ? renderRow("Exon start offset", results.exon_start_offset) + {txSegEnd?.exon_ord != null + ? renderRow("Exon end", txSegEnd.exon_ord) : null} - {results.exon_end ? renderRow("Exon end", results.exon_end) : null} - {results.exon_end_offset - ? renderRow("Exon end offset", results.exon_end_offset) + {txSegEnd?.offset != null + ? renderRow("Exon end offset", txSegEnd.offset) : null}
); diff --git a/server/src/curfu/routers/utilities.py b/server/src/curfu/routers/utilities.py index 6203a7a4..ca5a1f53 100644 --- a/server/src/curfu/routers/utilities.py +++ b/server/src/curfu/routers/utilities.py @@ -114,11 +114,11 @@ async def get_genome_coords( exon_start_offset=exon_start_offset, exon_end_offset=exon_end_offset, ) - warnings = response.warnings + warnings = response.errors if warnings: return CoordsUtilsResponse(warnings=warnings, coordinates_data=None) - return CoordsUtilsResponse(coordinates_data=response.genomic_data, warnings=None) + return CoordsUtilsResponse(coordinates_data=response, warnings=None) @router.get( @@ -164,11 +164,11 @@ async def get_exon_coords( transcript=transcript, gene=gene, ) - warnings = response.warnings + warnings = response.errors if warnings: return CoordsUtilsResponse(warnings=warnings, coordinates_data=None) - return CoordsUtilsResponse(coordinates_data=response.genomic_data, warnings=None) + return CoordsUtilsResponse(coordinates_data=response, warnings=None) @router.get( diff --git a/server/src/curfu/schemas.py b/server/src/curfu/schemas.py index ad2eaabe..007c6d9b 100644 --- a/server/src/curfu/schemas.py +++ b/server/src/curfu/schemas.py @@ -3,7 +3,7 @@ from enum import Enum from typing import Literal -from cool_seq_tool.schemas import GenomicTxData +from cool_seq_tool.mappers.exon_genomic_coords import GenomicTxSegService from fusor.models import ( Assay, AssayedFusion, @@ -213,7 +213,7 @@ def validate_number(cls, v) -> int: class CoordsUtilsResponse(Response): """Response model for genomic coordinates retrieval""" - coordinates_data: GenomicTxData | None + coordinates_data: GenomicTxSegService | None class SequenceIDResponse(Response): diff --git a/server/tests/conftest.py b/server/tests/conftest.py index 4b70125b..743e674d 100644 --- a/server/tests/conftest.py +++ b/server/tests/conftest.py @@ -156,7 +156,7 @@ def tpm3_tx_t_element(tpm3_gene): @pytest.fixture(scope="module") -def tpm3_tx_g_element(tpm3_descriptor): +def tpm3_tx_g_element(tpm3_gene): """Provide TranscriptSegmentElement for TPM3 gene constructed using genomic coordinates and gene name. """ @@ -167,7 +167,7 @@ def tpm3_tx_g_element(tpm3_descriptor): "exonStartOffset": 5, "exonEnd": 6, "exonEndOffset": -71, - "gene": tpm3_descriptor, + "gene": tpm3_gene, "elementGenomicStart": { "id": "fusor.location_descriptor:NC_000001.11", "type": "SequenceLocation", From fbe0a83f2221073c4ccfbd118904a5579bae7782 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Mon, 12 Aug 2024 15:10:06 -0400 Subject: [PATCH 03/17] update response models --- client/src/services/ResponseModels.ts | 67 +++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/client/src/services/ResponseModels.ts b/client/src/services/ResponseModels.ts index 7558f88d..ff5f1979 100644 --- a/client/src/services/ResponseModels.ts +++ b/client/src/services/ResponseModels.ts @@ -630,19 +630,66 @@ export interface ClientStructuralElement { */ export interface CoordsUtilsResponse { warnings?: string[] | null; - coordinates_data: GenomicTxData | null; + coordinates_data: GenomicTxSegService | null; } /** - * Represent aligned genomic/transcript exon data + * Service model for genomic and transcript data. */ -export interface GenomicTxData { - gene: string; - strand: Strand; - tx_pos_range: [unknown, unknown]; - alt_pos_range: [unknown, unknown]; - alt_aln_method: string; - tx_exon_id: number; - alt_exon_id: number; +export interface GenomicTxSegService { + /** + * HGNC gene symbol. + */ + gene?: string | null; + /** + * RefSeq genomic accession. + */ + genomic_ac?: string | null; + /** + * RefSeq transcript accession. + */ + tx_ac?: string | null; + /** + * Start transcript segment. + */ + seg_start?: TxSegment | null; + /** + * End transcript segment. + */ + seg_end?: TxSegment | null; + /** + * Error messages. + */ + errors?: string[]; + /** + * Service metadata. + */ + service_meta: ServiceMeta; +} +/** + * Model for representing transcript segment data. + */ +export interface TxSegment { + /** + * Exon number. 0-based. + */ + exon_ord: number; + /** + * The value added to or subtracted from the `genomic_location` to find the start or end of an exon. + */ + offset?: number; + /** + * The genomic position of a transcript segment. + */ + genomic_location: SequenceLocation; +} +/** + * Metadata for cool_seq_tool service + */ +export interface ServiceMeta { + name?: "cool_seq_tool"; + version: string; + response_datetime: string; + url?: "https://github.com/GenomicMedLab/cool-seq-tool"; } /** * Response model for demo fusion object retrieval endpoints. From b2c6787a9a9e0c072a957b15a552857529a0a312 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Tue, 20 Aug 2024 10:45:23 -0400 Subject: [PATCH 04/17] feat: update variable names with cool-seq-tool updates --- client/src/components/Pages/Summary/Main/Summary.tsx | 2 -- server/src/curfu/routers/constructors.py | 8 ++++---- server/src/curfu/routers/utilities.py | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/components/Pages/Summary/Main/Summary.tsx b/client/src/components/Pages/Summary/Main/Summary.tsx index f8e2a01e..14b0605e 100644 --- a/client/src/components/Pages/Summary/Main/Summary.tsx +++ b/client/src/components/Pages/Summary/Main/Summary.tsx @@ -162,8 +162,6 @@ export const Summary: React.FC = ({ setVisibleTab }) => { setFormattedFusion(formattedFusion); }, [fusion]); - console.log(formattedFusion); - return ( <> {(!validationErrors || validationErrors.length === 0) && diff --git a/server/src/curfu/routers/constructors.py b/server/src/curfu/routers/constructors.py index c7367978..bd39db38 100644 --- a/server/src/curfu/routers/constructors.py +++ b/server/src/curfu/routers/constructors.py @@ -110,8 +110,8 @@ async def build_tx_segment_gct( tx_to_genomic_coords=False, transcript=parse_identifier(transcript), chromosome=parse_identifier(chromosome), - genomic_start=start, - genomic_end=end, + seg_start_genomic=start, + seg_end_genomic=end, ) return TxSegmentElementResponse(element=tx_segment, warnings=warnings) @@ -146,8 +146,8 @@ async def build_tx_segment_gcg( tx_to_genomic_coords=False, gene=gene, chromosome=parse_identifier(chromosome), - genomic_start=start, - genomic_end=end, + seg_start_genomic=start, + seg_end_genomic=end, ) return TxSegmentElementResponse(element=tx_segment, warnings=warnings) diff --git a/server/src/curfu/routers/utilities.py b/server/src/curfu/routers/utilities.py index ca5a1f53..0f08d955 100644 --- a/server/src/curfu/routers/utilities.py +++ b/server/src/curfu/routers/utilities.py @@ -159,8 +159,8 @@ async def get_exon_coords( response = await request.app.state.fusor.cool_seq_tool.ex_g_coords_mapper.genomic_to_tx_segment( genomic_ac=chromosome, - genomic_start=start, - genomic_end=end, + seg_start_genomic=start, + seg_end_genomic=end, transcript=transcript, gene=gene, ) From 053843e3c4e1047afe2427a117c747ba48b2b291 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Wed, 21 Aug 2024 14:21:36 -0400 Subject: [PATCH 05/17] feat: update calls to fusor and cool-seq-tool with updated params --- server/pyproject.toml | 2 +- server/src/curfu/routers/constructors.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/pyproject.toml b/server/pyproject.toml index 1f02c35f..34606c85 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "boto3", "botocore", "fusor ~= 0.2.0", - "cool-seq-tool ~= 0.5.1", + "cool-seq-tool ~= 0.7.0", "pydantic == 2.4.2", "gene-normalizer ~= 0.4.0", ] diff --git a/server/src/curfu/routers/constructors.py b/server/src/curfu/routers/constructors.py index bd39db38..d4d4d94d 100644 --- a/server/src/curfu/routers/constructors.py +++ b/server/src/curfu/routers/constructors.py @@ -109,7 +109,7 @@ async def build_tx_segment_gct( tx_segment, warnings = await request.app.state.fusor.transcript_segment_element( tx_to_genomic_coords=False, transcript=parse_identifier(transcript), - chromosome=parse_identifier(chromosome), + genomic_ac=parse_identifier(chromosome), seg_start_genomic=start, seg_end_genomic=end, ) @@ -145,7 +145,7 @@ async def build_tx_segment_gcg( tx_segment, warnings = await request.app.state.fusor.transcript_segment_element( tx_to_genomic_coords=False, gene=gene, - chromosome=parse_identifier(chromosome), + genomic_ac=parse_identifier(chromosome), seg_start_genomic=start, seg_end_genomic=end, ) From b58a5b7b59cf429be1d91d27150cfad8087b1977 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Wed, 21 Aug 2024 15:25:45 -0400 Subject: [PATCH 06/17] update fusor version --- server/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/pyproject.toml b/server/pyproject.toml index c6bcab6d..87093fae 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "click", "boto3", "botocore", - "fusor ~= 0.3.0", + "fusor ~= 0.4.0", "cool-seq-tool ~= 0.7.0", "pydantic == 2.4.2", "gene-normalizer ~= 0.4.0", From 726d7e69061b8cafdd2ccd29f349d127b5cca2a6 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Thu, 22 Aug 2024 11:17:31 -0400 Subject: [PATCH 07/17] updating fusor version --- requirements.txt | 2 +- server/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index a03724bb..152f56e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ decorator==5.1.1 executing==1.2.0 fake-useragent==1.1.3 fastapi==0.100.0 -fusor==0.2.0 +fusor==0.4.1 ga4gh.vrs==2.0.0a10 gene-normalizer==0.4.0 h11==0.14.0 diff --git a/server/pyproject.toml b/server/pyproject.toml index 87093fae..e0ba96b6 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "click", "boto3", "botocore", - "fusor ~= 0.4.0", + "fusor ~= 0.4.1", "cool-seq-tool ~= 0.7.0", "pydantic == 2.4.2", "gene-normalizer ~= 0.4.0", From 6c672bd71ce43a37708fdb866a5e6b545f7c1074 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Thu, 22 Aug 2024 13:58:04 -0400 Subject: [PATCH 08/17] wip: fixing tests from cool-seq-tool and fusor updates --- server/src/curfu/routers/demo.py | 6 +- server/tests/conftest.py | 17 +++- server/tests/integration/test_constructors.py | 4 +- server/tests/integration/test_utilities.py | 77 +++++++++++++++---- server/tests/integration/test_validate.py | 6 +- 5 files changed, 81 insertions(+), 29 deletions(-) diff --git a/server/src/curfu/routers/demo.py b/server/src/curfu/routers/demo.py index c155b8b3..f2d6646c 100644 --- a/server/src/curfu/routers/demo.py +++ b/server/src/curfu/routers/demo.py @@ -71,7 +71,7 @@ def clientify_structural_element( context :return: client-ready structural element """ - element_args = element.dict() + element_args = element.model_dump() element_args["elementId"] = str(uuid4()) if element.type == StructuralElementType.UNKNOWN_GENE_ELEMENT: @@ -119,7 +119,7 @@ def clientify_fusion(fusion: Fusion, fusor_instance: FUSOR) -> ClientFusion: :param fusor_instance: FUSOR object instance provided by FastAPI request context :return: completed client-ready fusion """ - fusion_args = fusion.dict() + fusion_args = fusion.model_dump() client_elements = [ clientify_structural_element(element, fusor_instance) for element in fusion.structure @@ -145,7 +145,7 @@ def clientify_fusion(fusion: Fusion, fusor_instance: FUSOR) -> ClientFusion: if fusion.criticalFunctionalDomains: client_domains = [] for domain in fusion.criticalFunctionalDomains: - client_domain = domain.dict() + client_domain = domain.model_dump() client_domain["domainId"] = str(uuid4()) client_domains.append(client_domain) fusion_args["criticalFunctionalDomains"] = client_domains diff --git a/server/tests/conftest.py b/server/tests/conftest.py index 743e674d..21a71159 100644 --- a/server/tests/conftest.py +++ b/server/tests/conftest.py @@ -1,5 +1,6 @@ """Provide core fixtures for testing Flask functions.""" +import asyncio from collections.abc import Callable import pytest @@ -8,6 +9,14 @@ from httpx import ASGITransport, AsyncClient +@pytest_asyncio.fixture(scope="session") +def event_loop(): + """Create an instance of the event loop with session scope.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + @pytest_asyncio.fixture(scope="session") async def async_client(): """Provide httpx async client fixture.""" @@ -136,9 +145,9 @@ def tpm3_tx_t_element(tpm3_gene): "type": "TranscriptSegmentElement", "transcript": "refseq:NM_152263.4", "exonStart": 6, - "exonStartOffset": 71, + "exonStartOffset": 72, "exonEnd": 6, - "exonEndOffset": -4, + "exonEndOffset": -5, "gene": tpm3_gene, "elementGenomicStart": { "id": "fusor.location_descriptor:NC_000001.11", @@ -164,9 +173,9 @@ def tpm3_tx_g_element(tpm3_gene): "type": "TranscriptSegmentElement", "transcript": "refseq:NM_152263.4", "exonStart": 6, - "exonStartOffset": 5, + "exonStartOffset": 72, "exonEnd": 6, - "exonEndOffset": -71, + "exonEndOffset": -5, "gene": tpm3_gene, "elementGenomicStart": { "id": "fusor.location_descriptor:NC_000001.11", diff --git a/server/tests/integration/test_constructors.py b/server/tests/integration/test_constructors.py index a6568433..38642863 100644 --- a/server/tests/integration/test_constructors.py +++ b/server/tests/integration/test_constructors.py @@ -146,7 +146,7 @@ async def test_build_tx_segment_ect( # test handle invalid transcript await check_response( "/api/construct/structural_element/tx_segment_ect?transcript=NM_0012529.3&exon_start=3", - {"warnings": ["Unable to get exons for NM_0012529.3"]}, + {"warnings": ["No exons found given NM_0012529.3"]}, check_tx_element_response, ) @@ -213,7 +213,7 @@ async def test_build_templated_sequence( "element": { "type": "TemplatedSequenceElement", "region": { - "id": "ga4gh:SL.thjDCmA1u2mB0vLGjgQbCOEg81eP5hdO", + "id": "ga4gh:SL._4tPimZ9AFATsAr2TKp-6VDZMNcQnIf8", "type": "SequenceLocation", "sequenceReference": { "id": "refseq:NC_000001.11", diff --git a/server/tests/integration/test_utilities.py b/server/tests/integration/test_utilities.py index 6a98c611..c6b68881 100644 --- a/server/tests/integration/test_utilities.py +++ b/server/tests/integration/test_utilities.py @@ -95,15 +95,39 @@ def check_genomic_coords_response(response: dict, expected_response: dict): { "coordinates_data": { "gene": "NTRK1", - "chr": "NC_000001.11", - "start": 156861146, - "end": 156868504, - "exon_start": 1, - "exon_start_offset": 0, - "exon_end": 6, - "exon_end_offset": 0, - "transcript": "NM_002529.3", - "strand": 1, + "genomic_ac": "NC_000001.11", + "tx_ac": "NM_002529.3", + "seg_start": { + "exon_ord": 0, + "offset": 0, + "genomic_location": { + "type": "SequenceLocation", + "sequenceReference": { + "type": "SequenceReference", + "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO", + }, + "start": 156860878, + }, + }, + "seg_end": { + "exon_ord": 5, + "offset": 0, + "genomic_location": { + "type": "SequenceLocation", + "sequenceReference": { + "type": "SequenceReference", + "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO", + }, + "end": 156868647, + }, + }, + "errors": [], + "service_meta": { + "name": "cool_seq_tool", + "version": "0.6.1.dev37+g1f798ae", + "response_datetime": "2024-08-22T17:42:06.009588Z", + "url": "https://github.com/GenomicMedLab/cool-seq-tool", + }, } }, check_genomic_coords_response, @@ -133,25 +157,44 @@ def check_coords_response(response: dict, expected_response: dict): "coordinates_data" not in expected_response ): return - assert response["coordinates_data"] == expected_response["coordinates_data"] + actual_coord_data = response["coordinates_data"] + expected_coord_data = expected_response["coordinates_data"] + + assert actual_coord_data.get("gene") == expected_coord_data.get("gene") + assert actual_coord_data["genomic_ac"] == expected_coord_data.get("genomic_ac") + assert actual_coord_data.get("tx_ac") == expected_coord_data.get("tx_ac") + assert actual_coord_data.get("seg_start") == expected_coord_data.get( + "seg_start" + ) + assert actual_coord_data.get("seg_end") == expected_coord_data.get("seg_end") await check_response( - "/api/utilities/get_exon?chromosome=1&transcript=NM_152263.3&start=154192135", + "/api/utilities/get_exon?chromosome=NC_000001.11&transcript=NM_152263.3&start=154192135", { "coordinates_data": { "gene": "TPM3", - "chr": "NC_000001.11", - "start": 154192134, - "exon_start": 1, - "exon_start_offset": 1, - "transcript": "NM_152263.3", + "genomic_ac": "NC_000001.11", + "tx_ac": "NM_152263.3", + "seg_start": { + "exon_ord": 0, + "offset": 0, + "genomic_location": { + "type": "SequenceLocation", + "sequenceReference": { + "type": "SequenceReference", + "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO", + }, + "end": 154192135, + }, + }, + "errors": [], } }, check_coords_response, ) await check_response( - "/api/utilities/get_exon?chromosome=1", + "/api/utilities/get_exon?chromosome=NC_000001.11", { "warnings": [ "Must provide start and/or end coordinates", diff --git a/server/tests/integration/test_validate.py b/server/tests/integration/test_validate.py index fdd8dadb..f4d3cb75 100644 --- a/server/tests/integration/test_validate.py +++ b/server/tests/integration/test_validate.py @@ -197,9 +197,9 @@ async def test_validate_fusion( """Perform some basic tests on the fusion validation endpoint.""" await check_validated_fusion_response(async_client, alk_fusion, "ALK fusion") await check_validated_fusion_response(async_client, ewsr1_fusion, "EWSR1 fusion") - await check_validated_fusion_response( - async_client, ewsr1_fusion_fill_types, "EWSR1 fusion needing type inference" - ) + # await check_validated_fusion_response( + # async_client, ewsr1_fusion_fill_types, "EWSR1 fusion needing type inference" + # ) await check_validated_fusion_response( async_client, wrong_type_fusion, "Wrong fusion type case" ) From d56bff01ca8d4c1359ff63d9ca4ba769fdd07358 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Thu, 22 Aug 2024 14:02:01 -0400 Subject: [PATCH 09/17] tests: updating tests with fusor changes --- server/tests/integration/test_constructors.py | 2 +- server/tests/integration/test_utilities.py | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/server/tests/integration/test_constructors.py b/server/tests/integration/test_constructors.py index 38642863..b711ae27 100644 --- a/server/tests/integration/test_constructors.py +++ b/server/tests/integration/test_constructors.py @@ -220,7 +220,7 @@ async def test_build_templated_sequence( "refgetAccession": "", "type": "SequenceReference", }, - "start": 154171414, + "start": 154171415, "end": 154171417, }, "strand": -1, diff --git a/server/tests/integration/test_utilities.py b/server/tests/integration/test_utilities.py index c6b68881..c027335b 100644 --- a/server/tests/integration/test_utilities.py +++ b/server/tests/integration/test_utilities.py @@ -88,7 +88,16 @@ def check_genomic_coords_response(response: dict, expected_response: dict): assert "warnings" in response assert set(response["warnings"]) == set(expected_response["warnings"]) return - assert response["coordinates_data"] == expected_response["coordinates_data"] + actual_coord_data = response["coordinates_data"] + expected_coord_data = expected_response["coordinates_data"] + + assert actual_coord_data.get("gene") == expected_coord_data.get("gene") + assert actual_coord_data["genomic_ac"] == expected_coord_data.get("genomic_ac") + assert actual_coord_data.get("tx_ac") == expected_coord_data.get("tx_ac") + assert actual_coord_data.get("seg_start") == expected_coord_data.get( + "seg_start" + ) + assert actual_coord_data.get("seg_end") == expected_coord_data.get("seg_end") await check_response( "/api/utilities/get_genomic?transcript=NM_002529.3&exon_start=1&exon_end=6", @@ -206,11 +215,7 @@ def check_coords_response(response: dict, expected_response: dict): await check_response( "/api/utilities/get_exon?chromosome=NC_000001.11&start=154192131&gene=TPM3", - { - "warnings": [ - "Unable to find mane data for NC_000001.11 with position 154192130 on gene TPM3" - ] - }, + {"warnings": ["Must find exactly one row for genomic data, but found: 0"]}, check_coords_response, ) From 7191723ee64598656a11ddb9370fb8d1f06c87f9 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Thu, 22 Aug 2024 15:02:30 -0400 Subject: [PATCH 10/17] fixing test examples and adding checks for correct start/end on sequence locations --- server/tests/conftest.py | 18 ++++++++---------- server/tests/integration/test_constructors.py | 11 +++++++---- server/tests/integration/test_validate.py | 1 + 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/server/tests/conftest.py b/server/tests/conftest.py index 21a71159..3f9e95a2 100644 --- a/server/tests/conftest.py +++ b/server/tests/conftest.py @@ -69,7 +69,7 @@ def check_sequence_location(): :param dict sequence_location: sequence location structure """ - def check_sequence_location(sequence_location): + def check_sequence_location(sequence_location, expected_sequence_location): assert "ga4gh:SL." in sequence_location.get("id") assert sequence_location.get("type") == "SequenceLocation" sequence_reference = sequence_location.get("sequenceReference", {}) @@ -77,6 +77,9 @@ def check_sequence_location(sequence_location): assert sequence_reference.get("refgetAccession") assert sequence_reference.get("type") == "SequenceReference" + assert sequence_location.get("start") == expected_sequence_location.get("start") + assert sequence_location.get("end") == expected_sequence_location.get("end") + return check_sequence_location @@ -130,8 +133,7 @@ def ntrk1_tx_element_start(ntrk1_gene): "elementGenomicStart": { "id": "fusor.location_descriptor:NC_000001.11", "type": "SequenceLocation", - "start": 156864429, - "end": 156864430, + "start": 156864354, }, } @@ -152,14 +154,12 @@ def tpm3_tx_t_element(tpm3_gene): "elementGenomicStart": { "id": "fusor.location_descriptor:NC_000001.11", "type": "SequenceLocation", - "start": 154171416, - "end": 154171417, + "end": 154171416, }, "elementGenomicEnd": { "id": "fusor.location_descriptor:NC_000001.11", "type": "SequenceLocation", "start": 154171417, - "end": 154171418, }, } @@ -180,13 +180,11 @@ def tpm3_tx_g_element(tpm3_gene): "elementGenomicStart": { "id": "fusor.location_descriptor:NC_000001.11", "type": "SequenceLocation", - "start": 154171483, - "end": 154171484, + "end": 154171416, }, "elementGenomicEnd": { "id": "fusor.location_descriptor:NC_000001.11", "type": "SequenceLocation", - "start": 154171482, - "end": 154171483, + "start": 154171417, }, } diff --git a/server/tests/integration/test_constructors.py b/server/tests/integration/test_constructors.py index b711ae27..15e0576b 100644 --- a/server/tests/integration/test_constructors.py +++ b/server/tests/integration/test_constructors.py @@ -66,10 +66,12 @@ def check_tx_element_response(response: dict, expected_response: dict): ) genomic_start = response_element.get("elementGenomicStart", {}) genomic_end = response_element.get("elementGenomicEnd", {}) + expected_genomic_start = expected_element.get("elementGenomicStart", {}) + expected_genomic_end = expected_element.get("elementGenomicEnd", {}) if genomic_start: - check_sequence_location(genomic_start) + check_sequence_location(genomic_start, expected_genomic_start) if genomic_end: - check_sequence_location(genomic_end) + check_sequence_location(genomic_end, expected_genomic_end) return check_tx_element_response @@ -95,8 +97,9 @@ def check_re_response(response: dict, expected_response: dict): assert response_re.get("featureId") == expected_re.get("featureId") assert response_re.get("associatedGene") == expected_re.get("associatedGene") sequence_location = response_re.get("sequenceLocation") + expected_sequence_location = expected_re.get("sequenceLocation") if sequence_location: - check_sequence_location(sequence_location) + check_sequence_location(sequence_location, expected_sequence_location) return check_re_response @@ -116,7 +119,7 @@ def check_temp_seq_response(response: dict, expected_response: dict): assert response_elem["type"] == expected_elem["type"] assert response_elem["strand"] == expected_elem["strand"] assert response_elem["region"]["id"] == expected_elem["region"]["id"] - check_sequence_location(response_elem["region"] or {}) + check_sequence_location(response_elem["region"] or {}, expected_elem["region"]) assert response_elem["region"]["start"] == expected_elem["region"]["start"] assert response_elem["region"]["end"] == expected_elem["region"]["end"] diff --git a/server/tests/integration/test_validate.py b/server/tests/integration/test_validate.py index f4d3cb75..d31fabac 100644 --- a/server/tests/integration/test_validate.py +++ b/server/tests/integration/test_validate.py @@ -197,6 +197,7 @@ async def test_validate_fusion( """Perform some basic tests on the fusion validation endpoint.""" await check_validated_fusion_response(async_client, alk_fusion, "ALK fusion") await check_validated_fusion_response(async_client, ewsr1_fusion, "EWSR1 fusion") + # TODO: add this test back in when https://github.com/cancervariants/fusor/issues/183 is addressed # await check_validated_fusion_response( # async_client, ewsr1_fusion_fill_types, "EWSR1 fusion needing type inference" # ) From 09e10bdd827f6b086ed4fac4ecf60c2ba99a27a1 Mon Sep 17 00:00:00 2001 From: Kori Kuzma Date: Fri, 23 Aug 2024 08:58:31 -0400 Subject: [PATCH 11/17] update reqs --- requirements.txt | 121 +++++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 72 deletions(-) diff --git a/requirements.txt b/requirements.txt index 152f56e3..4fcd91eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,89 +1,66 @@ -aiofiles==23.1.0 -anyio==3.7.1 -appdirs==1.4.4 -appnope==0.1.3 -asttokens==2.2.1 -asyncpg==0.28.0 -attrs==23.1.0 -backcall==0.2.0 -beautifulsoup4==4.12.2 -biocommons.seqrepo==0.6.5 +agct==0.1.0.dev2 +aiofiles==24.1.0 +annotated-types==0.7.0 +anyio==4.4.0 +asttokens==2.4.1 +async-timeout==4.0.3 +asyncpg==0.29.0 +attrs==24.2.0 +biocommons.seqrepo==0.6.9 bioutils==0.5.8.post1 -boto3==1.28.11 -botocore==1.31.11 -bs4==0.0.1 +boto3==1.35.4 +botocore==1.35.4 canonicaljson==2.0.0 -certifi==2023.7.22 -charset-normalizer==3.2.0 -click==8.1.6 +certifi==2024.7.4 +charset-normalizer==3.3.2 +click==8.1.7 coloredlogs==15.0.1 -configparser==6.0.0 -cool-seq-tool==0.5.1 -cssselect==1.2.0 -Cython==3.0.0 +configparser==7.1.0 +cool_seq_tool==0.7.0 decorator==5.1.1 -executing==1.2.0 -fake-useragent==1.1.3 -fastapi==0.100.0 +executing==2.0.1 +fastapi==0.112.1 fusor==0.4.1 ga4gh.vrs==2.0.0a10 gene-normalizer==0.4.0 h11==0.14.0 hgvs==1.5.4 humanfriendly==10.0 -idna==3.4 -importlib-metadata==6.8.0 -inflection==0.5.1 -ipython==8.14.0 -jedi==0.18.2 -Jinja2==3.1.2 +idna==3.7 +importlib_metadata==8.4.0 +ipython==8.26.0 +jedi==0.19.1 +Jinja2==3.1.4 jmespath==1.0.1 -jsonschema==3.2.0 -lxml==4.9.3 -Markdown==3.4.4 -MarkupSafe==2.1.3 -matplotlib-inline==0.1.6 -numpy==1.25.1 -pandas==2.0.3 -parse==1.19.1 +MarkupSafe==2.1.5 +matplotlib-inline==0.1.7 Parsley==1.3 -parso==0.8.3 -pexpect==4.8.0 -pickleshare==0.7.5 -prompt-toolkit==3.0.39 -psycopg2==2.9.6 +parso==0.8.4 +pexpect==4.9.0 +polars==1.5.0 +prompt_toolkit==3.0.47 +psycopg2==2.9.9 ptyprocess==0.7.0 -pure-eval==0.2.2 +pure_eval==0.2.3 pydantic==2.4.2 -pyee==8.2.2 -Pygments==2.15.1 -pyliftover==0.4 -pyppeteer==1.0.2 -pyquery==2.0.0 -pyrsistent==0.19.3 -pysam==0.21.0 -python-dateutil==2.8.2 -python-jsonschema-objects==0.4.2 -pytz==2023.3 -PyYAML==6.0.1 -requests==2.31.0 -requests-html==0.10.0 -s3transfer==0.6.1 +pydantic_core==2.10.1 +Pygments==2.18.0 +pysam==0.22.1 +python-dateutil==2.9.0.post0 +requests==2.32.3 +s3transfer==0.10.2 six==1.16.0 -sniffio==1.3.0 -soupsieve==2.4.1 -sqlparse==0.4.4 -stack-data==0.6.2 -starlette==0.27.0 +sniffio==1.3.1 +sqlparse==0.5.1 +stack-data==0.6.3 +starlette==0.38.2 tabulate==0.9.0 -tqdm==4.65.0 -traitlets==5.9.0 -typing_extensions==4.7.1 -tzdata==2023.3 -urllib3==1.26.16 -uvicorn==0.23.1 -w3lib==2.1.1 -wcwidth==0.2.6 -websockets==10.4 +tqdm==4.66.5 +traitlets==5.14.3 +typing_extensions==4.12.2 +urllib3==1.26.19 +uvicorn==0.30.6 +wags_tails==0.1.4 +wcwidth==0.2.13 yoyo-migrations==8.2.0 -zipp==3.16.2 +zipp==3.20.0 From 7f5675233266aa534d4dcd87b27b7c51f040f44e Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Fri, 23 Aug 2024 12:16:04 -0400 Subject: [PATCH 12/17] fix: bug where chromosome field was not editable --- .../TxSegmentElementInput.tsx | 53 +++++++++++-------- .../GetCoordinates/GetCoordinates.tsx | 23 ++++++-- .../ChromosomeField/ChromosomeField.tsx | 7 ++- client/src/services/main.tsx | 7 +++ 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index 72691a95..e98dfe92 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -10,12 +10,19 @@ import { TranscriptSegmentElement, TxSegmentElementResponse, } from "../../../../../services/ResponseModels"; -import React, { useEffect, useState, KeyboardEvent, useContext } from "react"; +import React, { + useEffect, + useState, + KeyboardEvent, + useContext, + ChangeEvent, +} from "react"; import { getTxSegmentElementECT, getTxSegmentElementGCG, getTxSegmentElementGCT, getTxSegmentNomenclature, + TxElementInputType, } from "../../../../../services/main"; import { GeneAutocomplete } from "../../../../main/shared/GeneAutocomplete/GeneAutocomplete"; import { StructuralElementInputProps } from "../StructuralElementInputProps"; @@ -30,13 +37,6 @@ interface TxSegmentElementInputProps extends StructuralElementInputProps { element: ClientTranscriptSegmentElement; } -export enum InputType { - default = "default", - gcg = "genomic_coords_gene", - gct = "genomic_coords_tx", - ect = "exon_coords_tx", -} - const TxSegmentCompInput: React.FC = ({ element, index, @@ -46,8 +46,8 @@ const TxSegmentCompInput: React.FC = ({ }) => { const { fusion } = useContext(FusionContext); - const [txInputType, setTxInputType] = useState( - (element.inputType as InputType) || InputType.default + const [txInputType, setTxInputType] = useState( + (element.inputType as TxElementInputType) || TxElementInputType.default ); // "Text" variables refer to helper or warning text to set under input fields @@ -104,15 +104,15 @@ const TxSegmentCompInput: React.FC = ({ // programming horror const inputComplete = - (txInputType === InputType.gcg && + (txInputType === TxElementInputType.gcg && txGene !== "" && txChrom !== "" && (txStartingGenomic !== "" || txEndingGenomic !== "")) || - (txInputType === InputType.gct && + (txInputType === TxElementInputType.gct && txAc !== "" && txChrom !== "" && (txStartingGenomic !== "" || txEndingGenomic !== "")) || - (txInputType === InputType.ect && + (txInputType === TxElementInputType.ect && txAc !== "" && (startingExon !== "" || endingExon !== "")); @@ -233,7 +233,7 @@ const TxSegmentCompInput: React.FC = ({ setPendingResponse(true); // fire constructor request switch (txInputType) { - case InputType.gcg: + case TxElementInputType.gcg: clearGenomicCoordWarnings(); getTxSegmentElementGCG( txGene, @@ -261,7 +261,7 @@ const TxSegmentCompInput: React.FC = ({ } }); break; - case InputType.gct: + case TxElementInputType.gct: clearGenomicCoordWarnings(); getTxSegmentElementGCT( txAc, @@ -289,7 +289,7 @@ const TxSegmentCompInput: React.FC = ({ } }); break; - case InputType.ect: + case TxElementInputType.ect: getTxSegmentElementECT( txAc, startingExon as string, @@ -435,10 +435,19 @@ const TxSegmentCompInput: React.FC = ({
); + const handleChromosomeChange = (e: ChangeEvent) => { + setTxChrom(e.target.value); + }; + const genomicCoordinateInfo = ( <> - + @@ -449,7 +458,7 @@ const TxSegmentCompInput: React.FC = ({ const renderTxOptions = () => { switch (txInputType) { - case InputType.gcg: + case TxElementInputType.gcg: return ( @@ -466,14 +475,14 @@ const TxSegmentCompInput: React.FC = ({ {genomicCoordinateInfo} ); - case InputType.gct: + case TxElementInputType.gct: return ( {txInputField} {genomicCoordinateInfo} ); - case InputType.ect: + case TxElementInputType.ect: return ( {txInputField} @@ -610,7 +619,7 @@ const TxSegmentCompInput: React.FC = ({ * Wrapper around input type selection to ensure unused inputs/warnings get cleared * @param selection selection from input type dropdown menu */ - const selectInputType = (selection: InputType) => { + const selectInputType = (selection: TxElementInputType) => { if (txInputType !== "default") { if (selection === "exon_coords_tx") { clearGenomicCoordWarnings(); @@ -643,7 +652,7 @@ const TxSegmentCompInput: React.FC = ({ diff --git a/client/src/components/main/shared/ChromosomeField/ChromosomeField.tsx b/client/src/components/main/shared/ChromosomeField/ChromosomeField.tsx index 5776aef5..a35b28a4 100644 --- a/client/src/components/main/shared/ChromosomeField/ChromosomeField.tsx +++ b/client/src/components/main/shared/ChromosomeField/ChromosomeField.tsx @@ -1,5 +1,5 @@ import { makeStyles, TextField, Typography } from "@material-ui/core"; -import React, { KeyboardEventHandler } from "react"; +import React, { ChangeEvent } from "react"; import HelpTooltip from "../HelpTooltip/HelpTooltip"; interface Props { @@ -7,14 +7,13 @@ interface Props { errorText: string; width?: number | undefined; editable?: boolean; - onChange?: (event: any) => void; + onChange?: (event: ChangeEvent) => void; } const ChromosomeField: React.FC = ({ fieldValue, errorText, width, - editable, onChange, }) => { const useStyles = makeStyles(() => ({ @@ -45,7 +44,6 @@ const ChromosomeField: React.FC = ({ error={errorText != ""} label="Chromosome" helperText={errorText != "" ? errorText : null} - contentEditable={editable} onChange={onChange} className={classes.textField} /> From c3d093c44d45a7593c4ffe7ffc8f13030cd7b0c9 Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Fri, 23 Aug 2024 12:45:43 -0400 Subject: [PATCH 14/17] changing validation for tx segment elemetn since they only require either a start or end now, regardless of position in the structure --- .../TxSegmentElementInput/TxSegmentElementInput.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index cf33662f..720aaa42 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -89,18 +89,8 @@ const TxSegmentCompInput: React.FC = ({ const [pendingResponse, setPendingResponse] = useState(false); - /* - Depending on this element's location in the structure array, the user - needs to provide some kind of coordinate input for either one or both ends - of the element. This can change as the user drags the element around the structure - array, or adds other elements to the array. - */ const hasRequiredEnds = - index !== 0 && index < fusion.length - ? (txStartingGenomic && txEndingGenomic) || (startingExon && endingExon) - : index === 0 - ? txEndingGenomic || endingExon - : txStartingGenomic || startingExon; + txEndingGenomic || endingExon || txStartingGenomic || startingExon; // programming horror const inputComplete = From b611f843f6c47afac12f429d76ed623ab912e9ae Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Mon, 26 Aug 2024 14:01:18 -0400 Subject: [PATCH 15/17] refactor: remove ability to change strand, since it's auto populated --- .../Input/TxSegmentElementInput/TxSegmentElementInput.tsx | 2 +- .../components/main/shared/StrandSwitch/StrandSwitch.tsx | 6 +----- requirements.txt | 2 +- server/pyproject.toml | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index 720aaa42..7386f405 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -438,7 +438,7 @@ const TxSegmentCompInput: React.FC = ({ onChange={handleChromosomeChange} /> - + {renderTxGenomicCoords()} diff --git a/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx b/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx index 2f936ea0..d32c40c4 100644 --- a/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx +++ b/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx @@ -23,16 +23,12 @@ export default function StrandSwitch( props: StrandSwitchProps ): React.ReactElement { const classes = useStyles(); - const { setStrand, selectedStrand, switchClasses } = props; - const handleSwitchChange = (e: React.ChangeEvent) => { - setStrand(e.target.checked ? "-" : "+"); - }; + const { selectedStrand, switchClasses } = props; return ( } diff --git a/requirements.txt b/requirements.txt index 4fcd91eb..0c7c0fdf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ cool_seq_tool==0.7.0 decorator==5.1.1 executing==2.0.1 fastapi==0.112.1 -fusor==0.4.1 +fusor==0.4.2 ga4gh.vrs==2.0.0a10 gene-normalizer==0.4.0 h11==0.14.0 diff --git a/server/pyproject.toml b/server/pyproject.toml index e0ba96b6..93ae38e1 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "click", "boto3", "botocore", - "fusor ~= 0.4.1", + "fusor ~= 0.4.2", "cool-seq-tool ~= 0.7.0", "pydantic == 2.4.2", "gene-normalizer ~= 0.4.0", From e5545ebf0cfbc1493ac9a07149a97404ae8a5a4b Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Tue, 27 Aug 2024 13:54:22 -0400 Subject: [PATCH 16/17] removing strand switch --- .../TxSegmentElementInput.tsx | 4 ---- .../Utilities/GetCoordinates/GetCoordinates.tsx | 15 --------------- 2 files changed, 19 deletions(-) diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index 7386f405..0b9aef51 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -28,7 +28,6 @@ import { GeneAutocomplete } from "../../../../main/shared/GeneAutocomplete/GeneA import { StructuralElementInputProps } from "../StructuralElementInputProps"; import StructuralElementInputAccordion from "../StructuralElementInputAccordion"; import { FusionContext } from "../../../../../global/contexts/FusionContext"; -import StrandSwitch from "../../../../main/shared/StrandSwitch/StrandSwitch"; import HelpTooltip from "../../../../main/shared/HelpTooltip/HelpTooltip"; import ChromosomeField from "../../../../main/shared/ChromosomeField/ChromosomeField"; import TranscriptField from "../../../../main/shared/TranscriptField/TranscriptField"; @@ -437,9 +436,6 @@ const TxSegmentCompInput: React.FC = ({ errorText={txChromText} onChange={handleChromosomeChange} /> - - - {renderTxGenomicCoords()} diff --git a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx index bb0b8db6..91f7f830 100644 --- a/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx +++ b/client/src/components/Utilities/GetCoordinates/GetCoordinates.tsx @@ -21,7 +21,6 @@ import { CoordsUtilsResponse, GenomicTxSegService, } from "../../../services/ResponseModels"; -import StrandSwitch from "../../main/shared/StrandSwitch/StrandSwitch"; import TabHeader from "../../main/shared/TabHeader/TabHeader"; import TabPaper from "../../main/shared/TabPaper/TabPaper"; import { HelpPopover } from "../../main/shared/HelpPopover/HelpPopover"; @@ -64,9 +63,6 @@ const GetCoordinates: React.FC = () => { flexDirection: "row", alignItems: "center", }, - strandSwitchLabel: { - marginLeft: "0 !important", - }, coordsCard: { margin: "10px", }, @@ -278,17 +274,6 @@ const GetCoordinates: React.FC = () => { errorText={chromosomeText} onChange={handleChromosomeChange} /> - - - - - ); From 09183e1aff4bd075fb0272a2c73ac321f41b49fc Mon Sep 17 00:00:00 2001 From: Katie Stahl Date: Tue, 27 Aug 2024 13:55:36 -0400 Subject: [PATCH 17/17] fix: ability to change strand for templated sequence --- .../components/main/shared/StrandSwitch/StrandSwitch.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx b/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx index d32c40c4..2f936ea0 100644 --- a/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx +++ b/client/src/components/main/shared/StrandSwitch/StrandSwitch.tsx @@ -23,12 +23,16 @@ export default function StrandSwitch( props: StrandSwitchProps ): React.ReactElement { const classes = useStyles(); - const { selectedStrand, switchClasses } = props; + const { setStrand, selectedStrand, switchClasses } = props; + const handleSwitchChange = (e: React.ChangeEvent) => { + setStrand(e.target.checked ? "-" : "+"); + }; return ( }