orfdata 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orfdata/__init__.py +36 -0
- orfdata/build.py +625 -0
- orfdata/catalog.py +637 -0
- orfdata/cli.py +156 -0
- orfdata/data/orf-evidence/AUTHOR-LICENSE.txt +21 -0
- orfdata/data/orf-evidence/NOTICE.txt +32 -0
- orfdata/data/orf-evidence/catalog.json.gz +0 -0
- orfdata/data/orf-evidence/manifest.json +30 -0
- orfdata/data/uorf-evidence/AUTHOR-LICENSE.txt +21 -0
- orfdata/data/uorf-evidence/NOTICE.txt +32 -0
- orfdata/data/uorf-evidence/catalog.json.gz +0 -0
- orfdata/data/uorf-evidence/manifest.json +29 -0
- orfdata/initiation_context.py +178 -0
- orfdata/model.py +188 -0
- orfdata/sequence.py +30 -0
- orfdata/version.py +1 -0
- orfdata-0.1.0.dist-info/METADATA +98 -0
- orfdata-0.1.0.dist-info/RECORD +22 -0
- orfdata-0.1.0.dist-info/WHEEL +5 -0
- orfdata-0.1.0.dist-info/entry_points.txt +2 -0
- orfdata-0.1.0.dist-info/licenses/LICENSE +201 -0
- orfdata-0.1.0.dist-info/top_level.txt +1 -0
orfdata/cli.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""Query and export the offline ORF evidence reference."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import csv
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from .catalog import EVIDENCE_METHODS, UORFCatalog, load_catalog
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def run(argv=None, prog=None, *, catalog_loader=load_catalog):
|
|
13
|
+
"""Export reference records as JSON, TSV or FASTA."""
|
|
14
|
+
parser = argparse.ArgumentParser(description=__doc__, prog=prog)
|
|
15
|
+
parser.add_argument("--catalog", help="Use a compatible local JSON/JSON.gz catalogue")
|
|
16
|
+
parser.add_argument("--gene", help="Exact gene symbol or Ensembl gene ID")
|
|
17
|
+
parser.add_argument("--transcript", help="Exact source transcript ID (unversioned)")
|
|
18
|
+
parser.add_argument("--orf-id", help="Exact catalogue ORF identifier")
|
|
19
|
+
parser.add_argument("--evidence", choices=EVIDENCE_METHODS)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"--require-unique", action="store_true", help="Require one protein mapping in the MS source"
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"--require-reviewed",
|
|
25
|
+
action="store_true",
|
|
26
|
+
help="Require convincing reviewed spectra (benchmark scores 4-5)",
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument("--biotype", help="Source ORF class, e.g. uORF, lncRNA, intORF, dORF")
|
|
29
|
+
parser.add_argument("--region", help="1-based inclusive interval: chr7:66205483-66205522")
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--position", help="Map a 1-based variant position: chr7:66205483 (JSON only)"
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--include-initiation-context",
|
|
35
|
+
action="store_true",
|
|
36
|
+
help="Include spliced start flanks in locus lookup",
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument("--ref", help="Forward-genomic SNV REF; requires --alt and --position")
|
|
39
|
+
parser.add_argument("--alt", help="Forward-genomic SNV ALT; compare initiation contexts")
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--genome-build", help="Required for genomic queries; packaged data use GRCh38"
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument("--format", choices=("json", "tsv", "fasta"), default="json")
|
|
44
|
+
args = parser.parse_args(argv)
|
|
45
|
+
if args.region and args.position:
|
|
46
|
+
parser.error("Choose --region or --position")
|
|
47
|
+
if args.position and args.format != "json":
|
|
48
|
+
parser.error("--position requires --format json")
|
|
49
|
+
if (args.ref is not None or args.alt is not None) and (
|
|
50
|
+
not args.ref or not args.alt or not args.position
|
|
51
|
+
):
|
|
52
|
+
parser.error("SNV annotation requires --position, --ref and --alt")
|
|
53
|
+
if args.ref and (
|
|
54
|
+
args.ref not in ("A", "C", "G", "T")
|
|
55
|
+
or args.alt not in ("A", "C", "G", "T")
|
|
56
|
+
or args.ref == args.alt
|
|
57
|
+
):
|
|
58
|
+
parser.error("Provide distinct single-base forward-genomic REF and ALT")
|
|
59
|
+
try:
|
|
60
|
+
catalog = catalog_loader(args.catalog)
|
|
61
|
+
options = {
|
|
62
|
+
"gene": args.gene,
|
|
63
|
+
"transcript_id": args.transcript,
|
|
64
|
+
"evidence": args.evidence,
|
|
65
|
+
"require_unique": args.require_unique,
|
|
66
|
+
"require_reviewed": args.require_reviewed,
|
|
67
|
+
"biotype": args.biotype,
|
|
68
|
+
"genome_build": args.genome_build,
|
|
69
|
+
"include_initiation_context": args.include_initiation_context or bool(args.ref),
|
|
70
|
+
}
|
|
71
|
+
locus = args.region or args.position
|
|
72
|
+
if locus:
|
|
73
|
+
pattern = r"([^:]+):([0-9]+)-([0-9]+)" if args.region else r"([^:]+):([0-9]+)"
|
|
74
|
+
match = re.fullmatch(pattern, locus)
|
|
75
|
+
if match is None:
|
|
76
|
+
raise ValueError(f"Invalid locus: {locus}")
|
|
77
|
+
start = int(match.group(2))
|
|
78
|
+
options.update(
|
|
79
|
+
contig=match.group(1),
|
|
80
|
+
start=start,
|
|
81
|
+
end=int(match.group(3)) if args.region else start,
|
|
82
|
+
)
|
|
83
|
+
records = catalog.query(**options)
|
|
84
|
+
if args.orf_id:
|
|
85
|
+
catalog.get(args.orf_id) # A misspelled ID is an error, not empty evidence.
|
|
86
|
+
records = tuple(r for r in records if r.orf_id == args.orf_id)
|
|
87
|
+
initiation_annotations = None
|
|
88
|
+
if args.position:
|
|
89
|
+
initiation_annotations = []
|
|
90
|
+
for r in records:
|
|
91
|
+
annotation = r.map_initiation_position(
|
|
92
|
+
options["start"], genome_build=args.genome_build
|
|
93
|
+
)
|
|
94
|
+
if args.ref and annotation is not None:
|
|
95
|
+
annotation = r.annotate_initiation_snv(
|
|
96
|
+
options["start"], args.ref, args.alt, genome_build=args.genome_build
|
|
97
|
+
)
|
|
98
|
+
initiation_annotations.append(annotation)
|
|
99
|
+
if args.ref and not any(a is not None for a in initiation_annotations):
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"No mapped initiation context covers the SNV; coding consequences require full transcript reconstruction"
|
|
102
|
+
)
|
|
103
|
+
except (ValueError, KeyError, OSError) as exc:
|
|
104
|
+
parser.error(str(exc))
|
|
105
|
+
if args.format == "json":
|
|
106
|
+
output = {
|
|
107
|
+
"schema": "isovar.uorf_query.v1"
|
|
108
|
+
if isinstance(catalog, UORFCatalog)
|
|
109
|
+
else "orfdata.query.v1",
|
|
110
|
+
"metadata": catalog.metadata,
|
|
111
|
+
"records": [r.to_dict() for r in records],
|
|
112
|
+
}
|
|
113
|
+
if args.position:
|
|
114
|
+
output["position_annotations"] = [
|
|
115
|
+
r.map_genomic_position(options["start"], genome_build=args.genome_build)
|
|
116
|
+
for r in records
|
|
117
|
+
]
|
|
118
|
+
output["initiation_annotations"] = initiation_annotations
|
|
119
|
+
json.dump(output, sys.stdout, indent=2)
|
|
120
|
+
sys.stdout.write("\n")
|
|
121
|
+
elif args.format == "fasta":
|
|
122
|
+
for r in records:
|
|
123
|
+
sys.stdout.write(
|
|
124
|
+
f">{r.orf_id} gene={r.gene_name} transcript={r.transcript_id} assembly={r.genome_build} biotype={r.biotype}\n{r.protein_sequence}\n"
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
fields = (
|
|
128
|
+
"orf_id",
|
|
129
|
+
"gene_id",
|
|
130
|
+
"gene_name",
|
|
131
|
+
"transcript_id",
|
|
132
|
+
"genome_build",
|
|
133
|
+
"taxon_id",
|
|
134
|
+
"species",
|
|
135
|
+
"translation_table",
|
|
136
|
+
"source",
|
|
137
|
+
"contig",
|
|
138
|
+
"strand",
|
|
139
|
+
"biotype",
|
|
140
|
+
"protein_sequence",
|
|
141
|
+
"coding_blocks_json",
|
|
142
|
+
"ribosome_studies_json",
|
|
143
|
+
"peptides_json",
|
|
144
|
+
"initiation_context_json",
|
|
145
|
+
)
|
|
146
|
+
writer = csv.DictWriter(sys.stdout, fieldnames=fields, delimiter="\t", lineterminator="\n")
|
|
147
|
+
writer.writeheader()
|
|
148
|
+
for r in records:
|
|
149
|
+
row = r.to_dict()
|
|
150
|
+
for field in ("coding_blocks", "ribosome_studies", "peptides", "initiation_context"):
|
|
151
|
+
row[field + "_json"] = json.dumps(row.pop(field), separators=(",", ":"))
|
|
152
|
+
writer.writerow(row)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
run()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Leron Kok
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
orfdata ncORF evidence catalogue, dataset version 2026-10-11.1.
|
|
2
|
+
|
|
3
|
+
The orfdata API and builder (derived from Isovar) are Apache-2.0. Source data retain their own licenses.
|
|
4
|
+
|
|
5
|
+
GENCODE Phase I models and legacy MS annotations, plus HLA mapping/count data:
|
|
6
|
+
Copyright (c) 2025 Leron Kok. MIT license, included as AUTHOR-LICENSE.txt.
|
|
7
|
+
VanHeeschLab/deutsch_kok_et_al_2024, commit
|
|
8
|
+
b65ae0c09a53e9efe083d806d617581e6139bdde.
|
|
9
|
+
https://github.com/VanHeeschLab/deutsch_kok_et_al_2024
|
|
10
|
+
Associated studies: Mudge et al. 2022, DOI 10.1038/s41587-022-01369-0;
|
|
11
|
+
Deutsch et al. 2026, DOI 10.1038/s41586-026-10459-x.
|
|
12
|
+
|
|
13
|
+
Community spectrum review input:
|
|
14
|
+
Aaron Wacholder and the community assessment authors, archived dataset version 1.
|
|
15
|
+
https://doi.org/10.6084/m9.figshare.30131869.v1
|
|
16
|
+
License: Creative Commons Attribution 4.0 International (CC BY 4.0).
|
|
17
|
+
https://creativecommons.org/licenses/by/4.0/
|
|
18
|
+
Associated study: Wacholder et al. 2026, DOI 10.1038/s41467-025-68002-x.
|
|
19
|
+
|
|
20
|
+
Changes: included all complete stopped source ncORF classes; normalized coordinates and source metadata;
|
|
21
|
+
joined sequence-compatible peptide observations; retained individual reviews,
|
|
22
|
+
source attribution and unknown mapping counts; calculated peptide intervals and
|
|
23
|
+
conservative review labels. Full original article text and supplementary
|
|
24
|
+
curation tables are not redistributed. Source URLs, SHA256 pins, evidence scope
|
|
25
|
+
and exclusions are in catalog metadata and manifest.json.
|
|
26
|
+
|
|
27
|
+
Initiation-context sequence: Ensembl release 101, human GRCh38 GTF/cDNA/ncRNA.
|
|
28
|
+
Ensembl-generated data are available without restriction:
|
|
29
|
+
https://www.ensembl.org/info/about/legal/disclaimer.html
|
|
30
|
+
Changes: exact ORF path/protein validation; extracted transcript-oriented start
|
|
31
|
+
flanks and genomic placements; added partial-context/positional Kozak priors.
|
|
32
|
+
Sequence priors are not measurements of translation or protein abundance.
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"catalog_sha256": "06bc0bf3f81c25a7356f71a38581ff5704c05dcb75752454bc1ca75075ab8c09",
|
|
3
|
+
"dataset_version": "2026-10-11.1",
|
|
4
|
+
"excluded_assignments": [],
|
|
5
|
+
"schema": "orfdata.manifest.v1",
|
|
6
|
+
"source_sha256": {
|
|
7
|
+
"author-hla-counts.json": "b1e8e79e74e90d205224cc86663ebf9d64ed97cf0e0290cd86117756ee46a4b6",
|
|
8
|
+
"author-hla-mappings.tsv": "7f97f4ea675ac6abc97217c865019d73135358f448533ad8d98c9479fee9fb8f",
|
|
9
|
+
"ensembl101.cdna.fa.gz": "519cb4398f7a7904531a0eaaf16a8252f0487f101e00087f6316017bd51a1093",
|
|
10
|
+
"ensembl101.gtf.gz": "6f63da87a7f2f7b5e6940f7e2bd9dd2e7aee37494430e6ac7274f7ef8dc214ba",
|
|
11
|
+
"ensembl101.ncrna.fa.gz": "6bbf091adb1214942b6f258aa830393b27ad7cc49f8ee2fe18260a7b46a0cc88",
|
|
12
|
+
"filtered_peptides.tar.bz2": "a97d73b08b4ee7376a064f9fee3480b3d73639ebe0bd238a6dd0099df6a9e30c",
|
|
13
|
+
"media-4_with_dot_products.csv": "9e2cbb54765f8a9886cdcbf0bdfefa772f4623f54291add2bf3c47c26b17250f",
|
|
14
|
+
"ncorf_list.xlsx": "ca2e2f9389052c62f48ec6f81d53ca88c64152edb5940e556813d4a7bf1e6c62",
|
|
15
|
+
"peptide_sample_msrun_counts.tar.bz2": "290658de32de2579d17f0b75c3fcc39b4d50c5e6ce1ceea9ce9f411ccc8a98ba"
|
|
16
|
+
},
|
|
17
|
+
"statistics": {
|
|
18
|
+
"excluded_legacy_assignments": 0,
|
|
19
|
+
"hla_orfs": 1881,
|
|
20
|
+
"initiation_context_complete": 7041,
|
|
21
|
+
"initiation_context_partial": 223,
|
|
22
|
+
"initiation_context_unavailable": 0,
|
|
23
|
+
"ms_orfs": 2186,
|
|
24
|
+
"peptides": 4315,
|
|
25
|
+
"records": 7264,
|
|
26
|
+
"reviewed_ms_orfs": 44,
|
|
27
|
+
"ribosome_orfs": 7264,
|
|
28
|
+
"shotgun_orfs": 73
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Leron Kok
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Isovar uORF evidence catalogue, dataset version 2026-10-08.2.
|
|
2
|
+
|
|
3
|
+
The Isovar API and builder are Apache-2.0. Source data retain their own licenses.
|
|
4
|
+
|
|
5
|
+
GENCODE Phase I models and legacy MS annotations, plus HLA mapping/count data:
|
|
6
|
+
Copyright (c) 2025 Leron Kok. MIT license, included as AUTHOR-LICENSE.txt.
|
|
7
|
+
VanHeeschLab/deutsch_kok_et_al_2024, commit
|
|
8
|
+
b65ae0c09a53e9efe083d806d617581e6139bdde.
|
|
9
|
+
https://github.com/VanHeeschLab/deutsch_kok_et_al_2024
|
|
10
|
+
Associated studies: Mudge et al. 2022, DOI 10.1038/s41587-022-01369-0;
|
|
11
|
+
Deutsch et al. 2026, DOI 10.1038/s41586-026-10459-x.
|
|
12
|
+
|
|
13
|
+
Community spectrum review input:
|
|
14
|
+
Aaron Wacholder and the community assessment authors, archived dataset version 1.
|
|
15
|
+
https://doi.org/10.6084/m9.figshare.30131869.v1
|
|
16
|
+
License: Creative Commons Attribution 4.0 International (CC BY 4.0).
|
|
17
|
+
https://creativecommons.org/licenses/by/4.0/
|
|
18
|
+
Associated study: Wacholder et al. 2026, DOI 10.1038/s41467-025-68002-x.
|
|
19
|
+
|
|
20
|
+
Changes: selected uORF/uoORF models; normalized coordinates and source metadata;
|
|
21
|
+
joined sequence-compatible peptide observations; retained individual reviews,
|
|
22
|
+
source attribution and unknown mapping counts; calculated peptide intervals and
|
|
23
|
+
conservative review labels. Full original article text and supplementary
|
|
24
|
+
curation tables are not redistributed. Source URLs, SHA256 pins, evidence scope
|
|
25
|
+
and exclusions are in catalog metadata and manifest.json.
|
|
26
|
+
|
|
27
|
+
Initiation-context sequence: Ensembl release 101, human GRCh38 GTF/cDNA.
|
|
28
|
+
Ensembl-generated data are available without restriction:
|
|
29
|
+
https://www.ensembl.org/info/about/legal/disclaimer.html
|
|
30
|
+
Changes: exact ORF path/protein validation; extracted transcript-oriented start
|
|
31
|
+
flanks and genomic placements; added partial-context/positional Kozak priors.
|
|
32
|
+
Sequence priors are not measurements of translation or protein abundance.
|
|
Binary file
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"catalog_sha256": "408d79631214f3872b1fb886bf2aa117228d4ae6179d59113af8ce336244bedd",
|
|
3
|
+
"dataset_version": "2026-10-08.2",
|
|
4
|
+
"excluded_assignments": [],
|
|
5
|
+
"schema": "isovar.uorf_manifest.v1",
|
|
6
|
+
"source_sha256": {
|
|
7
|
+
"author-hla-counts.json": "b1e8e79e74e90d205224cc86663ebf9d64ed97cf0e0290cd86117756ee46a4b6",
|
|
8
|
+
"author-hla-mappings.tsv": "7f97f4ea675ac6abc97217c865019d73135358f448533ad8d98c9479fee9fb8f",
|
|
9
|
+
"ensembl101.cdna.fa.gz": "519cb4398f7a7904531a0eaaf16a8252f0487f101e00087f6316017bd51a1093",
|
|
10
|
+
"ensembl101.gtf.gz": "6f63da87a7f2f7b5e6940f7e2bd9dd2e7aee37494430e6ac7274f7ef8dc214ba",
|
|
11
|
+
"filtered_peptides.tar.bz2": "a97d73b08b4ee7376a064f9fee3480b3d73639ebe0bd238a6dd0099df6a9e30c",
|
|
12
|
+
"media-4_with_dot_products.csv": "9e2cbb54765f8a9886cdcbf0bdfefa772f4623f54291add2bf3c47c26b17250f",
|
|
13
|
+
"ncorf_list.xlsx": "ca2e2f9389052c62f48ec6f81d53ca88c64152edb5940e556813d4a7bf1e6c62",
|
|
14
|
+
"peptide_sample_msrun_counts.tar.bz2": "290658de32de2579d17f0b75c3fcc39b4d50c5e6ce1ceea9ce9f411ccc8a98ba"
|
|
15
|
+
},
|
|
16
|
+
"statistics": {
|
|
17
|
+
"excluded_legacy_assignments": 0,
|
|
18
|
+
"hla_orfs": 1059,
|
|
19
|
+
"initiation_context_complete": 3598,
|
|
20
|
+
"initiation_context_partial": 173,
|
|
21
|
+
"initiation_context_unavailable": 0,
|
|
22
|
+
"ms_orfs": 1219,
|
|
23
|
+
"peptides": 2414,
|
|
24
|
+
"records": 3771,
|
|
25
|
+
"reviewed_ms_orfs": 16,
|
|
26
|
+
"ribosome_orfs": 3771,
|
|
27
|
+
"shotgun_orfs": 31
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Loose, positional initiation priors, separate from translation observations."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
# A of ATG is +1; there is no position zero. The outer GCC is optional.
|
|
7
|
+
KOZAK_PREFERENCES = {
|
|
8
|
+
-9: "G",
|
|
9
|
+
-8: "C",
|
|
10
|
+
-7: "C",
|
|
11
|
+
-6: "G",
|
|
12
|
+
-5: "C",
|
|
13
|
+
-4: "C",
|
|
14
|
+
-3: "AG",
|
|
15
|
+
-2: "C",
|
|
16
|
+
-1: "C",
|
|
17
|
+
4: "G",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class InitiationContext:
|
|
23
|
+
"""Transcript-oriented bases surrounding a proposed initiation codon.
|
|
24
|
+
|
|
25
|
+
Missing flanks are empty/short strings, never inferred from protein
|
|
26
|
+
sequence or intronic genomic adjacency. Ambiguous bases remain unknown.
|
|
27
|
+
``genomic_positions`` are optional 1-based placements in sequence order.
|
|
28
|
+
``start_offset`` is measured from the supplied transcript sequence; it
|
|
29
|
+
is not a verified cap distance unless ``five_prime_complete`` is True.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
upstream: str
|
|
33
|
+
start_codon: str
|
|
34
|
+
downstream: str
|
|
35
|
+
genomic_positions: tuple = ()
|
|
36
|
+
source: Optional[str] = None
|
|
37
|
+
source_transcript_id: Optional[str] = None
|
|
38
|
+
start_offset: Optional[int] = None
|
|
39
|
+
five_prime_complete: Optional[bool] = None
|
|
40
|
+
unavailable_reason: Optional[str] = None
|
|
41
|
+
|
|
42
|
+
def __post_init__(self):
|
|
43
|
+
sequence = self.upstream + self.start_codon + self.downstream
|
|
44
|
+
if (
|
|
45
|
+
len(self.upstream) > 9
|
|
46
|
+
or len(self.downstream) > 6
|
|
47
|
+
or any(b not in "ACGTRYSWKMBDHVN" for b in sequence)
|
|
48
|
+
or (len(self.start_codon) != 3 and not self.unavailable_reason)
|
|
49
|
+
):
|
|
50
|
+
raise ValueError("Invalid initiation-context sequence")
|
|
51
|
+
if self.unavailable_reason and sequence:
|
|
52
|
+
raise ValueError("Unavailable context must not carry unvalidated sequence")
|
|
53
|
+
if self.genomic_positions and (
|
|
54
|
+
len(self.genomic_positions) != len(sequence)
|
|
55
|
+
or any(type(p) is not int or p < 1 for p in self.genomic_positions)
|
|
56
|
+
or len(set(self.genomic_positions)) != len(self.genomic_positions)
|
|
57
|
+
):
|
|
58
|
+
raise ValueError("Invalid initiation-context genomic placements")
|
|
59
|
+
if self.start_offset is not None and (
|
|
60
|
+
type(self.start_offset) is not int or self.start_offset < len(self.upstream)
|
|
61
|
+
):
|
|
62
|
+
raise ValueError("Invalid initiation-context start offset")
|
|
63
|
+
if self.five_prime_complete is not None and type(self.five_prime_complete) is not bool:
|
|
64
|
+
raise ValueError("five_prime_complete must be True, False or None")
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def relative_positions(self):
|
|
68
|
+
"""Kozak numbering for every retained base, without a position zero."""
|
|
69
|
+
return tuple(range(-len(self.upstream), 0)) + tuple(
|
|
70
|
+
range(1, len(self.start_codon) + len(self.downstream) + 1)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def assessment(self):
|
|
75
|
+
"""Return observed preferences, missingness and a qualitative prior.
|
|
76
|
+
|
|
77
|
+
Match counts are descriptive, not calibrated probabilities or a
|
|
78
|
+
translation threshold. A mismatch never establishes no initiation.
|
|
79
|
+
Non-ATG starts are retained without predicting their efficiency.
|
|
80
|
+
"""
|
|
81
|
+
sequence = self.upstream + self.start_codon + self.downstream
|
|
82
|
+
bases = dict(zip(self.relative_positions, sequence))
|
|
83
|
+
positions = []
|
|
84
|
+
for position, preferred in KOZAK_PREFERENCES.items():
|
|
85
|
+
base = bases.get(position)
|
|
86
|
+
positions.append(
|
|
87
|
+
{
|
|
88
|
+
"position": position,
|
|
89
|
+
"base": base,
|
|
90
|
+
"preferred": preferred,
|
|
91
|
+
"matches": base in preferred if base is not None and base in "ACGT" else None,
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
key = [p for p in positions if p["position"] in (-3, 4)]
|
|
95
|
+
observed = sum(p["matches"] is not None for p in key)
|
|
96
|
+
matches = sum(p["matches"] is True for p in key)
|
|
97
|
+
if self.unavailable_reason:
|
|
98
|
+
status, interpretation = "unavailable", "sequence_context_unavailable"
|
|
99
|
+
else:
|
|
100
|
+
status = (
|
|
101
|
+
"complete"
|
|
102
|
+
if len(self.upstream) == 9
|
|
103
|
+
and len(self.downstream) == 6
|
|
104
|
+
and all(b in "ACGT" for b in sequence)
|
|
105
|
+
else "partial"
|
|
106
|
+
)
|
|
107
|
+
interpretation = (
|
|
108
|
+
"both_key_preferences_present"
|
|
109
|
+
if matches == 2
|
|
110
|
+
else "one_key_preference_present"
|
|
111
|
+
if matches == 1
|
|
112
|
+
else "no_observed_key_preference; initiation_still_possible"
|
|
113
|
+
if observed
|
|
114
|
+
else "key_positions_unknown; initiation_unresolved"
|
|
115
|
+
)
|
|
116
|
+
codon = self.start_codon
|
|
117
|
+
atg = None if len(codon) != 3 or any(b not in "ACGT" for b in codon) else codon == "ATG"
|
|
118
|
+
boundary = (
|
|
119
|
+
(
|
|
120
|
+
"at_verified_5prime_end; conventional_scanning_uncertain"
|
|
121
|
+
if self.five_prime_complete
|
|
122
|
+
else "at_supplied_sequence_start; true_5prime_end_unverified"
|
|
123
|
+
)
|
|
124
|
+
if self.start_offset == 0
|
|
125
|
+
else None
|
|
126
|
+
)
|
|
127
|
+
return {
|
|
128
|
+
"policy": "isovar.initiation_context.v1",
|
|
129
|
+
"status": status,
|
|
130
|
+
"display": self.upstream + "[" + codon + "]" + self.downstream if sequence else None,
|
|
131
|
+
"is_atg": atg,
|
|
132
|
+
"kozak_positions": positions,
|
|
133
|
+
"key_positions_observed": observed,
|
|
134
|
+
"key_positions_matching": matches,
|
|
135
|
+
"interpretation": interpretation,
|
|
136
|
+
"sequence_boundary_note": boundary,
|
|
137
|
+
"cap_distance_nt": self.start_offset if self.five_prime_complete is True else None,
|
|
138
|
+
"translation_evidence": "sequence_prior_only; not_observed",
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
def to_dict(self):
|
|
142
|
+
"""Serialize raw sequence/provenance and the reproducible assessment."""
|
|
143
|
+
result = asdict(self)
|
|
144
|
+
result["assessment"] = self.assessment
|
|
145
|
+
return result
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def annotate_initiation_context(sequence, start, *, five_prime_complete=None):
|
|
149
|
+
"""Extract up to 9 upstream and 6 downstream bases from a supplied RNA.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
sequence : str
|
|
154
|
+
Transcript-oriented sequence, accepting RNA U or DNA T and IUPAC
|
|
155
|
+
ambiguity. It need not be a complete mature mRNA.
|
|
156
|
+
start : int
|
|
157
|
+
Zero-based offset of a complete proposed initiation codon. ATG is
|
|
158
|
+
not required; retained non-ATG codons receive no efficiency claim.
|
|
159
|
+
five_prime_complete : bool or None
|
|
160
|
+
Caller evidence that the sequence begins at the biological 5-prime
|
|
161
|
+
end. The default leaves the cap distance unknown.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
InitiationContext
|
|
166
|
+
Observed flanks and a loose positional assessment. Partial contexts
|
|
167
|
+
and ATG at the first three bases are retained, never filtered out.
|
|
168
|
+
"""
|
|
169
|
+
sequence = sequence.upper().replace("U", "T")
|
|
170
|
+
if type(start) is not int or not 0 <= start <= len(sequence) - 3:
|
|
171
|
+
raise ValueError("start must identify a complete codon in the sequence")
|
|
172
|
+
return InitiationContext(
|
|
173
|
+
sequence[max(0, start - 9) : start],
|
|
174
|
+
sequence[start : start + 3],
|
|
175
|
+
sequence[start + 3 : start + 9],
|
|
176
|
+
start_offset=start,
|
|
177
|
+
five_prime_complete=five_prime_complete,
|
|
178
|
+
)
|