orfdata 0.16.0__tar.gz → 0.17.0__tar.gz
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-0.16.0/orfdata.egg-info → orfdata-0.17.0}/PKG-INFO +1 -1
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/reference.md +37 -3
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/__init__.py +2 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/catalog.py +52 -9
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/cli.py +3 -0
- orfdata-0.17.0/orfdata/evidence_summary.py +108 -0
- orfdata-0.17.0/orfdata/version.py +1 -0
- {orfdata-0.16.0 → orfdata-0.17.0/orfdata.egg-info}/PKG-INFO +1 -1
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata.egg-info/SOURCES.txt +3 -0
- orfdata-0.17.0/tests/data/aggregate_evidence.json +877 -0
- orfdata-0.17.0/tests/test_evidence_summary.py +178 -0
- orfdata-0.16.0/orfdata/version.py +0 -1
- {orfdata-0.16.0 → orfdata-0.17.0}/LICENSE +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/MANIFEST.in +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/README.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/deploy.sh +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/copy-yeast.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/coverage.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/design.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/human-tissue.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/ingolia-yeast.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/measurements.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/pairing.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/pfizer-protein.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/pfizer-rna.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/search-references.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/source-references.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/species.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/docs/storage.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/lint.sh +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/build.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/datasets.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/orf-evidence/AUTHOR-LICENSE.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/orf-evidence/NOTICE.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/orf-evidence/catalog.json.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/orf-evidence/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/uorf-evidence/AUTHOR-LICENSE.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/uorf-evidence/NOTICE.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/uorf-evidence/catalog.json.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/data/uorf-evidence/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/dataset.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/dataset_cli.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/datasets.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/initiation_context.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/measurements.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/model.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/pairing.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/reference.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/reference_mapping.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/search_reference.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sequence.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sources/__init__.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sources/copy.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sources/ingolia.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sources/pfizer.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sources/pfizer_rna.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata/sources/wang.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata.egg-info/dependency_links.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata.egg-info/entry_points.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata.egg-info/requires.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/orfdata.egg-info/top_level.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/pyproject.toml +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/setup.cfg +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/test.sh +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/conftest.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905474.soft +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905474_KL9_fpkm.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905476.soft +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905476_KL10_fpkm.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905478.soft +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905478_KL11_fpkm.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905479.soft +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/GSM1905479_KL12_fpkm.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/geo-series.soft +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/methods.pdf +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/paper.xml +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/pmc-metadata.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/qconcat.fasta +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/copy/workbook.xlsx +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346111.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346111.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346114.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346114.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346115.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346115.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346116.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346116.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346117.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346117.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346118.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346118.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346120.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346120.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346122.metadata.txt +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/GSM346122.quant.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/ingolia/readMe.txt.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/dog/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/dog/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/dog/protein.tsv +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/dog/search.fasta +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/human/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/human/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/human/protein.tsv +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/human/search.fasta +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/mouse/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/mouse/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/mouse/protein.tsv +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer/mouse/search.fasta +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/GSE325522_family.soft.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/GSE325523_family.soft.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/GSE325525_family.soft.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/counts.csv.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/dog-annotation.gtf.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/dog-expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/dog-manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/mouse-annotation.gtf.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/mouse-expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/mouse-manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/pfizer_rna/samples.xlsx +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/references/README.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/references/canis_lupus_familiaris.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/references/context-keys-v0.4.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/references/homo_sapiens.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/references/mus_musculus.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/references/saccharomyces_cerevisiae.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/regions/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/regions/ingolia.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/search_reference/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/search_reference/dog.fasta +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/search_reference/ensembl83-expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/search_reference/ensembl83-human.fasta.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/search_reference/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/README.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/generate.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/v1.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/v1.sqlite +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/v2.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/v2.sqlite +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/v3.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/storage/v3.sqlite +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/NOTICE.md +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/annotation.gtf.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/copies.zip +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/expected.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/manifest.json +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/protein.zip +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/rna.zip +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/data/wang/search.fasta.gz +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_copy.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_cross_reference_pairing.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_ensembl_search_reference.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_ingolia.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_initiation_context.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_local_build_queries.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_measurements.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_paired_selectors.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_pairing.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_pfizer.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_pfizer_rna.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_reference_context.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_reference_mapping.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_reference_orf.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_region_targets.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_search_reference.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_selectors.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_storage.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_uorf_catalog.py +0 -0
- {orfdata-0.16.0 → orfdata-0.17.0}/tests/test_wang.py +0 -0
|
@@ -12,7 +12,7 @@ PyEnsembl. Binding uses a transcript you have already loaded.
|
|
|
12
12
|
ORF. Each has:
|
|
13
13
|
|
|
14
14
|
- `model`: source identity, ORF type, coordinates, species and protein sequence.
|
|
15
|
-
- `evidence`: ribosome observations
|
|
15
|
+
- `evidence`: ribosome observations, peptide-level MS and native aggregate support.
|
|
16
16
|
- `transcript`: the original PyEnsembl transcript, including its original biotype.
|
|
17
17
|
- `coding_sequence` and `protein_sequence`: checked against that transcript.
|
|
18
18
|
|
|
@@ -46,10 +46,44 @@ possible protein. Inspect `orf.evidence.peptides` for peptide sequences, source
|
|
|
46
46
|
accessions, matching intervals, mapping counts and review quality. Missing counts
|
|
47
47
|
remain unknown; low or mixed spectrum reviews do not count as supporting MS.
|
|
48
48
|
|
|
49
|
+
Some sources provide only aggregate support counts. `EvidenceSummary` keeps the
|
|
50
|
+
native metric, definition, value, source/release, source checksum and explicitly
|
|
51
|
+
scoped entity. For example, [OpenProt's native metrics](https://api.openprot.org/api/2.0/SC/downloads/yeast_s288c-openprot-2_2-altprots+isoforms-min_2_pep-R64-1-1.106.tsv.readme.html)
|
|
52
|
+
include an MS score that sums study-specific unique-peptide
|
|
53
|
+
counts; it is neither global peptide uniqueness nor protein abundance. Its
|
|
54
|
+
translation score counts studies with significant translation detection.
|
|
55
|
+
`None` means unknown and remains distinct from a reported zero.
|
|
56
|
+
|
|
57
|
+
Positive summaries in `orf.evidence.summaries` can satisfy general evidence
|
|
58
|
+
queries. To require actual peptide records or named ribosome studies, use:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
orf.evidence.has_evidence("ms", require_resolved=True)
|
|
62
|
+
catalog.query(evidence="ribosome", require_resolved=True)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The CLI uses `--evidence ms --require-resolved`. Uniqueness and review filters
|
|
66
|
+
always require resolved peptide observations. Summaries never create peptide
|
|
67
|
+
sequences, residue coverage, retained variant peptides or mutant-translation
|
|
68
|
+
evidence. Their protein checksum and species/reference checks prevent attaching
|
|
69
|
+
them to a different protein or incompatible source context.
|
|
70
|
+
|
|
71
|
+
A sequence-level summary may have several transcript assignments. Those records
|
|
72
|
+
share the summary's `key`; `catalog.evidence_summaries` returns each native metric
|
|
73
|
+
once and rejects conflicting facts for the same identity. Native accession
|
|
74
|
+
aliases must be resolved explicitly by the source adapter. Counts from different
|
|
75
|
+
metrics and sources are not summed, and a later peptide-resolved snapshot is not
|
|
76
|
+
an additional independent experiment merely because it has more detail.
|
|
77
|
+
|
|
78
|
+
This API includes source-backed OpenProt human, mouse and yeast test slices.
|
|
79
|
+
It does not yet publish those species' OpenProt ORF catalogues; coordinate and
|
|
80
|
+
sequence qualification remains tracked in [#18](https://github.com/openvax/orfdata/issues/18).
|
|
81
|
+
|
|
49
82
|
The distinction between translation, peptide detection and functional protein
|
|
50
83
|
evidence follows the [TransCODE study](https://www.nature.com/articles/s41586-026-10459-x).
|
|
51
|
-
Source evidence
|
|
52
|
-
evidence for
|
|
84
|
+
Source evidence stays at its declared ORF or protein-sequence scope. It is not
|
|
85
|
+
automatically evidence for another isoform, a mutant protein, a fusion or
|
|
86
|
+
another species.
|
|
53
87
|
|
|
54
88
|
## Variants and RNA products
|
|
55
89
|
|
|
@@ -14,6 +14,7 @@ from .catalog import (
|
|
|
14
14
|
)
|
|
15
15
|
from .dataset import QuantitativeDataset
|
|
16
16
|
from .datasets import DatasetRegistry, build_dataset
|
|
17
|
+
from .evidence_summary import EvidenceSummary
|
|
17
18
|
from .initiation_context import KOZAK_PREFERENCES, InitiationContext, annotate_initiation_context
|
|
18
19
|
from .measurements import (
|
|
19
20
|
Assay,
|
|
@@ -44,6 +45,7 @@ __all__ = [
|
|
|
44
45
|
"ORFCatalog",
|
|
45
46
|
"ORFRecord",
|
|
46
47
|
"ORFEvidence",
|
|
48
|
+
"EvidenceSummary",
|
|
47
49
|
"PeptideEvidence",
|
|
48
50
|
"ORFModel",
|
|
49
51
|
"ReferenceORF",
|
|
@@ -13,6 +13,7 @@ from importlib.resources import files
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Optional
|
|
15
15
|
|
|
16
|
+
from .evidence_summary import EvidenceSummary, unique_summaries
|
|
16
17
|
from .initiation_context import KOZAK_PREFERENCES, InitiationContext
|
|
17
18
|
from .model import ORFModel, ReferenceORF, _species
|
|
18
19
|
from .reference import ReferenceContext
|
|
@@ -73,25 +74,41 @@ class ORFEvidence:
|
|
|
73
74
|
|
|
74
75
|
ribosome_studies: tuple = ()
|
|
75
76
|
peptides: tuple = ()
|
|
77
|
+
summaries: tuple = ()
|
|
78
|
+
|
|
79
|
+
def __post_init__(self):
|
|
80
|
+
object.__setattr__(self, "summaries", unique_summaries(self.summaries))
|
|
76
81
|
|
|
77
82
|
def to_dict(self):
|
|
78
|
-
|
|
83
|
+
result = asdict(self)
|
|
84
|
+
if not self.summaries:
|
|
85
|
+
result.pop("summaries")
|
|
86
|
+
return result
|
|
79
87
|
|
|
80
|
-
def has_evidence(self, method, *, require_unique=False, require_reviewed=False):
|
|
81
|
-
"""Select
|
|
88
|
+
def has_evidence(self, method, *, require_unique=False, require_reviewed=False, require_resolved=False):
|
|
89
|
+
"""Select reported support, or require named studies/resolved peptides.
|
|
90
|
+
|
|
91
|
+
Aggregate counts never satisfy uniqueness or spectrum-review filters.
|
|
92
|
+
No selection establishes evidence for a modified protein product.
|
|
93
|
+
"""
|
|
82
94
|
if method not in EVIDENCE_METHODS:
|
|
83
95
|
raise ValueError(f"Unknown evidence method: {method}")
|
|
84
96
|
if method == "ribosome":
|
|
85
97
|
if require_unique or require_reviewed:
|
|
86
98
|
raise ValueError("MS filters do not apply to ribosome evidence")
|
|
87
|
-
return bool(self.ribosome_studies)
|
|
88
|
-
|
|
99
|
+
return bool(self.ribosome_studies) or (not require_resolved and any(
|
|
100
|
+
s.method == "ribosome" and s.is_supporting for s in self.summaries))
|
|
101
|
+
resolved = any(
|
|
89
102
|
(method == "ms" or p.method == method or (method == "mhc" and p.method == "hla"))
|
|
90
103
|
and p.is_supporting
|
|
91
104
|
and (not require_unique or p.unique_in_source)
|
|
92
105
|
and (not require_reviewed or p.quality == "reviewed_support")
|
|
93
106
|
for p in self.peptides
|
|
94
107
|
)
|
|
108
|
+
return resolved or (not (require_resolved or require_unique or require_reviewed) and any(
|
|
109
|
+
(method == "ms" and s.method != "ribosome"
|
|
110
|
+
or s.method == method or method == "mhc" and s.method == "hla")
|
|
111
|
+
and s.is_supporting for s in self.summaries))
|
|
95
112
|
|
|
96
113
|
|
|
97
114
|
@dataclass(frozen=True)
|
|
@@ -116,6 +133,14 @@ class ORFRecord:
|
|
|
116
133
|
translation_table: int = 1
|
|
117
134
|
source: str = ""
|
|
118
135
|
reference_context: Optional[ReferenceContext] = None
|
|
136
|
+
summaries: tuple = ()
|
|
137
|
+
|
|
138
|
+
def __post_init__(self):
|
|
139
|
+
object.__setattr__(self, "summaries", unique_summaries(self.summaries))
|
|
140
|
+
if self.summaries:
|
|
141
|
+
model = self.model
|
|
142
|
+
for summary in self.summaries:
|
|
143
|
+
summary.validate_orf(model)
|
|
119
144
|
|
|
120
145
|
@property
|
|
121
146
|
def model(self):
|
|
@@ -140,7 +165,7 @@ class ORFRecord:
|
|
|
140
165
|
|
|
141
166
|
@property
|
|
142
167
|
def evidence(self):
|
|
143
|
-
return ORFEvidence(self.ribosome_studies, self.peptides)
|
|
168
|
+
return ORFEvidence(self.ribosome_studies, self.peptides, self.summaries)
|
|
144
169
|
|
|
145
170
|
@classmethod
|
|
146
171
|
def from_model(cls, model, evidence=None, *, initiation_context=None):
|
|
@@ -154,6 +179,7 @@ class ORFRecord:
|
|
|
154
179
|
**fields,
|
|
155
180
|
ribosome_studies=evidence.ribosome_studies,
|
|
156
181
|
peptides=evidence.peptides,
|
|
182
|
+
summaries=evidence.summaries,
|
|
157
183
|
initiation_context=initiation_context,
|
|
158
184
|
)
|
|
159
185
|
|
|
@@ -164,6 +190,8 @@ class ORFRecord:
|
|
|
164
190
|
def to_dict(self):
|
|
165
191
|
"""Return a serializable copy of this record."""
|
|
166
192
|
result = asdict(self)
|
|
193
|
+
if not self.summaries:
|
|
194
|
+
result.pop("summaries")
|
|
167
195
|
if self.reference_context is None:
|
|
168
196
|
result.pop("reference_context")
|
|
169
197
|
if self.initiation_context is not None:
|
|
@@ -284,9 +312,10 @@ class ORFRecord:
|
|
|
284
312
|
translation_change="not_measured",
|
|
285
313
|
)
|
|
286
314
|
|
|
287
|
-
def has_evidence(self, method, *, require_unique=False, require_reviewed=False):
|
|
315
|
+
def has_evidence(self, method, *, require_unique=False, require_reviewed=False, require_resolved=False):
|
|
288
316
|
return self.evidence.has_evidence(
|
|
289
|
-
method, require_unique=require_unique, require_reviewed=require_reviewed
|
|
317
|
+
method, require_unique=require_unique, require_reviewed=require_reviewed,
|
|
318
|
+
require_resolved=require_resolved,
|
|
290
319
|
)
|
|
291
320
|
|
|
292
321
|
def _coding_offset(self, position):
|
|
@@ -423,6 +452,13 @@ class ORFCatalog:
|
|
|
423
452
|
):
|
|
424
453
|
raise ValueError(f"Peptide sequence does not match {r.orf_id}")
|
|
425
454
|
|
|
455
|
+
self._evidence_summaries = unique_summaries(s for r in self.records for s in r.summaries)
|
|
456
|
+
|
|
457
|
+
@property
|
|
458
|
+
def evidence_summaries(self):
|
|
459
|
+
"""Distinct source counts, without multiplying transcript assignments."""
|
|
460
|
+
return self._evidence_summaries
|
|
461
|
+
|
|
426
462
|
@property
|
|
427
463
|
def metadata(self):
|
|
428
464
|
"""Return a copy of dataset version, sources, scope and provenance."""
|
|
@@ -472,6 +508,7 @@ class ORFCatalog:
|
|
|
472
508
|
evidence=None,
|
|
473
509
|
require_unique=False,
|
|
474
510
|
require_reviewed=False,
|
|
511
|
+
require_resolved=False,
|
|
475
512
|
biotype=None,
|
|
476
513
|
include_initiation_context=False,
|
|
477
514
|
):
|
|
@@ -483,6 +520,8 @@ class ORFCatalog:
|
|
|
483
520
|
are unversioned identifiers. Empty results do not prove no translation.
|
|
484
521
|
``require_unique`` means unique within the evidence source's mapping
|
|
485
522
|
scope, not unique in every normal human proteome.
|
|
523
|
+
``require_resolved`` excludes aggregate-only support: MS needs a peptide
|
|
524
|
+
observation and ribosome evidence needs a named study.
|
|
486
525
|
``include_initiation_context`` also intersects placed spliced start
|
|
487
526
|
flanks, for example an upstream Kozak SNV. The default remains coding
|
|
488
527
|
blocks only. It does not include introns between context bases.
|
|
@@ -504,6 +543,8 @@ class ORFCatalog:
|
|
|
504
543
|
raise ValueError("require_unique applies to MS evidence only")
|
|
505
544
|
if require_reviewed and evidence not in EVIDENCE_METHODS[1:]:
|
|
506
545
|
raise ValueError("require_reviewed applies to MS evidence only")
|
|
546
|
+
if require_resolved and evidence is None:
|
|
547
|
+
raise ValueError("require_resolved requires an evidence method")
|
|
507
548
|
|
|
508
549
|
return tuple(
|
|
509
550
|
r
|
|
@@ -530,7 +571,8 @@ class ORFCatalog:
|
|
|
530
571
|
and (
|
|
531
572
|
evidence is None
|
|
532
573
|
or r.has_evidence(
|
|
533
|
-
evidence, require_unique=require_unique, require_reviewed=require_reviewed
|
|
574
|
+
evidence, require_unique=require_unique, require_reviewed=require_reviewed,
|
|
575
|
+
require_resolved=require_resolved,
|
|
534
576
|
)
|
|
535
577
|
)
|
|
536
578
|
)
|
|
@@ -604,6 +646,7 @@ def _load_catalog(path=None, *, expected_sha256=None, resource="orf-evidence"):
|
|
|
604
646
|
p["spectrum_ids"] = tuple(p.get("spectrum_ids", ()))
|
|
605
647
|
peptides.append(PeptideEvidence(**p))
|
|
606
648
|
row["peptides"] = tuple(peptides)
|
|
649
|
+
row["summaries"] = tuple(EvidenceSummary.from_dict(s) for s in row.get("summaries", ()))
|
|
607
650
|
records.append(ORFRecord(**row))
|
|
608
651
|
return ORFCatalog(records, metadata)
|
|
609
652
|
|
|
@@ -24,6 +24,8 @@ def run(argv=None, prog=None, *, catalog_loader=load_catalog):
|
|
|
24
24
|
parser.add_argument("--transcript", help="Exact source transcript ID (unversioned)")
|
|
25
25
|
parser.add_argument("--orf-id", help="Exact catalogue ORF identifier")
|
|
26
26
|
parser.add_argument("--evidence", choices=EVIDENCE_METHODS)
|
|
27
|
+
parser.add_argument("--require-resolved", action="store_true",
|
|
28
|
+
help="Require resolved peptides or named ribosome studies; exclude aggregate-only support")
|
|
27
29
|
parser.add_argument(
|
|
28
30
|
"--require-unique", action="store_true", help="Require one protein mapping in the MS source"
|
|
29
31
|
)
|
|
@@ -69,6 +71,7 @@ def run(argv=None, prog=None, *, catalog_loader=load_catalog):
|
|
|
69
71
|
"gene": args.gene,
|
|
70
72
|
"transcript_id": args.transcript,
|
|
71
73
|
"evidence": args.evidence,
|
|
74
|
+
"require_resolved": args.require_resolved,
|
|
72
75
|
"require_unique": args.require_unique,
|
|
73
76
|
"require_reviewed": args.require_reviewed,
|
|
74
77
|
"biotype": args.biotype,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Source-reported support counts, separate from resolved observations."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import re
|
|
5
|
+
from dataclasses import asdict, dataclass, replace
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
|
|
9
|
+
from .reference import ReferenceContext, ScopedTarget
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class EvidenceSummary:
|
|
14
|
+
"""One native count of experimental support for an exact source entity.
|
|
15
|
+
|
|
16
|
+
``value`` is a nonnegative integer or unknown (None), never a confidence
|
|
17
|
+
score or abundance. ``definition`` preserves the source's counting rules;
|
|
18
|
+
a sum of unique peptides per study is not a globally unique peptide count.
|
|
19
|
+
A protein-sequence summary can support several transcript assignments,
|
|
20
|
+
which retain the same ``key`` instead of multiplying independent evidence.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
source: str
|
|
24
|
+
release: str
|
|
25
|
+
target: ScopedTarget
|
|
26
|
+
protein_sha256: str
|
|
27
|
+
method: str
|
|
28
|
+
metric: str
|
|
29
|
+
value: Optional[int]
|
|
30
|
+
definition: str
|
|
31
|
+
scope: str
|
|
32
|
+
source_url: str
|
|
33
|
+
source_sha256: str
|
|
34
|
+
|
|
35
|
+
def __post_init__(self):
|
|
36
|
+
if not isinstance(self.target, ScopedTarget):
|
|
37
|
+
raise TypeError("Evidence summaries require a ScopedTarget")
|
|
38
|
+
if self.method not in ("ribosome", "shotgun", "mhc", "hla", "ms_unclassified", "ms"):
|
|
39
|
+
raise ValueError("Unknown summary evidence method")
|
|
40
|
+
if self.method == "hla" and self.target.reference.taxon_id != 9606:
|
|
41
|
+
raise ValueError("Use mhc for non-human immunopeptidomics evidence")
|
|
42
|
+
if self.scope not in ("protein_sequence", "orf") or self.target.kind != {
|
|
43
|
+
"protein_sequence": "protein", "orf": "orf"
|
|
44
|
+
}.get(self.scope):
|
|
45
|
+
raise ValueError("Evidence summary scope and target kind disagree")
|
|
46
|
+
if any(not isinstance(x, str) or not x.strip() for x in (self.source, self.release, self.metric, self.definition)):
|
|
47
|
+
raise ValueError("Source, release, native metric and counting definition are required")
|
|
48
|
+
for value in (self.protein_sha256, self.source_sha256):
|
|
49
|
+
if not isinstance(value, str) or not re.fullmatch(r"[0-9a-f]{64}", value):
|
|
50
|
+
raise ValueError("Evidence summaries require lowercase SHA-256 pins")
|
|
51
|
+
if not isinstance(self.source_url, str) or urlparse(self.source_url).scheme not in ("https", "http") or not urlparse(self.source_url).netloc:
|
|
52
|
+
raise ValueError("Evidence summaries require a source URL")
|
|
53
|
+
if self.value is not None and (type(self.value) is not int or self.value < 0):
|
|
54
|
+
raise ValueError("A support count must be a nonnegative integer or None")
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def key(self):
|
|
58
|
+
"""Shared source metric identity, independent of transcript assignment."""
|
|
59
|
+
return (self.source, self.release, self.target.key, self.scope, self.method, self.metric)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def is_supporting(self):
|
|
63
|
+
"""Positive reported support; zero and unknown both fail selection."""
|
|
64
|
+
return self.value is not None and self.value > 0
|
|
65
|
+
|
|
66
|
+
def validate_orf(self, model):
|
|
67
|
+
"""Reject attachment to another species, protein sequence or native ORF."""
|
|
68
|
+
if self.target.reference.taxon_id != model.taxon_id:
|
|
69
|
+
raise ValueError("Summary and ORF species disagree")
|
|
70
|
+
reference = self.target.reference
|
|
71
|
+
if reference.genome_build is not None and reference.genome_build != model.genome_build:
|
|
72
|
+
raise ValueError("Summary and ORF assemblies disagree")
|
|
73
|
+
for field in ("strain", "strain_taxon_id"):
|
|
74
|
+
source = getattr(reference, field)
|
|
75
|
+
destination = getattr(model.reference_context, field, None)
|
|
76
|
+
if source != destination:
|
|
77
|
+
raise ValueError("Summary and ORF strain contexts disagree")
|
|
78
|
+
if self.protein_sha256 != hashlib.sha256(model.protein_sequence.encode("ascii")).hexdigest():
|
|
79
|
+
raise ValueError("Summary and ORF protein sequences disagree")
|
|
80
|
+
if self.scope == "orf" and (
|
|
81
|
+
self.target.identifier != model.orf_id
|
|
82
|
+
or reference.genome_build != model.genome_build
|
|
83
|
+
or (model.reference_context is not None and reference.key != model.reference_context.key)
|
|
84
|
+
):
|
|
85
|
+
raise ValueError("Summary and native ORF identities disagree")
|
|
86
|
+
|
|
87
|
+
def to_dict(self):
|
|
88
|
+
return asdict(self)
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def from_dict(cls, record):
|
|
92
|
+
record = dict(record)
|
|
93
|
+
target = dict(record["target"])
|
|
94
|
+
target["reference"] = ReferenceContext(**target["reference"])
|
|
95
|
+
record["target"] = ScopedTarget(**target)
|
|
96
|
+
return cls(**record)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def unique_summaries(summaries):
|
|
100
|
+
"""Preserve first occurrence; conflicting facts for one identity are errors."""
|
|
101
|
+
result = {}
|
|
102
|
+
for summary in summaries:
|
|
103
|
+
if not isinstance(summary, EvidenceSummary):
|
|
104
|
+
raise TypeError("Expected EvidenceSummary")
|
|
105
|
+
previous = result.setdefault(summary.key, summary)
|
|
106
|
+
if previous != replace(summary, target=previous.target):
|
|
107
|
+
raise ValueError("Conflicting evidence summaries for one source metric")
|
|
108
|
+
return tuple(result.values())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.17.0"
|
|
@@ -26,6 +26,7 @@ orfdata/cli.py
|
|
|
26
26
|
orfdata/dataset.py
|
|
27
27
|
orfdata/dataset_cli.py
|
|
28
28
|
orfdata/datasets.py
|
|
29
|
+
orfdata/evidence_summary.py
|
|
29
30
|
orfdata/initiation_context.py
|
|
30
31
|
orfdata/measurements.py
|
|
31
32
|
orfdata/model.py
|
|
@@ -60,6 +61,7 @@ tests/conftest.py
|
|
|
60
61
|
tests/test_copy.py
|
|
61
62
|
tests/test_cross_reference_pairing.py
|
|
62
63
|
tests/test_ensembl_search_reference.py
|
|
64
|
+
tests/test_evidence_summary.py
|
|
63
65
|
tests/test_ingolia.py
|
|
64
66
|
tests/test_initiation_context.py
|
|
65
67
|
tests/test_local_build_queries.py
|
|
@@ -77,6 +79,7 @@ tests/test_selectors.py
|
|
|
77
79
|
tests/test_storage.py
|
|
78
80
|
tests/test_uorf_catalog.py
|
|
79
81
|
tests/test_wang.py
|
|
82
|
+
tests/data/aggregate_evidence.json
|
|
80
83
|
tests/data/copy/GSM1905474.soft
|
|
81
84
|
tests/data/copy/GSM1905474_KL9_fpkm.txt.gz
|
|
82
85
|
tests/data/copy/GSM1905476.soft
|