From 16bd37c14f748f0b707226a94e080f4aef419d77 Mon Sep 17 00:00:00 2001 From: Elarwei Date: Wed, 24 Jun 2026 21:52:42 +0800 Subject: [PATCH 1/4] fix(seq): return spliced cDNA for transcripts instead of genomic (#187) Ensembl's sequence/id endpoint returns the genomic span by default, which for a transcript ID includes introns rather than the spliced transcript sequence. gget seq therefore returned the wrong sequence for any ENST/transcript query. Request type=cdna for transcript IDs across all three code paths: - non-isoform bulk request: classify IDs via lookup/id and split into a cDNA batch (transcripts) and a genomic batch (genes/other), falling back to the previous genomic-only behaviour if the lookup fails - isoform gene branch: fetch each transcript as cDNA - isoform non-gene branch: cDNA for transcripts, genomic otherwise The cDNA response carries no "desc" field, so coerce a missing desc to an empty string when building the FASTA header. Regenerate the test7/ test8 fixtures to the spliced-transcript output. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/src/en/updates.md | 1 + gget/gget_seq.py | 51 +++++++++++++++++++++++++++++------- tests/fixtures/test_seq.json | 36 ++++++++++++------------- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/docs/src/en/updates.md b/docs/src/en/updates.md index 89be22281..b72416792 100644 --- a/docs/src/en/updates.md +++ b/docs/src/en/updates.md @@ -37,6 +37,7 @@ - Deprecations: - [`gget alphafold`](alphafold.md) and [`gget gpt`](gpt.md) are no longer actively maintained. Both now emit a warning when invoked, and a deprecation notice was added to the top of each module's docs. - Bug fixes: + - [`gget seq`](seq.md): Transcript/ENST IDs now return the spliced cDNA sequence instead of the genomic span (which included introns). gget requests `type=cdna` from the Ensembl `sequence/id` endpoint for transcript IDs across all code paths (bulk, isoform, and single-ID); gene IDs are unaffected and still return the genomic sequence. Resolves [issue 187](https://github.com/scverse/gget/issues/187). - [`gget search`](search.md): Missing values are now consistently returned as `None` instead of `NaN`, both in scalar cells and inside synonym lists (`[None]` rather than `[nan]` for genes with no synonyms). The previous output was an artifact of `SQL LEFT JOIN`s surfacing as pandas `NaN`s; the JSON output was already `null` either way, so this only affects the DataFrame return path. - [`gget mutate`](mutate.md): Fixed `pyarrow.lib.ArrowNotImplementedError: Function 'binary_join_element_wise' has no kernel matching input types (large_string, null, large_string)` when the input contained no substitutions (only deletions/insertions/delins/duplications/inversions). The substitution-only sequence-build branches now short-circuit on an empty selection instead of triggering an arrow-string kernel that older `pyarrow` versions don't implement. - [`gget muscle`](muscle.md) and [`gget diamond`](diamond.md): When the bundled MUSCLE / DIAMOND binary fails because a system library is missing (most commonly `libgomp` / `libomp` on macOS without Homebrew gcc/libomp installed), gget now raises a clear `RuntimeError` naming the missing library and the exact `brew install` / `apt install` command to fix it — instead of the raw `dyld` / `ld.so` error spilling onto stderr. diff --git a/gget/gget_seq.py b/gget/gget_seq.py index e58d026ca..7adea36b0 100644 --- a/gget/gget_seq.py +++ b/gget/gget_seq.py @@ -90,11 +90,34 @@ def seq( if not isoforms: actual_results_dict = {} - endpoint = "sequence/id/" - query = {"ids": ens_ids_clean} + # Ensembl's sequence/id endpoint returns the *genomic* sequence by + # default. For a transcript, that genomic span includes the introns + # rather than the spliced transcript, so we must request type=cdna + # for transcripts (issue #187). Genes keep the default genomic + # sequence. Classify the IDs with a single bulk lookup and split the + # request into a cDNA batch (transcripts) and a genomic batch (rest). + try: + id_types = post_query(server, "lookup/id", {"ids": ens_ids_clean}) + except RuntimeError: + # If the lookup fails, fall back to the previous behaviour + # (single genomic request) rather than erroring out. + id_types = {} + + transcript_ids = [] + other_ids = [] + for ensembl_ID in ens_ids_clean: + lookup_entry = id_types.get(ensembl_ID) if isinstance(id_types, dict) else None + if isinstance(lookup_entry, dict) and lookup_entry.get("object_type") == "Transcript": + transcript_ids.append(ensembl_ID) + else: + other_ids.append(ensembl_ID) + + results_list = [] + if transcript_ids: + results_list += post_query(server, "sequence/id?type=cdna", {"ids": transcript_ids}) + if other_ids: + results_list += post_query(server, "sequence/id", {"ids": other_ids}) - # noinspection PyTypeChecker - results_list = post_query(server, endpoint, query) results_dict = {v["query"]: v for v in results_list if v is not None} for ensembl_ID, df_temp in results_dict.items(): @@ -149,8 +172,9 @@ def seq( # Try if query is valid try: - # Define the REST query - query = "sequence/id/" + transcipt_id + "?" + # Define the REST query (request the spliced cDNA, not + # the genomic span, for transcripts -- issue #187) + query = "sequence/id/" + transcipt_id + "?type=cdna" # Submit query df_temp = rest_query(server, query, content_type) @@ -172,8 +196,11 @@ def seq( else: # Try if query is valid try: - # Define the REST query - query = "sequence/id/" + ensembl_ID + "?" + # Define the REST query. Request the spliced cDNA for + # transcripts (issue #187); any other object type keeps + # the default genomic sequence. + seq_type = "cdna" if ens_ID_type == "Transcript" else "genomic" + query = "sequence/id/" + ensembl_ID + "?type=" + seq_type # Submit query df_temp = rest_query(server, query, content_type) @@ -201,11 +228,15 @@ def seq( # Build FASTA file for ens_ID in master_dict: for key in master_dict[ens_ID].keys(): + # The cDNA (type=cdna) response has no "desc" field (None); coerce + # to an empty string so the FASTA header still builds. if key == "seq": - fasta.append(">" + ens_ID + " " + master_dict[ens_ID][key]["desc"]) + desc = master_dict[ens_ID][key].get("desc") or "" + fasta.append((">" + ens_ID + " " + desc).rstrip()) fasta.append(master_dict[ens_ID][key]["seq"]) else: - fasta.append(">" + master_dict[ens_ID][key]["id"] + " " + master_dict[ens_ID][key]["desc"]) + desc = master_dict[ens_ID][key].get("desc") or "" + fasta.append((">" + master_dict[ens_ID][key]["id"] + " " + desc).rstrip()) fasta.append(master_dict[ens_ID][key]["seq"]) ## Fetch amino acid sequences from UniProt diff --git a/tests/fixtures/test_seq.json b/tests/fixtures/test_seq.json index 5a3eddafa..66e71e264 100644 --- a/tests/fixtures/test_seq.json +++ b/tests/fixtures/test_seq.json @@ -78,22 +78,22 @@ "isoforms": true }, "expected_result": [ - ">ENST00000392653 chromosome:GRCh38:1:153056120:153057512:-1", - "AAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATA", - ">ENST00001096805 chromosome:GRCh38:1:153056118:153065583:-1", - "CTGTGCTGACTTCAAGTCCTGAATACACGTGTTAAATTTCAGCCACTATGATCTGTCTAATACTGTCAGTGGGGTGTTAAAGTCTCCCACTATTACTGTATGGGAGTCTAATTCTCTTTGAAGGGCACTGAGAAATTGCTTCATGAATGTGAGTGCTCCTGTGTTGGGTGCATTTATATTTAAGACAGTTGGGTATTCTTGTTGAATCCTTTACCACTGTGTAATGCTTTTTTTGGTCTTTATTGATTTTTGTTGGTTTAAAGTCTCTTTGTCTGAAATTGGGATTGCAATCCCTGCTTTTTTCTGTTTTGTGGTTGCTTCACTCTCAGTGCCTCCCCTCTGAAAATCTGTTAAAAGTGGGCCAGTCGTCTCTGTCCCTCAGTGGCAGCTATTCTACCTGGCTGCATCTAGTTGGCCATCTTGCCCAGAGCCACAGGAATTATCTGGTATGTTAAATGTTTTTGAGCATTTTTTGCATCAATATTCATGAGGAATATTGGTGTGTAGTTTTCATTCCTTGCAGTGTCTTTGTCTGGATTTTCTATCAGGGTAATCCTGGCTTCATGGAATAAGGCAGGAAGTATTCTCTATTTTAAGTTTTCTTTTTTGATAGAGTTTGAGAAGGATTGGTATATACTTCTCCAATAAATCCTTCTGGGTCAACACTTTTCTTTCTTGTGAGATTTTAGATTAATAATTCAATCTCCTTACTTTTTATACATCTCTTCAAATTTTCTATTTCTTTATGATTTGGTTTGGTAGACAGTATATTTCTAAGAATTTGTTCATTTCAACTGGGTTATCTGATAAGCCGACATAGAATTGTTTCGATGTTTTCCCTTAAAATTCTTTTCATTTCTGTAAAATCAGTAGTAACTTCCCCACTTTCTTTTAAGATTTTAGCTATTTGAGTGTTACATCATTTTTCTCTTCTGTGGTTAATCTAACAATTTGTCAGTTTTGTTGCCTTTTCAATGAAATAAAAGTTGGTTTTACTGATTTTCTCTATTGTTTTCTTGTCTTTTATTTTATTTATCTCCATTCTAGTCTCTCATATTTACTTTTTTTGGGTTTAGTTTACTTTTCTTTTTGTATTTCCCTAAGGTGTAACATGAAGTTATTGATCTGAGAATTTTTTAAATTAAAAATATATGTGGTTATGGCTGTAAATTTCCCTGTTAGCACTGCTTTTTCTGCAATCCTGAAGTTTTGGTATGATGTGTTTTTGTTGTCAGTAGTCTCAAGCTATTTCTAATTTTCCCGTGATTTCTTATTTGACCTGTTGGTTGTTTAAGAGTGTTTTTTTGTTTGTTTGTTTCCACAAATGTGTGAATTTTCCAGTTTTAAGTTGGTTATAGATTTTTAGTCTTATTCCAAAGTGATTGGAAAAGTACTTTGTATGATTTTAGTCTTTTAAAATATATTAACTTATTTTCTAGCCTAATATGTGGTCTATCCTGGAGGGTGTTCCATGTTCTCCTGAGAAAATTGTAGGGTATATCCTGCTGTTGGTGGGTACAGGGTTGTGTATTTTTCTGTTTGGACTAATTGGTTTATATTTTTAAGTCATCTATTTTCTTTTTGAACTTCTATTATTCTAGCCATTTTTGAAAGTGAAGTATTTAAGTTTTCAATATTTATTATAGAACTATCAATTTCTTTTAATTTCTCTCAATGTATCTTCATATGTTTTAGAGTTCTGATGTTAGGAAATGTATGTTTATAACTTCTATGTTTTCTGAGTGAATAAATCTCTTTATCAATATATATGTCCTTTATAGTCTCATGTAACAGTACTCAACTTAATTGTGTCTCATGTTATTGTAACCACCTCTGGTCTCTTGTGGCTACTATTTACATAAAATATCTTTTTCCATACATTACTTTCAACCTCTTTGTGTCTTTAGTTGTAAAGTTAGTCTCTTGTAAACAGCAAATAGTTGAATCAATTTTTTAATTTAAGATCCATGCTTTCAATTTCTGTTGCTGGGGAAAGTTTAATTCACTTACAGTTAAAATAATAACTCATGAGGTAGGTCCTCTTTTTGCATTTACTCTTTTCTCTATGTTATCTTTCATTAGTGCCTGATTTGTGTTTAGTTTTTTTTAATAGTAAAACTTTTTAAATTGTCTTTTTTCTGTCGTGTGTATTCTAAAATATTTATTTTGTGGTTACAGTGAAGACTGTATATAATATCTTAAAGTTATACTAATCTAATTAGCATTAACACCAACAATTCCAACTGCATAGAAAAATTAACTCATACAACCACCCCATCTTCTTTTTATGTTGAGTTCACAAATTACATCTTTATACACTGTATGTTCACTAACATATATTTGTAATTGTATTGTATACATTTGCATTTTAAATCTTGTAGAAAATAAAAAGTGGAGTTACAAGCTAAAATTACAATAATGCTGGCTTTTATGTACCTGTGCATGTCTATCAGATACCTTTATATCTTCATACAGTTTCTCTCCAGCATCCTTTTTTTTTGTGAGACAGTGTCTCTCTCTGTTGCCCAGGCTGGAGTGCAGTGGTGCGATCTCGGCTCACTGCAACCTCCACCTCCTGGGTTCAAGCAATTCTCCTGCCTCAGCCTCCTAAGTAGCTGGGATTATAGGCACACACCACCACACCCAGCTAATTTTTGTATTTTTAGTACAGATGGGGTTTCACCATGTTGGTCAGGCTGCTCTCGAACTCCTGACCTTGTGATCCGCCCACCTCGACCTCTCAACGTGCTGGGATTACAGGTGTGAGCCACCGCGCCTGGCCCAGCATCCTTTTATTTCAACCTGAGAGGCTCTCTGTATCATTTCTCATACAGAAAATCTAGGAGCAATGAACTGCCTCAAGTTTTGATTTCTGGAAATGTCATAAGTTTGCCCTCACTTTTAAGGAAATTTTGCCGGCTGTACAATTTTAGGTTGAAAGTGGTTTCTTTCTAGAATTCTACAGCGTTGAAAGAAATCACTATCAACATAGAATTCCACTGCCTTGGAGATCAGGAGGCAGTAGGATGATATATTGAAAATTACTTATTCAGAAAACTACTTCTGATAAGAATTTGGTCAACTACTTATTAAGGATCCCTTAGATATGATGATTTACTTCCTTCTTCCTGCTTTCAAGATTCTCTCTTTTGATAATTTAATTATAATGTGTCTCAGTGTGGGTGTCATTGAATTCATTGAACTTGGAGTTTGTTGTGCTTTTTGGATGTGTAATTTTGCATTTTACAGAAATCATATAAATGGAACCATTTTAGAAACAGTGTGTAGCCTTTGAGACTGACTTTTTTTAAACTTACCAGTTTGCATTTAAAATTCATTCATATCTTTGTATTTCTTGATAGATCATTCCATGTTATCACTGCATAGTGTTCCACTGCATGGGTATAATCCACCGTGGTTTATCGATTCATTTATTGAAGGGCATCTTGGTAGATCACGCTTCTTGGAATTTATGAATAAAGCTGCTGCAATCATTTGAATGCAGGTTATTTTTTGTTGAAATATTTTGAAATGTACTAGATCAAAATTTGCTGGATCATATTGTAAAATTGTGTTTATCTCTGTAAGACTGTTAGTTTTGATTGTTCTAATAATGTTTATGTTTTATTTCATATATTTCTAACTTACAGTAGAATTTCAGCTCTCCCCATATTAGATTTCAAACAGTTTTTTTCCTCTTCAAAATTTTTCACAATTTTGTTCGTGTTTCCTTATTTTCCTTTTTGACTTTTTTTGGAAGGAAACCACAGCCTATGCACATTCACTATCTTGAAAAGATTCTTATGAGGAGAAGTGTCTGATTCATTCTATCATTTACCATATGTCCTTCTTAATCTCATTAACATTAAGCAACAGGAGTACTTTACATTACTAATAGCTCTTGAAATTATGCTCTTAAATATTCTGATCTAACATATAGAGAAAATAACAGTAGAATCTATAAGGTCTATTCACTTTGGGAAGGTTAGTGCTAATGAGCTATTCAGTTTCTTATAAGGATTTAGCCTAAAATTTAGGTAATTTGCCACCAGAAGAAATGTGATATTTGAATGAGTGTTTTTTATTAATGTCCTAAACAGCTAACCACATAACAGTAAACTAAATTGGAGGTAACATTATATATATTTTCACATGGAATGCTAAATATCTATGTATGTTAATATTTTACAAATGAACACATCCACATATTGCTATTTACTGTATTTAGATTTATTTTCTTGTATTAACTGAATTCAGAGGAAAGTCTTAGAGAGTACGAACAACTAGGAACTGATCTAAATTTCTGCTTAGATTAACTCTCATTTTTATCACATAAGAATAAACGTCAGGATCAGCCCATCTTATTATTTCTGCCCACTTCATTCAAATAATATATTTGCATTTGCTTTGTCCTAAAAACTTCTGGCACACAGTTAAAATAAGGATAATATAAAAGATCTTAAAGAGAAAGCAAGTATCTTTCTTAACCATAAACAACTTGAAATTGATATTTTGTCTCTATTTCTTTCATTAACAATGTGTTACTTTAGCATTTTGAGCACTATCTGTAGCCTGTGCTAAGTATTTATATGCAGTCTCTGATTTAATTGTTTTCTCATGACAATTTAGTGGTAGTTACTATTATTATCACCACGTTCTACTATCCTTACTACCTGTCCTGCTAATCATCCATCTCTTCCAATTTCATCATATTATGGCCAATTTATGCTTTCTATCCACCTGGCTCTTGGATAGTAGACAAACTCATTCCTGATTTTGTTATCCTAGAATGATCTCCCAATTTTGGTGAATGATTTCACAGACACATACAGCTATTGGGTGTCTGTGGTTACTACGATTCTCACATTTGGAGAGAACACCATTTGTAAACATCTGTGTGTATATGTCAATACTCTGAGGAAGGGGGATTATTATTGGAGTTTTCTTCGAGAGAGATTTTAGAAGGGATGTGATCAAATGTAGAGCTATTACAATAAAACTACTGCTACTTACATCCTGCCCCACCTTTAGTGTCTAGCCAATAATGCTTAAAAAAAACCCAAAAAACCCACTATCTCACTAACTGAGCAATGGACAGGCTTGTCTCTTGTTAGCTTTTCAAAGTAGAATTTTAAGATTCCTTACTCAATAATAGGTAACATTTGAAGCATACTTTGAAAAGTTAAATAAGAACATAAACATCATCTGTAATTATACCAGCCATATATAATCACATTTAGTATGTTGTTTTATGTTTCCCATCTTTTAATGAAAATGTTATCATGCTTTACATACATTTTTTAGTATAATTTGAATATTTTAAATAATATTACATAATCTCCCAAAACATTCTTCTTAATTACTTTCAGAATTCTACCATATGTTTATCTAATTCATCGAATTATGGAAGGACAATGGAGACTAAGCCTGCTATTCAGAAATAAAAGCAGAAGGCAGATATGCATGGGGACTGGTAGTTACCATTTCTCTTAACATATCAAGAATATTTTGCAACAATTCCTGTTTCTTTGTTTTTTCATATTTTATTTTAAATCTTCACTTGCCAGCACTATTTTGTATAGCAGAATGTATCATAGTAAAATGTGAGATAAAATGTTGAATCAAATATTACACCAAATAAAAGTTTTTGTTCTTTCCTGTCATTTTTATGAACTAATAATTCGTACTTAATGATCCCTTACAAAATTAGGAAGTAGAAATAATAGGAATGAATCTAAGGCTATCAGACTGTTAAGAAACATAAAGCTAAGCTCTTTAGACATGAAGATAGATGATAGATAAATAAAGACCCATGGAGTGCGTGTGTATGTGTGTGTGTGTGTGCATGTGTGAAGTATGCCTCGCTCCATGTATCAAGGCCTGGATGTCCTAACTTGGGGAAGCTGTGACTGTTAGCTGCCCCTCTTCATATTGTGGCCGTTCCTCATGTGGCTGCTCTGTGTGGAACTCTGAGTTTCAAGTTCACCACCTCAACTTGTAAAGTGAGCCTGTCTGAGATGCGGGGGGCACTAGGGCTGCTGCCATTCTAGTGCCTGCACTGGTGTGATAAGCCTCCTGTTGGAATGCGGTGTTCTCAGAAGGGGTGTCGCAGGGTGTGACTCAGACTGTGTTATCTCACACAGTGATCTCATCTGGCAGCAAATTCTTCAATTTTGCATGGCACAAATCAGATATTTCTTTAAGGATTTGTGTTTTAGATGTGATGTGAGGCTGTTGGGGAGTAGTAGGGGACCTATTGAGTAAAGGCCCTTTACTTTGCCCAGTGAAGTGCTTGACATGTGTAATAGTCTATAGGAAACACTTGGTGAGAACACCATTTGTAAACACCTGGCCTCAAGGTTCTGATATGTTGGCTCTATTTCTGTAGTGTCCTGGCCAGTGATGATCTTAGCCAAAAGCCCTTCCTTACTGACAGGAGAAATAGCAGTTCTGGGTACCTAACCTGCTTAACTGAGGGATGTGATGCTGGGTTCATTCAACACATGTTCTTCCTGGAGCATAGCTGGTGACTGCTCTGATGATTTTGTCTTTCCTCTTCCTCATTCCCCTTTCTTCTTATCTACTTACAAAACCACATTCTTGGAAAGCTTCCTGATTAATGGTCCAGATAAGGAAGCTCTAGCAATATCACTTTAAATGCTTAATATACAATATTTAGAAAACCTTATGATTGTAAAAGAGCTTAAAAAAGATGTGAAAGAACAATCACTAAATGCATTGACAACATATGTGTTAAGTGAACAATATGTACCAAAATGGACAGATGAGAGGTGTACATTGGGGTGTGAGTTGATAATCCAGCAGACTGTGGGACTAGAGGGTCTACGGAAAAAACAAAGGAAGAACATACAAACAAATTTTAAAACACTGTCTTTCAAACACCTAAAACCTGTTTGGAAATAGAGAGCAAGAATACATATTGGATTACACTTAGCTTTTATTTTCCTCTAGATTTCAGACTTTAAGTGCTCTGAACTTCTGCACTCTGCAAACCTACTTCTAATTATTTACATATGATAACATGAGTCTATGCAGCTTGTTCTCTATAGGATATTCACAGGACACTACAGAATGTTTTGGGAGATTATGTAATATTTAAAATATTCAAATTATACTAAAAATGTATGTAAAATGTATTGAACATAGGCAAGTTTCAATACATAGATTTTGAGTGAATGCTTGCAACTTTGGTTCCATTCTCTCTACTTCCTTAAGGTGGTGTCCAAGAGTACATTTTTATAAATAAAAAGTTATAGTACACATCCCTAAGGGCAGCAAGTAGAAAACGTGCTAGGGAGACTCGATCTCACTTTGGAATCTATCCTGGGAGACAAATGCCTCTACAAATGGATTAGAGAAGACAGTTTTAAAGAGGAAGATAATACAGGTAAAATCTGGGGTTTTATGAGAGAAAGAAAGAGGTAGAAGAAAAAATTTCAAGCTCGAACAGGGTCATCAGGTGGCACAATGCGGTCAATGCCTGCAAACTCAGGGGTAAGTATTATTCTCCCTGTTTACAGTTCCGTGGAGGAGAAGTGACTTGCCTGTGGTCATACAACAGAGCAAAGAAAAGGCTTGAGCTAGAACTCAGGCCTTTGTTAGGTCTCCCCTTCCTCCTAGCACATTGGCAAATTGCATGAGGAAAGTAGAGGTACAGTTGAGTTCATGTACAACAATAAGGCATTCAGGTAAAGTGAATGAGGGCAGAAGTTTTATGATTTAGGGAAGGTGTAAGACAGGAAAATATCTTTGTTCCCAATTAAGAAAGAGATCCCTTGACCATCAGTTAGAGATTCCCCCAAGTCCCTCTTTGCCATAAGTCACTGAAACTGAGATCCAAGGCATGGCTTCTGTGAGTCAGGAGAGCTTAACCCAGAGGAGAGATTTCAGAACAGGATATTTCCTATTTTGAGTATCCTGCTCATGCCAGTCATGGATAAATTTGCATCTGGCTTAAGAAATTACTGGATCAGCATTGTTTTGGGTAGTTTCACTTCCTGCTGGGTGGGGTAGCAGGCTCTATAAAGAGATCCTCTGCTGCACGACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", - ">ENST00001096806 chromosome:GRCh38:1:153056118:153058304:-1", - "CACATCCCTAAGGGCAGCAAGTAGAAAACGTGCTAGGGAGACTCGATCTCACTTTGGAATCTATCCTGGGAGACAAATGCCTCTACAAATGGATTAGAGAAGACAGTTTTAAAGAGGAAGATAATACAGGTAAAATCTGGGGTTTTATGAGAGAAAGAAAGAGGTAGAAGAAAAAATTTCAAGCTCGAACAGGGTCATCAGGTGGCACAATGCGGTCAATGCCTGCAAACTCAGGGGTAAGTATTATTCTCCCTGTTTACAGTTCCGTGGAGGAGAAGTGACTTGCCTGTGGTCATACAACAGAGCAAAGAAAAGGCTTGAGCTAGAACTCAGGCCTTTGTTAGGTCTCCCCTTCCTCCTAGCACATTGGCAAATTGCATGAGGAAAGTAGAGGTACAGTTGAGTTCATGTACAACAATAAGGCATTCAGGTAAAGTGAATGAGGGCAGAAGTTTTATGATTTAGGGAAGGTGTAAGACAGGAAAATATCTTTGTTCCCAATTAAGAAAGAGATCCCTTGACCATCAGTTAGAGATTCCCCCAAGTCCCTCTTTGCCATAAGTCACTGAAACTGAGATCCAAGGCATGGCTTCTGTGAGTCAGGAGAGCTTAACCCAGAGGAGAGATTTCAGAACAGGATATTTCCTATTTTGAGTATCCTGCTCATGCCAGTCATGGATAAATTTGCATCTGGCTTAAGAAATTACTGGATCAGCATTGTTTTGGGTAGTTTCACTTCCTGCTGGGTGGGGTAGCAGGCTCTATAAAGAGATCCTCTGCTGCACGACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", - ">ENST00001096807 chromosome:GRCh38:1:153056118:153057519:-1", - "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", - ">ENST00001096808 chromosome:GRCh38:1:153056118:153057519:-1", - "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", - ">ENST00001096809 chromosome:GRCh38:1:153056122:153057519:-1", - "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATA", - ">ENST00001096810 chromosome:GRCh38:1:153056118:153057485:-1", - "GCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", - ">ENST00001144725 chromosome:GRCh38:1:153056118:153057519:-1", - "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA" + ">ENST00000392653", + "AAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATA", + ">ENST00001096805", + "CTGTGCTGACTTCAAGTCCTGAATACACGTGTTAAATTTCAGCCACTATGATCTGTCTAATACTGTCAGTGGGGTGTTAAAGTCTCCCACTATTACTGTATGGGAGTCTAATTCTCTTTGAAGGGCACTGAGAAATTGCTTCATGAATATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", + ">ENST00001096806", + "CACATCCCTAAGGGCAGCAAGTAGAAAACGTGCTAGGGAGACTCGATCTCACTTTGGAATCTATCCTGGGAGACAAATGCCTCTACAAATGGATTAGAGAAGACAGTTTTAAAGAGGAAGATAATACAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", + ">ENST00001096807", + "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", + ">ENST00001096808", + "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", + ">ENST00001096809", + "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATA", + ">ENST00001096810", + "GCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA", + ">ENST00001144725", + "GACTCTTAAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATATA" ] }, "test8": { @@ -103,8 +103,8 @@ "isoforms": true }, "expected_result": [ - ">ENST00000392653 chromosome:GRCh38:1:153056120:153057512:-1", - "AAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGGTGAGTCGGCTTCCTTGAGTTCCTCTGTTCTTTGTGCCCTGAAATGTTGAGTTTAATCTGAATATGGCAAGTTTGGTGGATCCAATCCTATGAAAATTGACTTGATGCTACTTAGTGGATGAAAATTTAAGATTAGAGCACAATTATATGCTATTTTAGCTTTCTTTTGTTATACAGGTAGGTATCCATATGGACAGAGAAGTTAAGGGGTAACCTTTGATATGAAGAAGAAAAAAGAACAAAGTATTTTTCTTTATTCTCTGTCTTTCTAGTGTCCTTTACAAAGGTTTGTGTCTTAGCAGGTGTGAAAGACTACAATTCTCCCTGAGCAGCCCTTTGCTCTATGCCCAAGTCAGCCCACTTGGACTTTATAACAGATAATGATGATAGGAATAGCATATTAGATTGCCCAGGGTGTCTGAACTTGTGACTGCCTTTCTTGAATTGGTTATTTTCAGGGAAATAAGATGCTTGATTCTTTATAACAGAGATAATTTATTTGGAAAAATTGTATGAGAAAACACAGGATTTCCTAGGGACAATGAAGCAATTTGTTAAAGTGGAAGGGAGAAACCAGAAAGTCTTGAAAAGGTAATTAAGAATTTAAATAATTTCTTGGAGATTGGAGAAATAATATGCCATGGTATTACACAAGCTTTGGCTTCTCTCTCTGGAGGATTCCCTTCCCACGAACACTGTTGTATCATTTCTTTCAGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATA" + ">ENST00000392653", + "AAACCCCTGGTACCTGAGCACTGATCTGCCTTGGAGAACCTGATCCTGAGACTCCAGCAGGATGTCTTATCAACAGCAGCAGTGCAAGCAGCCCTGCCAGCCACCTCCTGTGTGCCCCACGCCAAAGTGCCCAGAGCCATGTCCACCCCCGAAGTGCCCTGAGCCCTGCCCACCACCAAAGTGTCCACAGCCCTGCCCACCTCAGCAGTGCCAGCAGAAATATCCTCCTGTGACACCTTCCCCACCCTGCCAGTCAAAGTATCCACCGAAGAGCAAGTAACAGCTTCAGAATTCATCAGGACCAAGAAAGGATAAGGATATTTGGCTCACCTCGTTCCACAGCTCCACCTTCATCTTCTCATCAAAGCCTACCATGGATACACAGGGAGCTTCTTTCTCCTTAGCCAGTAATCTGCCCATGATGATCCCTGACAGCAAAAAGTTTCTTTTCTGAGGCTGCCATACTGCCACTGTCCAGGTGGAGACTGAGCAAAGGAAGTCCTGGGCTGTGCCAGCTCCCAGAGCTTCGGAAGAAAGAGCAGCAGCTCTCTCCCTGGGAACCATCAGAGAATTCTGTTGATGTGTTCTGTGTCTGTCTGTCACCTGGTCACGAGCTTCTACCACCTTTGCAATTGTCACTTATCTTTCACTCCCTGAATAAAGTATCTATGCATATA" ] }, "test9": { From 80fb29e8f9fb8903e0844f605aae96e201cd232d Mon Sep 17 00:00:00 2001 From: Elarwei Date: Wed, 24 Jun 2026 23:19:13 +0800 Subject: [PATCH 2/4] test(seq): harden transcript cDNA edge-case tests (#187) Add network-free, mocked tests covering the #187 fix (gget seq returns the spliced cDNA for transcript/ENST IDs instead of the genomic span): - versioned ENST id (.N) is version-stripped and fetched as type=cdna - non-coding/ncRNA transcript uses the same cDNA path - mixed gene+transcript batch splits into a genomic and a cDNA request - isoforms=True for both a gene (cDNA per transcript) and a transcript - translate=True for a transcript queries UniProt with the transcript ID - graceful handling when an entry has no desc, and when an ID is absent from the Ensembl response All Ensembl/UniProt calls are mocked so the new tests are deterministic and offline; existing live tests are left unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_seq.py | 218 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/tests/test_seq.py b/tests/test_seq.py index 8d34e4ed7..1c04c6ecf 100644 --- a/tests/test_seq.py +++ b/tests/test_seq.py @@ -1,7 +1,9 @@ import json import time import unittest +from unittest.mock import patch +import pandas as pd from gget.gget_seq import seq # Load dictionary containing arguments and expected results @@ -93,3 +95,219 @@ def test_seq_missing_uniprot_gene_name(self): result_to_test = seq(**seq_dict[test]["args"]) self.assertListEqual(result_to_test, expected_result) + + +def _seq_entry(query, sequence, desc="chromosome:GRCh38:17:1:100:1", extra=None): + """Build a fake Ensembl sequence/id POST entry (as returned before key cleanup).""" + entry = { + "query": query, + "id": query, + "version": 1, + "molecule": "dna", + "seq": sequence, + "desc": desc, + } + if extra is not None: + entry.update(extra) + return entry + + +def _info_df(ensembl_id, object_type, all_transcripts=None, canonical_transcript=None): + """Build a minimal gget.info-style DataFrame indexed by the queried Ensembl ID.""" + row = {"object_type": [object_type]} + if all_transcripts is not None: + row["all_transcripts"] = [all_transcripts] + if canonical_transcript is not None: + row["canonical_transcript"] = [canonical_transcript] + return pd.DataFrame(row, index=[ensembl_id]) + + +class TestSeqTranscriptMocked(unittest.TestCase): + """Network-free tests for the #187 fix: gget seq must request the spliced cDNA + (type=cdna) for transcript/ENST IDs instead of the default genomic span. + + All Ensembl/UniProt calls are mocked so these tests are deterministic and offline. + """ + + # ----- non-isoform bulk path (lookup/id -> split cDNA vs genomic) ----- + + def test_versioned_transcript_requests_cdna(self): + """A versioned ENST id (.N) is version-stripped and fetched as cDNA, not genomic.""" + + def fake_post_query(server, endpoint, data): + if endpoint == "lookup/id": + # The version must already be stripped before lookup + self.assertEqual(data["ids"], ["ENST00000361390"]) + return {"ENST00000361390": {"object_type": "Transcript"}} + if endpoint == "sequence/id?type=cdna": + return [_seq_entry(i, "ATGCDNASPLICED", desc=None) for i in data["ids"]] + raise AssertionError(f"Unexpected genomic request for a transcript: {endpoint}") + + with patch("gget.gget_seq.post_query", side_effect=fake_post_query) as mock_pq: + result = seq("ENST00000361390.2", verbose=False) + + endpoints = [call.args[1] for call in mock_pq.call_args_list] + self.assertIn("sequence/id?type=cdna", endpoints) + self.assertNotIn("sequence/id", endpoints) # no genomic request for a transcript + # desc is None for cDNA responses -> header has no trailing description + self.assertEqual(result, [">ENST00000361390", "ATGCDNASPLICED"]) + + def test_noncoding_transcript_requests_cdna(self): + """A non-coding (e.g. lincRNA) transcript is handled by the same cDNA path.""" + + def fake_post_query(server, endpoint, data): + if endpoint == "lookup/id": + return {"ENST00000456328": {"object_type": "Transcript", "biotype": "lncRNA"}} + if endpoint == "sequence/id?type=cdna": + return [_seq_entry(i, "NCRNASEQ", desc=None) for i in data["ids"]] + raise AssertionError(f"Unexpected genomic request for ncRNA transcript: {endpoint}") + + with patch("gget.gget_seq.post_query", side_effect=fake_post_query) as mock_pq: + result = seq("ENST00000456328", verbose=False) + + endpoints = [call.args[1] for call in mock_pq.call_args_list] + self.assertIn("sequence/id?type=cdna", endpoints) + self.assertNotIn("sequence/id", endpoints) + self.assertEqual(result, [">ENST00000456328", "NCRNASEQ"]) + + def test_mixed_gene_and_transcript_batch_splits_requests(self): + """A single call with a gene + a transcript splits into a genomic and a cDNA request.""" + gene_id = "ENSG00000012048" + transcript_id = "ENST00000357654" + + cdna_ids = [] + genomic_ids = [] + + def fake_post_query(server, endpoint, data): + if endpoint == "lookup/id": + return { + gene_id: {"object_type": "Gene"}, + transcript_id: {"object_type": "Transcript"}, + } + if endpoint == "sequence/id?type=cdna": + cdna_ids.extend(data["ids"]) + return [_seq_entry(i, "CDNASEQ", desc=None) for i in data["ids"]] + if endpoint == "sequence/id": + genomic_ids.extend(data["ids"]) + return [_seq_entry(i, "GENOMICSEQ", desc="chromosome:GRCh38:17") for i in data["ids"]] + raise AssertionError(endpoint) + + with patch("gget.gget_seq.post_query", side_effect=fake_post_query): + result = seq([gene_id, transcript_id], verbose=False) + + # The transcript went to the cDNA batch, the gene to the genomic batch + self.assertEqual(cdna_ids, [transcript_id]) + self.assertEqual(genomic_ids, [gene_id]) + # Both sequences are present, each under its own header + self.assertIn(">" + transcript_id, result) + self.assertIn("CDNASEQ", result) + self.assertIn(">" + gene_id + " chromosome:GRCh38:17", result) + self.assertIn("GENOMICSEQ", result) + + def test_entry_with_no_desc_builds_header_gracefully(self): + """An Ensembl cDNA entry lacking a 'desc' field must not break FASTA header building.""" + + def fake_post_query(server, endpoint, data): + if endpoint == "lookup/id": + return {"ENST00000361390": {"object_type": "Transcript"}} + if endpoint == "sequence/id?type=cdna": + # Note: no "desc" key at all (and no version/molecule) + return [{"query": "ENST00000361390", "id": "ENST00000361390", "seq": "ATGC"}] + raise AssertionError(endpoint) + + with patch("gget.gget_seq.post_query", side_effect=fake_post_query): + result = seq("ENST00000361390", verbose=False) + + self.assertEqual(result, [">ENST00000361390", "ATGC"]) + + def test_id_absent_from_response_is_skipped_gracefully(self): + """If Ensembl returns no entry for an ID, it is logged and skipped (no crash, empty FASTA).""" + + def fake_post_query(server, endpoint, data): + if endpoint == "lookup/id": + return {"ENST00000361390": {"object_type": "Transcript"}} + if endpoint == "sequence/id?type=cdna": + return [] # nothing returned for the requested transcript + raise AssertionError(endpoint) + + with patch("gget.gget_seq.post_query", side_effect=fake_post_query): + with self.assertLogs(level="ERROR") as captured: + result = seq("ENST00000361390", verbose=False) + + self.assertEqual(result, []) + self.assertTrue(any("ENST00000361390" in line for line in captured.output)) + + # ----- isoforms=True path (per-transcript rest_query) ----- + + def test_isoforms_gene_requests_cdna_for_each_transcript(self): + """isoforms=True on a gene fetches each transcript as cDNA via rest_query.""" + gene_id = "ENSG00000012048" + queries = [] + + def fake_rest_query(server, query, content_type): + queries.append(query) + tid = query.split("/")[-1].split("?")[0] + return {"id": tid, "seq": "CDNA_" + tid, "desc": None} + + with ( + patch("gget.gget_seq.info", return_value=_info_df(gene_id, "Gene", all_transcripts=["ENST00000357654", "ENST00000352993"])), + patch("gget.gget_seq.rest_query", side_effect=fake_rest_query), + ): + result = seq(gene_id, isoforms=True, verbose=False) + + # Every transcript was requested as cDNA + self.assertTrue(queries) + for q in queries: + self.assertTrue(q.endswith("?type=cdna"), q) + self.assertIn(">ENST00000357654", result) + self.assertIn("CDNA_ENST00000357654", result) + self.assertIn(">ENST00000352993", result) + + def test_isoforms_transcript_requests_cdna_and_warns(self): + """isoforms=True on a transcript fetches cDNA and warns that isoforms only apply to genes.""" + transcript_id = "ENST00000357654" + queries = [] + + def fake_rest_query(server, query, content_type): + queries.append(query) + return {"id": transcript_id, "seq": "CDNAISO", "desc": None} + + with ( + patch("gget.gget_seq.info", return_value=_info_df(transcript_id, "Transcript")), + patch("gget.gget_seq.rest_query", side_effect=fake_rest_query), + self.assertLogs(level="WARNING") as captured, + ): + result = seq(transcript_id, isoforms=True, verbose=False) + + self.assertEqual(queries, ["sequence/id/" + transcript_id + "?type=cdna"]) + self.assertEqual(result, [">" + transcript_id, "CDNAISO"]) + self.assertTrue(any("isoform" in line.lower() for line in captured.output)) + + # ----- translate=True path (UniProt) ----- + + def test_translate_transcript_queries_uniprot(self): + """translate=True on a transcript queries UniProt with the transcript ID.""" + transcript_id = "ENST00000357654" + uniprot_df = pd.DataFrame( + { + "uniprot_id": ["P38398"], + "query": [transcript_id], + "gene_name": ["BRCA1"], + "organism": ["Homo sapiens"], + "sequence_length": [3], + "sequence": ["MEN"], + } + ) + + with ( + patch("gget.gget_seq.info", return_value=_info_df(transcript_id, "Transcript")), + patch("gget.gget_seq.get_uniprot_seqs", return_value=uniprot_df) as mock_uniprot, + ): + result = seq(transcript_id, translate=True, verbose=False) + + # UniProt queried with the transcript ID + self.assertEqual(list(mock_uniprot.call_args.args[1]), [transcript_id]) + self.assertEqual(len(result), 2) + self.assertIn("uniprot_id: P38398", result[0]) + self.assertIn(transcript_id, result[0]) + self.assertEqual(result[1], "MEN") From ccb2dc245b13ee778cc2febef42fb8cb817f1807 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:38:03 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_seq.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_seq.py b/tests/test_seq.py index 1c04c6ecf..df1136316 100644 --- a/tests/test_seq.py +++ b/tests/test_seq.py @@ -250,7 +250,10 @@ def fake_rest_query(server, query, content_type): return {"id": tid, "seq": "CDNA_" + tid, "desc": None} with ( - patch("gget.gget_seq.info", return_value=_info_df(gene_id, "Gene", all_transcripts=["ENST00000357654", "ENST00000352993"])), + patch( + "gget.gget_seq.info", + return_value=_info_df(gene_id, "Gene", all_transcripts=["ENST00000357654", "ENST00000352993"]), + ), patch("gget.gget_seq.rest_query", side_effect=fake_rest_query), ): result = seq(gene_id, isoforms=True, verbose=False) From 70e1c80831ecaf056ad9818a2920ee04e67d587e Mon Sep 17 00:00:00 2001 From: Elarwei Date: Thu, 25 Jun 2026 00:06:18 +0800 Subject: [PATCH 4/4] test(seq): cover remaining transcript branches (#187) Add targeted, network-free tests for the previously-uncovered branches of the #187 fix (patch coverage was 82.6%, 4 lines in gget/gget_seq.py): - lookup/id classification failure -> falls back to a genomic request - isoforms=True on a gene where one transcript's cDNA fetch fails -> the error is logged and the remaining transcripts are still returned - isoforms=True on a transcript whose cDNA fetch fails -> error logged, no sequence returned These exercise the three `except RuntimeError` handlers that were not hit before, bringing patch coverage of the fix to ~100%. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/src/en/updates.md | 3 +- tests/test_seq.py | 62 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/docs/src/en/updates.md b/docs/src/en/updates.md index b72416792..5faa1ded7 100644 --- a/docs/src/en/updates.md +++ b/docs/src/en/updates.md @@ -5,6 +5,8 @@ #### *gget* officially became part of [*scverse*](https://scverse.org/) on June 9, 2026. 🥳🥳🥳 **Version ≥ 0.30.9** (XXX XX, 2026): +- Bug fixes: + - [`gget seq`](seq.md): Transcript/ENST IDs now return the spliced cDNA sequence instead of the genomic span (which included introns). gget requests `type=cdna` from the Ensembl `sequence/id` endpoint for transcript IDs across all code paths (bulk, isoform, and single-ID); gene IDs are unaffected and still return the genomic sequence. Resolves [issue 187](https://github.com/scverse/gget/issues/187). **Version ≥ 0.30.8** (Jun 28, 2026): - [`gget g2p`](g2p.md): Either `gene` or `--uniprot_id` is now sufficient — whichever is missing is resolved via UniProt and cached. Gene→UniProt picks the canonical reviewed human Swiss-Prot entry; the resolution and its limitations are logged. The canonical pair is **always** prepended to the result as `gene_name` / `uniprot_id` columns (and stored on `df.attrs`), so the output schema is invariant regardless of input mode. Existing call sites continue to work. @@ -37,7 +39,6 @@ - Deprecations: - [`gget alphafold`](alphafold.md) and [`gget gpt`](gpt.md) are no longer actively maintained. Both now emit a warning when invoked, and a deprecation notice was added to the top of each module's docs. - Bug fixes: - - [`gget seq`](seq.md): Transcript/ENST IDs now return the spliced cDNA sequence instead of the genomic span (which included introns). gget requests `type=cdna` from the Ensembl `sequence/id` endpoint for transcript IDs across all code paths (bulk, isoform, and single-ID); gene IDs are unaffected and still return the genomic sequence. Resolves [issue 187](https://github.com/scverse/gget/issues/187). - [`gget search`](search.md): Missing values are now consistently returned as `None` instead of `NaN`, both in scalar cells and inside synonym lists (`[None]` rather than `[nan]` for genes with no synonyms). The previous output was an artifact of `SQL LEFT JOIN`s surfacing as pandas `NaN`s; the JSON output was already `null` either way, so this only affects the DataFrame return path. - [`gget mutate`](mutate.md): Fixed `pyarrow.lib.ArrowNotImplementedError: Function 'binary_join_element_wise' has no kernel matching input types (large_string, null, large_string)` when the input contained no substitutions (only deletions/insertions/delins/duplications/inversions). The substitution-only sequence-build branches now short-circuit on an empty selection instead of triggering an arrow-string kernel that older `pyarrow` versions don't implement. - [`gget muscle`](muscle.md) and [`gget diamond`](diamond.md): When the bundled MUSCLE / DIAMOND binary fails because a system library is missing (most commonly `libgomp` / `libomp` on macOS without Homebrew gcc/libomp installed), gget now raises a clear `RuntimeError` naming the missing library and the exact `brew install` / `apt install` command to fix it — instead of the raw `dyld` / `ld.so` error spilling onto stderr. diff --git a/tests/test_seq.py b/tests/test_seq.py index df1136316..240c27681 100644 --- a/tests/test_seq.py +++ b/tests/test_seq.py @@ -314,3 +314,65 @@ def test_translate_transcript_queries_uniprot(self): self.assertIn("uniprot_id: P38398", result[0]) self.assertIn(transcript_id, result[0]) self.assertEqual(result[1], "MEN") + + # ----- error/fallback branches (the remaining uncovered #187 lines) ----- + + def test_lookup_failure_falls_back_to_genomic(self): + """If the lookup/id classification fails, gget seq falls back to a genomic request.""" + + def fake_post_query(server, endpoint, data): + if endpoint == "lookup/id": + raise RuntimeError("lookup/id endpoint unavailable") + if endpoint == "sequence/id": + return [_seq_entry(i, "FALLBACKSEQ", desc="chromosome:GRCh38:1") for i in data["ids"]] + raise AssertionError(f"Unexpected endpoint after lookup failure: {endpoint}") + + with patch("gget.gget_seq.post_query", side_effect=fake_post_query) as mock_pq: + result = seq("ENSG00000012048", verbose=False) + + endpoints = [call.args[1] for call in mock_pq.call_args_list] + self.assertIn("lookup/id", endpoints) # the lookup was attempted + self.assertIn("sequence/id", endpoints) # and it fell back to the genomic request + self.assertNotIn("sequence/id?type=cdna", endpoints) + self.assertEqual(result, [">ENSG00000012048 chromosome:GRCh38:1", "FALLBACKSEQ"]) + + def test_isoforms_gene_transcript_fetch_error_is_logged(self): + """isoforms=True on a gene logs an error for a failing transcript but keeps the others.""" + gene_id = "ENSG00000012048" + + def fake_rest_query(server, query, content_type): + if "ENST00000357654" in query: + raise RuntimeError("transcript not found") + return {"id": "ENST00000352993", "seq": "CDNA_OK", "desc": None} + + with ( + patch( + "gget.gget_seq.info", + return_value=_info_df(gene_id, "Gene", all_transcripts=["ENST00000357654", "ENST00000352993"]), + ), + patch("gget.gget_seq.rest_query", side_effect=fake_rest_query), + self.assertLogs(level="ERROR") as captured, + ): + result = seq(gene_id, isoforms=True, verbose=False) + + self.assertTrue(any("ENST00000357654" in line for line in captured.output)) + # The transcript that succeeded is still returned + self.assertIn(">ENST00000352993", result) + self.assertIn("CDNA_OK", result) + + def test_isoforms_transcript_fetch_error_is_logged(self): + """isoforms=True on a transcript whose cDNA fetch fails logs an error and yields no sequence.""" + transcript_id = "ENST00000357654" + + def fake_rest_query(server, query, content_type): + raise RuntimeError("transcript not found") + + with ( + patch("gget.gget_seq.info", return_value=_info_df(transcript_id, "Transcript")), + patch("gget.gget_seq.rest_query", side_effect=fake_rest_query), + self.assertLogs(level="ERROR") as captured, + ): + result = seq(transcript_id, isoforms=True, verbose=False) + + self.assertEqual(result, []) + self.assertTrue(any(transcript_id in line for line in captured.output))