orfdata 0.37.0__tar.gz → 0.38.2__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.
Files changed (325) hide show
  1. {orfdata-0.37.0/orfdata.egg-info → orfdata-0.38.2}/PKG-INFO +1 -1
  2. {orfdata-0.37.0 → orfdata-0.38.2}/docs/proteome.md +9 -0
  3. {orfdata-0.37.0 → orfdata-0.38.2}/docs/species.md +9 -0
  4. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/catalog.py +40 -10
  5. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/proteome.py +5 -2
  6. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/openprot.py +12 -5
  7. orfdata-0.38.2/orfdata/version.py +1 -0
  8. {orfdata-0.37.0 → orfdata-0.38.2/orfdata.egg-info}/PKG-INFO +1 -1
  9. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata.egg-info/SOURCES.txt +1 -0
  10. orfdata-0.38.2/tests/test_dog_ncorf_search.py +62 -0
  11. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_genetic_codes.py +54 -0
  12. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_merge_catalogs.py +58 -0
  13. orfdata-0.37.0/orfdata/version.py +0 -1
  14. {orfdata-0.37.0 → orfdata-0.38.2}/LICENSE +0 -0
  15. {orfdata-0.37.0 → orfdata-0.38.2}/MANIFEST.in +0 -0
  16. {orfdata-0.37.0 → orfdata-0.38.2}/README.md +0 -0
  17. {orfdata-0.37.0 → orfdata-0.38.2}/deploy.sh +0 -0
  18. {orfdata-0.37.0 → orfdata-0.38.2}/docs/catalogs.md +0 -0
  19. {orfdata-0.37.0 → orfdata-0.38.2}/docs/copy-yeast.md +0 -0
  20. {orfdata-0.37.0 → orfdata-0.38.2}/docs/coverage.md +0 -0
  21. {orfdata-0.37.0 → orfdata-0.38.2}/docs/dog-peptides.md +0 -0
  22. {orfdata-0.37.0 → orfdata-0.38.2}/docs/downloads.md +0 -0
  23. {orfdata-0.37.0 → orfdata-0.38.2}/docs/downstream.md +0 -0
  24. {orfdata-0.37.0 → orfdata-0.38.2}/docs/examples.md +0 -0
  25. {orfdata-0.37.0 → orfdata-0.38.2}/docs/human-tissue.md +0 -0
  26. {orfdata-0.37.0 → orfdata-0.38.2}/docs/index.md +0 -0
  27. {orfdata-0.37.0 → orfdata-0.38.2}/docs/ingolia-yeast.md +0 -0
  28. {orfdata-0.37.0 → orfdata-0.38.2}/docs/measurements.md +0 -0
  29. {orfdata-0.37.0 → orfdata-0.38.2}/docs/pairing.md +0 -0
  30. {orfdata-0.37.0 → orfdata-0.38.2}/docs/pfizer-protein.md +0 -0
  31. {orfdata-0.37.0 → orfdata-0.38.2}/docs/pfizer-rna.md +0 -0
  32. {orfdata-0.37.0 → orfdata-0.38.2}/docs/reference.md +0 -0
  33. {orfdata-0.37.0 → orfdata-0.38.2}/docs/search-references.md +0 -0
  34. {orfdata-0.37.0 → orfdata-0.38.2}/docs/source-references.md +0 -0
  35. {orfdata-0.37.0 → orfdata-0.38.2}/docs/storage.md +0 -0
  36. {orfdata-0.37.0 → orfdata-0.38.2}/docs/stylesheets/docs.css +0 -0
  37. {orfdata-0.37.0 → orfdata-0.38.2}/docs/viral.md +0 -0
  38. {orfdata-0.37.0 → orfdata-0.38.2}/docs.sh +0 -0
  39. {orfdata-0.37.0 → orfdata-0.38.2}/lint.sh +0 -0
  40. {orfdata-0.37.0 → orfdata-0.38.2}/mkdocs.yml +0 -0
  41. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/__init__.py +0 -0
  42. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/_pinned_genome.py +0 -0
  43. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/_structure.py +0 -0
  44. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/build.py +0 -0
  45. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/catalog_cli.py +0 -0
  46. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/catalog_manifest.py +0 -0
  47. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/catalogs.py +0 -0
  48. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/cli.py +0 -0
  49. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/cli_output.py +0 -0
  50. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/catalogs.json +0 -0
  51. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/chains.json +0 -0
  52. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/datasets.json +0 -0
  53. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/genomes.json +0 -0
  54. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/ires/rfam-15.1-human-ires.json +0 -0
  55. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/orf-evidence/AUTHOR-LICENSE.txt +0 -0
  56. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/orf-evidence/NOTICE.txt +0 -0
  57. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/orf-evidence/catalog.json.gz +0 -0
  58. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/orf-evidence/manifest.json +0 -0
  59. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/uorf-evidence/AUTHOR-LICENSE.txt +0 -0
  60. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/uorf-evidence/NOTICE.txt +0 -0
  61. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/uorf-evidence/catalog.json.gz +0 -0
  62. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/uorf-evidence/manifest.json +0 -0
  63. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/viral/NOTICE.md +0 -0
  64. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/viral/gdc-grch38-d1-vd1-coverage.tsv +0 -0
  65. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/viral/gdc-grch38-d1-vd1-genbank.tsv +0 -0
  66. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/viral/gdc-grch38-d1-vd1-pave.tsv +0 -0
  67. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/viral/hpv16-refseq-CDS.json.gz +0 -0
  68. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/data/viral/subsets.yaml +0 -0
  69. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/dataset.py +0 -0
  70. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/dataset_cli.py +0 -0
  71. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/datasets.py +0 -0
  72. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/download_cli.py +0 -0
  73. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/downloads.py +0 -0
  74. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/evidence.py +0 -0
  75. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/evidence_summary.py +0 -0
  76. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/fasta.py +0 -0
  77. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/genbank.py +0 -0
  78. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/genomes.py +0 -0
  79. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/genomes_cli.py +0 -0
  80. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/gtf.py +0 -0
  81. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/initiation_context.py +0 -0
  82. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/install.py +0 -0
  83. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/liftover.py +0 -0
  84. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/liftover_cli.py +0 -0
  85. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/measurements.py +0 -0
  86. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/model.py +0 -0
  87. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/net.py +0 -0
  88. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/pairing.py +0 -0
  89. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/proteome_cli.py +0 -0
  90. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/record_sources.py +0 -0
  91. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/reference.py +0 -0
  92. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/reference_ledger.py +0 -0
  93. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/reference_mapping.py +0 -0
  94. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/reference_table.py +0 -0
  95. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/refseq.py +0 -0
  96. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/rna.py +0 -0
  97. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/search_reference.py +0 -0
  98. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sequence.py +0 -0
  99. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/__init__.py +0 -0
  100. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/copy.py +0 -0
  101. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/ingolia.py +0 -0
  102. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/kaabinejadian.py +0 -0
  103. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/ncorf_mammals.py +0 -0
  104. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/peptideatlas.py +0 -0
  105. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/pfizer.py +0 -0
  106. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/pfizer_rna.py +0 -0
  107. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/riborf.py +0 -0
  108. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/sources/wang.py +0 -0
  109. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral.py +0 -0
  110. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral_annotation.py +0 -0
  111. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral_cli.py +0 -0
  112. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral_coverage.py +0 -0
  113. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral_panel.py +0 -0
  114. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral_registry.py +0 -0
  115. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata/viral_subsets.py +0 -0
  116. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata.egg-info/dependency_links.txt +0 -0
  117. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata.egg-info/entry_points.txt +0 -0
  118. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata.egg-info/requires.txt +0 -0
  119. {orfdata-0.37.0 → orfdata-0.38.2}/orfdata.egg-info/top_level.txt +0 -0
  120. {orfdata-0.37.0 → orfdata-0.38.2}/pyproject.toml +0 -0
  121. {orfdata-0.37.0 → orfdata-0.38.2}/setup.cfg +0 -0
  122. {orfdata-0.37.0 → orfdata-0.38.2}/test.sh +0 -0
  123. {orfdata-0.37.0 → orfdata-0.38.2}/tests/conftest.py +0 -0
  124. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/aggregate_evidence.json +0 -0
  125. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905474.soft +0 -0
  126. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905474_KL9_fpkm.txt.gz +0 -0
  127. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905476.soft +0 -0
  128. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905476_KL10_fpkm.txt.gz +0 -0
  129. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905478.soft +0 -0
  130. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905478_KL11_fpkm.txt.gz +0 -0
  131. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905479.soft +0 -0
  132. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/GSM1905479_KL12_fpkm.txt.gz +0 -0
  133. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/NOTICE.md +0 -0
  134. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/expected.json +0 -0
  135. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/geo-series.soft +0 -0
  136. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/manifest.json +0 -0
  137. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/methods.pdf +0 -0
  138. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/paper.xml +0 -0
  139. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/pmc-metadata.json +0 -0
  140. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/qconcat.fasta +0 -0
  141. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/copy/workbook.xlsx +0 -0
  142. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346111.metadata.txt +0 -0
  143. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346111.quant.txt.gz +0 -0
  144. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346114.metadata.txt +0 -0
  145. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346114.quant.txt.gz +0 -0
  146. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346115.metadata.txt +0 -0
  147. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346115.quant.txt.gz +0 -0
  148. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346116.metadata.txt +0 -0
  149. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346116.quant.txt.gz +0 -0
  150. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346117.metadata.txt +0 -0
  151. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346117.quant.txt.gz +0 -0
  152. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346118.metadata.txt +0 -0
  153. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346118.quant.txt.gz +0 -0
  154. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346120.metadata.txt +0 -0
  155. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346120.quant.txt.gz +0 -0
  156. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346122.metadata.txt +0 -0
  157. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/GSM346122.quant.txt.gz +0 -0
  158. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/NOTICE.md +0 -0
  159. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/expected.json +0 -0
  160. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/manifest.json +0 -0
  161. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ingolia/readMe.txt.gz +0 -0
  162. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/kaabinejadian/README.md +0 -0
  163. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/kaabinejadian/Results.zip +0 -0
  164. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/kaabinejadian/manifest-v1.json +0 -0
  165. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/kaabinejadian/manifest.json +0 -0
  166. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/kaabinejadian/sdrf.tsv +0 -0
  167. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/README.md +0 -0
  168. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/S3.xlsx +0 -0
  169. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/ensembl107.cdna.fa.gz +0 -0
  170. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/ensembl107.gtf.gz +0 -0
  171. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/human-ensembl107.gtf.gz +0 -0
  172. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/human.bed +0 -0
  173. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/human.pep.fa +0 -0
  174. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/mouse.bed +0 -0
  175. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/ncorf_mammals/mouse.pep.fa +0 -0
  176. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/openprot/README.md +0 -0
  177. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/openprot/ensembl106.cdna.fa.gz +0 -0
  178. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/openprot/ensembl106.gtf.gz +0 -0
  179. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/openprot/mouse-openprot-2_2-altprots+isoforms-min_2_pep-GRCm39.106.bed.zip +0 -0
  180. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/openprot/mouse-openprot-2_2-altprots+isoforms-min_2_pep-GRCm39.106.fasta.zip +0 -0
  181. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/openprot/mouse-openprot-2_2-altprots+isoforms-min_2_pep-GRCm39.106.tsv.zip +0 -0
  182. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/peptideatlas/README.md +0 -0
  183. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/peptideatlas/atlas_build.tsv.zip +0 -0
  184. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/peptideatlas/ensembl.pep.fa.gz +0 -0
  185. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/peptideatlas/manifest.json +0 -0
  186. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/NOTICE.md +0 -0
  187. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/dog/expected.json +0 -0
  188. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/dog/manifest.json +0 -0
  189. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/dog/protein.tsv +0 -0
  190. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/dog/search.fasta +0 -0
  191. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/human/expected.json +0 -0
  192. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/human/manifest.json +0 -0
  193. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/human/protein.tsv +0 -0
  194. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/human/search.fasta +0 -0
  195. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/mouse/expected.json +0 -0
  196. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/mouse/manifest.json +0 -0
  197. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/mouse/protein.tsv +0 -0
  198. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer/mouse/search.fasta +0 -0
  199. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/GSE325522_family.soft.gz +0 -0
  200. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/GSE325523_family.soft.gz +0 -0
  201. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/GSE325525_family.soft.gz +0 -0
  202. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/NOTICE.md +0 -0
  203. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/counts.csv.gz +0 -0
  204. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/dog-annotation.gtf.gz +0 -0
  205. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/dog-expected.json +0 -0
  206. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/dog-manifest.json +0 -0
  207. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/mouse-annotation.gtf.gz +0 -0
  208. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/mouse-expected.json +0 -0
  209. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/mouse-manifest.json +0 -0
  210. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/pfizer_rna/samples.xlsx +0 -0
  211. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/README.md +0 -0
  212. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/canis_lupus_familiaris.json +0 -0
  213. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/context-keys-v0.4.json +0 -0
  214. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/ensembl115.json +0 -0
  215. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/homo_sapiens.json +0 -0
  216. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/mitochondrial.json +0 -0
  217. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/mus_musculus.json +0 -0
  218. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/saccharomyces_cerevisiae.json +0 -0
  219. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/references/uniprot_literature.json +0 -0
  220. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/regions/NOTICE.md +0 -0
  221. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/regions/ingolia.json +0 -0
  222. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/README.md +0 -0
  223. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/SD3.xlsx +0 -0
  224. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/ensembl107.cdna.fa.gz +0 -0
  225. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/ensembl107.gtf.gz +0 -0
  226. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/ensembl107.ncrna.fa.gz +0 -0
  227. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/human-ensembl105.cdna.fa.gz +0 -0
  228. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/human-ensembl105.gtf.gz +0 -0
  229. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/human-ensembl105.ncrna.fa.gz +0 -0
  230. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/worm-ensembl105.cdna.fa.gz +0 -0
  231. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/worm-ensembl105.gtf.gz +0 -0
  232. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/worm-ensembl105.ncrna.fa.gz +0 -0
  233. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/yeast-ensembl115.cdna.fa.gz +0 -0
  234. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/yeast-ensembl115.dna.fa.gz +0 -0
  235. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/yeast-ensembl115.gtf.gz +0 -0
  236. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/zebrafish-ensembl115.cdna.fa.gz +0 -0
  237. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/zebrafish-ensembl115.gtf.gz +0 -0
  238. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/riborf/zebrafish-ensembl115.ncrna.fa.gz +0 -0
  239. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/search_reference/NOTICE.md +0 -0
  240. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/search_reference/dog.fasta +0 -0
  241. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/search_reference/ensembl83-expected.json +0 -0
  242. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/search_reference/ensembl83-human.fasta.gz +0 -0
  243. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/search_reference/expected.json +0 -0
  244. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/README.md +0 -0
  245. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/generate.py +0 -0
  246. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v1.json +0 -0
  247. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v1.sqlite +0 -0
  248. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v2.json +0 -0
  249. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v2.sqlite +0 -0
  250. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v3.json +0 -0
  251. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v3.sqlite +0 -0
  252. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v4.json +0 -0
  253. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/storage/v4.sqlite +0 -0
  254. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/GRCh83.d1.vd1_virus_decoy.txt.gz +0 -0
  255. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/NC_001526.4.gb.gz +0 -0
  256. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/genbank/HBV__X04615.1.gb.gz +0 -0
  257. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/genbank/HPV16__K02718.1.gb.gz +0 -0
  258. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/genbank/HPV35__X74477.1.gb.gz +0 -0
  259. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/genbank/HPV51__M62877.1.gb.gz +0 -0
  260. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/viral/genbank/HPV56__X74483.1.gb.gz +0 -0
  261. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/NOTICE.md +0 -0
  262. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/annotation.gtf.gz +0 -0
  263. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/copies.zip +0 -0
  264. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/expected.json +0 -0
  265. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/manifest.json +0 -0
  266. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/protein.zip +0 -0
  267. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/rna.zip +0 -0
  268. {orfdata-0.37.0 → orfdata-0.38.2}/tests/data/wang/search.fasta.gz +0 -0
  269. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_catalog_registry.py +0 -0
  270. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_copy.py +0 -0
  271. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_cross_reference_pairing.py +0 -0
  272. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_dog_peptides.py +0 -0
  273. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_downloads.py +0 -0
  274. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_ensembl_search_reference.py +0 -0
  275. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_evidence_rules.py +0 -0
  276. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_evidence_summary.py +0 -0
  277. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_genbank.py +0 -0
  278. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_genbank_equivalence.py +0 -0
  279. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_genomes.py +0 -0
  280. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_ingolia.py +0 -0
  281. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_initiation_context.py +0 -0
  282. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_liftover.py +0 -0
  283. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_local_build_queries.py +0 -0
  284. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_measurements.py +0 -0
  285. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_more_species.py +0 -0
  286. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_ncorf_mammals.py +0 -0
  287. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_openprot.py +0 -0
  288. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_orf_cases.py +0 -0
  289. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_orf_gtf.py +0 -0
  290. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_paired_selectors.py +0 -0
  291. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_pairing.py +0 -0
  292. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_pfizer.py +0 -0
  293. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_pfizer_rna.py +0 -0
  294. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_protein_set.py +0 -0
  295. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_proteome.py +0 -0
  296. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_proteome_external.py +0 -0
  297. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_proteome_fasta_tokens.py +0 -0
  298. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_proteome_producer_graph.py +0 -0
  299. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_reference_context.py +0 -0
  300. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_reference_ledger.py +0 -0
  301. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_reference_mapping.py +0 -0
  302. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_reference_orf.py +0 -0
  303. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_reference_table.py +0 -0
  304. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_refseq.py +0 -0
  305. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_region_targets.py +0 -0
  306. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_riborf.py +0 -0
  307. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_search_reference.py +0 -0
  308. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_selectors.py +0 -0
  309. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_storage.py +0 -0
  310. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_uorf_catalog.py +0 -0
  311. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral.py +0 -0
  312. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_bundle.py +0 -0
  313. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_cli.py +0 -0
  314. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_collections.py +0 -0
  315. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_completeness.py +0 -0
  316. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_coverage.py +0 -0
  317. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_initiation.py +0 -0
  318. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_origin_join.py +0 -0
  319. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_sources.py +0 -0
  320. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_viral_subsets.py +0 -0
  321. {orfdata-0.37.0 → orfdata-0.38.2}/tests/test_wang.py +0 -0
  322. {orfdata-0.37.0 → orfdata-0.38.2}/tools/__init__.py +0 -0
  323. {orfdata-0.37.0 → orfdata-0.38.2}/tools/build_gdc_viral_coverage.py +0 -0
  324. {orfdata-0.37.0 → orfdata-0.38.2}/tools/build_hpv16_cds.py +0 -0
  325. {orfdata-0.37.0 → orfdata-0.38.2}/tools/build_reference_ledger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orfdata
3
- Version: 0.37.0
3
+ Version: 0.38.2
4
4
  Summary: Reference proteomes with evidence-backed noncanonical ORFs on PyEnsembl genomes
5
5
  Author: OpenVax
6
6
  License-Expression: Apache-2.0
@@ -281,6 +281,15 @@ other.
281
281
  `source:id`. `catalog.get` and `ExtraORFs.for_orf` accept any of them.
282
282
  - **ID collisions.** When two sources use one ID for different ORFs, both
283
283
  become `source:id`, and the bare ID raises rather than picking one.
284
+ Direct `ORFCatalog(records, metadata)` construction follows the same rule,
285
+ retaining each native record in `members` without merging its evidence.
286
+ IDs must still be unique within a source. If a source or native ID contains
287
+ punctuation that would collide with a generated ID, generated components
288
+ are percent-escaped; native IDs remain available through the source records.
289
+ Use `catalog.get("native-id", source="study")` or
290
+ `orfs.for_orf("native-id", source="study")` for explicit source selection.
291
+ A combined string such as `study:native-id` raises if it also identifies
292
+ another native record; explicit source selection resolves that ambiguity.
284
293
  - **Evidence.** Each source's evidence is kept, and evidence rules see the union:
285
294
  a peptide counts once per sequence. A Ribo-seq study two catalogues label
286
295
  differently counts once when their `ribosome_study_pmids` metadata give it
@@ -71,3 +71,12 @@ must declare table 2, and a yeast one table 3. See
71
71
  products, such as Varcode and Isovar, must translate them with that code.
72
72
  For example, OpenProt's IP_306399 on human MT-ND4 begins ATA and ends AGG. It
73
73
  binds under table 2; table 1 would read those codons as isoleucine and arginine.
74
+
75
+ OpenProt import manifests can declare `processing.translation_tables` by exact
76
+ native transcript ID, for example `{"ENST00000361381.2": 2}` for the qualified
77
+ human IP_306399 row. The declaration belongs to the pinned source/reference
78
+ manifest and is retained in catalogue provenance. Mitochondrial rows require
79
+ such a declaration; unsupported codes and IDs absent from the input fail.
80
+ The importer retains the native coordinate conversion and aggregate MS/TE
81
+ counts. Binding still checks the exact transcript sequence and protein.
82
+ This does not publish a complete human or yeast OpenProt catalogue (#18).
@@ -15,6 +15,7 @@ from dataclasses import asdict, dataclass, replace
15
15
  from importlib.resources import files
16
16
  from pathlib import Path
17
17
  from typing import NamedTuple, Optional
18
+ from urllib.parse import quote
18
19
 
19
20
  from .evidence import EVIDENCE_METHODS as EVIDENCE_METHODS # Re-exported for existing imports.
20
21
  from .evidence import MS_METHODS, evidence_rule, stored_method
@@ -402,25 +403,52 @@ class ORFRecord:
402
403
  }
403
404
 
404
405
 
406
+ def _qualify_colliding_ids(records):
407
+ """Give colliding source records unique catalogue IDs, retaining their native records."""
408
+ records = tuple(records)
409
+ keys = [(r.source, r.orf_id) for r in records]
410
+ if len(set(keys)) != len(keys):
411
+ raise ValueError("Duplicate ORF identifiers within one source")
412
+ names = [r.orf_id for r in records]
413
+ qualified = set()
414
+ while True:
415
+ counts = Counter(names)
416
+ collisions = {i for i, name in enumerate(names) if counts[name] > 1}
417
+ if not collisions:
418
+ break
419
+ # Qualify all participants, including a native ID that equals another
420
+ # record's generated ID. Escaping makes source/ID boundaries unambiguous.
421
+ qualified.update(collisions)
422
+ names = [f"{quote(r.source, safe='')}:{quote(r.orf_id, safe='')}" if i in qualified
423
+ else r.orf_id for i, r in enumerate(records)]
424
+ return tuple(r if name == r.orf_id else replace(
425
+ r, orf_id=name, members=r.members or (r,), lifted_from=None, liftover=None)
426
+ for r, name in zip(records, names))
427
+
428
+
405
429
  class ORFCatalog:
406
430
  """Offline ORF records for one explicitly identified species and assembly."""
407
431
 
408
432
  def __init__(self, records, metadata):
409
- self.records = tuple(records)
433
+ self.records = _qualify_colliding_ids(records)
410
434
  self._metadata = deepcopy(metadata)
411
435
  self.genome_build = metadata["genome_build"]
412
436
  self.taxon_id = metadata["taxon_id"]
413
437
  self.species = metadata["species"]
414
438
  self._by_id = {r.orf_id: r for r in self.records}
415
- if len(self._by_id) != len(self.records):
416
- raise ValueError("Duplicate ORF identifiers")
417
439
  self._aliases = {}
440
+ self._by_source_id = {}
418
441
  for r in self.records:
419
442
  names = {f"{m.source}:{m.orf_id}" for m in r.members or (r,)} | {m.orf_id for m in r.members}
420
443
  # A source accession split by coding path, "IP_1@ENST...", still answers to "IP_1".
421
444
  names |= {m.orf_id.split("@")[0] for m in r.members or (r,) if "@" in m.orf_id}
422
445
  for alias in names - {r.orf_id}:
423
446
  self._aliases.setdefault(alias, []).append(r)
447
+ for member in r.members or (r,):
448
+ for name in {member.orf_id, member.orf_id.split("@")[0]}:
449
+ matches = self._by_source_id.setdefault((member.source, name), [])
450
+ if not any(match is r for match in matches):
451
+ matches.append(r)
424
452
  for r in self.records:
425
453
  if r.genome_build != self.genome_build or r.strand not in ("+", "-"):
426
454
  raise ValueError(f"Invalid assembly or strand for {r.orf_id}")
@@ -503,14 +531,17 @@ class ORFCatalog:
503
531
  """Return a copy of dataset version, sources, scope and provenance."""
504
532
  return deepcopy(self._metadata)
505
533
 
506
- def get(self, orf_id):
534
+ def get(self, orf_id, *, source=None):
507
535
  """Return the ORF with this ID, bare or as ``source:id``; unknown IDs raise KeyError.
508
536
 
509
537
  In a merged catalogue every source's ID finds its ORF. A bare ID that
510
538
  two sources use for different ORFs raises rather than choosing one.
539
+ ``source`` selects a native ID explicitly, including when a source or
540
+ native ID contains a colon and the combined string is ambiguous.
511
541
  """
512
- found = list(dict.fromkeys(
513
- ([self._by_id[orf_id]] if orf_id in self._by_id else []) + list(self._aliases.get(orf_id, ()))))
542
+ matches = (self._by_source_id.get((source, orf_id), ()) if source is not None else
543
+ ([self._by_id[orf_id]] if orf_id in self._by_id else []) + list(self._aliases.get(orf_id, ())))
544
+ found = list({id(record): record for record in matches}.values())
514
545
  if len(found) > 1:
515
546
  raise ValueError(f"{orf_id} names several ORFs: {', '.join(r.orf_id for r in found)}")
516
547
  if not found:
@@ -780,21 +811,20 @@ def merge_catalogs(catalogs):
780
811
  groups.append(group)
781
812
  group[0].add(origin[id(record)])
782
813
  group[1].append(record)
783
- uses = Counter(orf_id for _, members in groups for orf_id in {m.orf_id for m in members})
784
814
  records = []
785
815
  for _, members in groups:
786
816
  primary = members[0]
787
- orf_id = primary.orf_id if uses[primary.orf_id] == 1 else f"{primary.source}:{primary.orf_id}"
788
- if len(members) == 1 and orf_id == primary.orf_id:
817
+ if len(members) == 1:
789
818
  records.append(primary)
790
819
  continue
791
820
  pinned = {None if m.reference_context is None else m.reference_context.key for m in members}
792
821
  records.append(replace(
793
822
  # The merged ORF is no one source's lift; each member keeps its own lift provenance.
794
- primary, orf_id=orf_id, members=tuple(members), lifted_from=None, liftover=None,
823
+ primary, members=tuple(members), lifted_from=None, liftover=None,
795
824
  initiation_context=_shared_context(primary, members),
796
825
  # Sources pinned to different annotations of one assembly leave the ORF unpinned.
797
826
  reference_context=primary.reference_context if len(pinned) == 1 else None, **_union(members, study)))
827
+ records = _qualify_colliding_ids(records)
798
828
  paths = {}
799
829
  for record in records:
800
830
  paths.setdefault(_path_key(record), set()).add((_merge_key(record), record.orf_id))
@@ -779,17 +779,20 @@ class ExtraORFs:
779
779
  found.append(orf)
780
780
  return tuple(found)
781
781
 
782
- def for_orf(self, orf_id):
782
+ def for_orf(self, orf_id, *, source=None):
783
783
  """Every transcript placement of one ORF, the source's own transcript first.
784
784
 
785
785
  After merging catalogues, any source's ID finds the ORF, bare or as
786
786
  ``source:id``; a bare ID two sources use for different ORFs raises.
787
+ Pass ``source`` to select the native ID in one source explicitly.
787
788
  """
788
789
  if self.catalog is not None:
789
790
  try:
790
- orf_id = self.catalog.get(orf_id).orf_id
791
+ orf_id = self.catalog.get(orf_id, source=source).orf_id
791
792
  except KeyError:
792
793
  return ()
794
+ elif source is not None:
795
+ raise ValueError("Source-qualified lookup requires the source catalogue")
793
796
  return tuple(sorted((o for o in self.orfs if o.orf_id == orf_id),
794
797
  key=lambda o: (not o.on_source_transcript, _versioned(o.transcript))))
795
798
 
@@ -31,6 +31,7 @@ from ..catalog import ORFCatalog, ORFEvidence, ORFRecord
31
31
  from ..evidence_summary import EvidenceSummary
32
32
  from ..model import ORFModel
33
33
  from ..reference import ScopedTarget
34
+ from ..sequence import genetic_code
34
35
 
35
36
  MS_DEFINITION = "Sum of study-specific unique-peptide counts; not global peptide uniqueness."
36
37
  TE_DEFINITION = "Count of studies reporting one or more significant translation detections."
@@ -83,6 +84,9 @@ def _summary(reference, accession, protein, method, metric, value, definition, u
83
84
  def import_orfs(inputs, output, manifest):
84
85
  """Write the catalogue ``manifest`` describes from its OpenProt TSV, BED and FASTA archives."""
85
86
  processing = manifest.processing
87
+ translation_tables = processing.get("translation_tables", {})
88
+ for code in translation_tables.values():
89
+ genetic_code(code) # Unsupported source declarations must never fall back.
86
90
  members = processing["members"]
87
91
  rows = list(csv.DictReader(io.StringIO(_member(inputs["tsv"], members["tsv"])), delimiter="\t"))
88
92
  bed = [line.split("\t") for line in _member(inputs["bed"], members["bed"]).splitlines() if line.strip()]
@@ -92,13 +96,16 @@ def import_orfs(inputs, output, manifest):
92
96
  tsv = next(s for s in manifest.sources if s.asset_id == "tsv")
93
97
  if len(bed) != len(rows):
94
98
  raise ValueError("OpenProt TSV and BED row counts disagree")
99
+ unknown = set(translation_tables) - {row["transcript accession"] for row in rows}
100
+ if unknown:
101
+ raise ValueError("OpenProt translation tables name absent source transcripts: %s" % sorted(unknown))
95
102
 
96
103
  paths, unresolved, scores = defaultdict(dict), [], {}
97
104
  for line, (row, region) in enumerate(zip(rows, bed), start=2):
98
105
  accession, transcript = row["protein accession"], row["transcript accession"]
99
- if row["chr"] in ("MT", "M"): # Needs table 2 and its starts, e.g. human IP_306399 begins ATA (#55).
106
+ if row["chr"] in ("MT", "M") and transcript not in translation_tables:
100
107
  raise ValueError(f"OpenProt TSV line {line} ({accession}) is mitochondrial; the importer handles "
101
- "nuclear ORFs only")
108
+ "it only with an explicit source-transcript translation table")
102
109
  length = int(row["protein length (a.a.)"])
103
110
  blocks = _blocks(region)
104
111
  protein = proteins.get(accession)
@@ -116,7 +123,7 @@ def import_orfs(inputs, output, manifest):
116
123
  if not transcript.startswith(processing["transcript_prefix"]):
117
124
  unresolved.append(dict(protein=accession, transcript=transcript, reason=processing["unresolved_reason"]))
118
125
  continue
119
- key = (row["chr"], region[5], blocks)
126
+ key = (row["chr"], region[5], blocks, translation_tables.get(transcript, 1))
120
127
  found = paths[accession].setdefault(key, dict(protein=protein, genes={}, types=set()))
121
128
  found["genes"][transcript] = row["gene symbol"].split(".")[0] # Overlapping genes can share a path.
122
129
  found["types"].add(row["protein type"])
@@ -124,7 +131,7 @@ def import_orfs(inputs, output, manifest):
124
131
  records = []
125
132
  for accession, found in sorted(paths.items()):
126
133
  ms, te = scores[accession]
127
- for (contig, strand, blocks), path in sorted(found.items(), key=lambda item: min(item[1]["genes"])):
134
+ for (contig, strand, blocks, table), path in sorted(found.items(), key=lambda item: min(item[1]["genes"])):
128
135
  transcript = min(path["genes"])
129
136
  if len(path["types"]) != 1:
130
137
  raise ValueError(f"OpenProt gives {accession} several protein types")
@@ -132,7 +139,7 @@ def import_orfs(inputs, output, manifest):
132
139
  model = ORFModel(accession if len(found) == 1 else f"{accession}@{transcript}", transcript,
133
140
  path["genes"][transcript], "", contig, strand, blocks, protein, path["types"].pop(),
134
141
  record_reference.genome_build, record_reference.taxon_id, record_reference.species,
135
- source="openprot", reference_context=record_reference)
142
+ source="openprot", reference_context=record_reference, translation_table=table)
136
143
  summaries = tuple(_summary(summary_reference, accession, protein, *values, tsv.url, tsv.sha256) for values in (
137
144
  ("ms", "MS score", ms, MS_DEFINITION), ("ribosome", "TE Translation Event score", te, TE_DEFINITION)))
138
145
  records.append(ORFRecord.from_model(model, ORFEvidence(summaries=summaries)))
@@ -0,0 +1 @@
1
+ __version__ = "0.38.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orfdata
3
- Version: 0.37.0
3
+ Version: 0.38.2
4
4
  Summary: Reference proteomes with evidence-backed noncanonical ORFs on PyEnsembl genomes
5
5
  Author: OpenVax
6
6
  License-Expression: Apache-2.0
@@ -118,6 +118,7 @@ tests/conftest.py
118
118
  tests/test_catalog_registry.py
119
119
  tests/test_copy.py
120
120
  tests/test_cross_reference_pairing.py
121
+ tests/test_dog_ncorf_search.py
121
122
  tests/test_dog_peptides.py
122
123
  tests/test_downloads.py
123
124
  tests/test_ensembl_search_reference.py
@@ -0,0 +1,62 @@
1
+ import importlib.util
2
+ import os
3
+ import subprocess
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ import numpy as np
8
+ import pytest
9
+
10
+ SCRIPTS = Path(__file__).parents[1] / "scripts" / "experimental" / "dog-ncorf-search"
11
+ pytestmark = pytest.mark.skipif(not SCRIPTS.is_dir(), reason="experimental scripts are not in the sdist")
12
+
13
+
14
+ def _load(name):
15
+ spec = importlib.util.spec_from_file_location(name, SCRIPTS / f"{name}.py")
16
+ module = importlib.util.module_from_spec(spec)
17
+ spec.loader.exec_module(module)
18
+ return module
19
+
20
+
21
+ def test_dog_search_qvalues_include_complete_score_ties():
22
+ qvalues = _load("fdr").qvalues
23
+ scores = np.array([10.0, 9.0, 9.0, 8.0])
24
+ decoys = np.array([False, False, True, True])
25
+ expected = np.array([0.0, 0.5, 0.5, 1.0])
26
+ np.testing.assert_allclose(qvalues(scores, decoys), expected)
27
+ np.testing.assert_allclose(qvalues(scores[[0, 2, 1, 3]], decoys[[0, 2, 1, 3]]), expected)
28
+
29
+
30
+ def test_dog_search_normalizes_non_blosum_residues():
31
+ normalize = _load("homology").blosum62_sequence
32
+ assert normalize("ACUOJX*") == "ACCKXX*"
33
+ with pytest.raises(ValueError, match="unsupported"):
34
+ normalize("AC-")
35
+
36
+
37
+ def test_dog_search_driver_fails_when_a_run_has_a_failure_marker(tmp_path):
38
+ work = tmp_path / "search"
39
+ (work / "db").mkdir(parents=True)
40
+ (work / "work").mkdir()
41
+ (work / "db" / "dog_db.fasta").write_text(">CANON000000\nPEPTIDE\n")
42
+ (work / "runs.tsv").write_text(
43
+ "failed\tfixture\thttps://example.invalid/archive.zip\tfailed.mzML\t1\t1\n")
44
+ (work / "work" / "failed.fetch_failed").write_text("intentional test marker\n")
45
+
46
+ sage = tmp_path / "sage"
47
+ sage.write_text("#!/bin/sh\n[ \"${1:-}\" = --version ] && echo 'sage test'\n")
48
+ sage.chmod(0o755)
49
+ python = tmp_path / "python"
50
+ python.write_text(
51
+ f"#!/bin/sh\n"
52
+ "case \"$*\" in\n"
53
+ " *'import pandas, pyarrow, inflate64'*) exit 0;;\n"
54
+ "esac\n"
55
+ f"exec {sys.executable} \"$@\"\n")
56
+ python.chmod(0o755)
57
+ env = dict(os.environ, SAGE=str(sage), PYTHON=str(python), MIN_FREE_GB="0")
58
+ result = subprocess.run(
59
+ ["bash", str(SCRIPTS / "driver.sh"), str(work)], env=env,
60
+ capture_output=True, text=True, check=False)
61
+ assert result.returncode == 1
62
+ assert "INCOMPLETE searched=0 failed=1" in result.stdout
@@ -1,6 +1,9 @@
1
1
  """Declared NCBI genetic codes bind native mitochondrial ORFs and fail closed otherwise."""
2
2
 
3
+ import csv
4
+ import io
3
5
  import json
6
+ import zipfile
4
7
  from dataclasses import replace
5
8
  from pathlib import Path
6
9
 
@@ -122,3 +125,54 @@ def test_codon_annotation_uses_the_declared_code(table, expected):
122
125
  assert codon["alternate_codon"] == "ATG" and codon["alternate_codon_translation"] == "M"
123
126
  with pytest.raises(ValueError, match="translation table"):
124
127
  replace(orf, translation_table=4).annotate_initiation_snv(103, "C", "A", genome_build="R64-1-1")
128
+
129
+
130
+ @pytest.mark.parametrize("native", FIXTURES[:1], ids=[FIXTURES[0]["name"]], indirect=True)
131
+ def test_native_openprot_import_accepts_only_a_declared_supported_code(native, tmp_path):
132
+ """Replay the pinned native row; archive wrappers/BED serialization are fixture-only."""
133
+ from orfdata import CatalogRegistry, load_catalog
134
+ from orfdata.sources.openprot import import_orfs
135
+
136
+ example, original, transcript = native
137
+ row = example["native"]
138
+ tsv = io.StringIO()
139
+ writer = csv.DictWriter(tsv, fieldnames=list(row), delimiter="\t", lineterminator="\n")
140
+ writer.writeheader()
141
+ writer.writerow(row)
142
+ a, b = original.coding_blocks[0]
143
+ bed = f"chrMT\t{a - 1}\t{b}\t{original.orf_id}\t0\t+\t{a - 1}\t{b}\t0\t1\t{b - a + 1}\t0\n"
144
+ contents = dict(tsv=tsv.getvalue(), bed=bed,
145
+ fasta=example["native_fasta_header"] + "\n" + original.protein_sequence + "\n")
146
+ inputs = {}
147
+ for kind, text in contents.items():
148
+ path = tmp_path / f"fixture.{kind}.zip"
149
+ with zipfile.ZipFile(path, "w") as archive:
150
+ archive.writestr(f"fixture.{kind}", text)
151
+ inputs[kind] = path
152
+ base = CatalogRegistry().info("openprot-mouse")
153
+ summary = example["summaries"][0]
154
+ manifest = replace(base, catalog_id="openprot-human-fixture",
155
+ references=(original.reference_context,
156
+ ReferenceContext(**summary["target"]["reference"])),
157
+ sources=tuple(replace(s, url=summary["source_url"], sha256=summary["source_sha256"])
158
+ if s.asset_id == "tsv" else s for s in base.sources),
159
+ processing=dict(base.processing, transcript_prefix="ENST",
160
+ members={kind: f"fixture.{kind}" for kind in contents},
161
+ translation_tables={original.transcript_id: 2}),
162
+ coverage=dict(records=1, source_rows=1, resolved_rows=1, unresolved_rows=0,
163
+ accessions=1, resolved_accessions=1))
164
+ output = tmp_path / "catalog.json.gz"
165
+ import_orfs(inputs, output, manifest)
166
+ imported = load_catalog(output).get(original.orf_id)
167
+ assert imported.translation_table == 2
168
+ assert imported.coding_blocks == original.coding_blocks
169
+ assert imported.bind(transcript).protein_sequence == original.protein_sequence
170
+ assert {s.metric: s.value for s in imported.summaries} == {
171
+ "MS score": 2, "TE Translation Event score": 0}
172
+ assert imported.summaries[0].source_sha256 == summary["source_sha256"]
173
+ for declarations, error in [({}, "is mitochondrial"),
174
+ ({original.transcript_id: 4}, "translation table"),
175
+ ({"missing-transcript": 2}, "absent source transcripts")]:
176
+ with pytest.raises(ValueError, match=error):
177
+ import_orfs(inputs, output, replace(manifest, processing=dict(
178
+ manifest.processing, translation_tables=declarations)))
@@ -62,6 +62,64 @@ def test_one_id_for_different_orfs_is_qualified_and_never_guessed():
62
62
  merged.get("missing")
63
63
 
64
64
 
65
+ def test_direct_catalogue_preserves_colliding_source_records_and_lookup(tmp_path):
66
+ first = replace(orf("shared", ribosome_studies=("study-a",)), source="a")
67
+ second = replace(orf("shared", ribosome_studies=("study-b",)), source="b")
68
+ catalog = ORFCatalog([first, second], metadata("combined-v1", "combined"))
69
+ assert [r.orf_id for r in catalog.records] == ["a:shared", "b:shared"]
70
+ for original in (first, second):
71
+ record = catalog.get("shared", source=original.source)
72
+ assert record.members == (original,)
73
+ assert catalog.get(f"{original.source}:shared") is record
74
+ assert record.ribosome_studies == original.ribosome_studies
75
+ with pytest.raises(ValueError, match="shared names several ORFs"):
76
+ catalog.get("shared")
77
+ with pytest.raises(KeyError):
78
+ catalog.get("shared", source="absent")
79
+ path = tmp_path / "collisions.json.gz"
80
+ catalog.save(path)
81
+ loaded = load_catalog(path)
82
+ assert loaded.to_dict() == catalog.to_dict()
83
+ assert loaded.get("shared", source="a").members == (first,)
84
+ with pytest.raises(ValueError, match="names several ORFs"):
85
+ loaded.get("shared")
86
+
87
+
88
+ def test_source_qualified_ids_cannot_overwrite_native_ids_or_delimiter_collisions():
89
+ records = [replace(orf(identifier), source=source) for source, identifier in (
90
+ ("a", "x"), ("b", "x"), ("a", "a:x"), ("a:b", "c"), ("a", "b:c"))]
91
+ catalog = ORFCatalog(records, metadata("combined-v1", "combined"))
92
+ assert len({r.orf_id for r in catalog.records}) == len(records)
93
+ for original in records:
94
+ resolved = catalog.get(original.orf_id, source=original.source)
95
+ assert original in (resolved.members or (resolved,))
96
+ for ambiguous in ("x", "a:x", "a:b:c"):
97
+ with pytest.raises(ValueError, match="names several ORFs"):
98
+ catalog.get(ambiguous)
99
+
100
+
101
+ @pytest.mark.parametrize("changed", [False, True])
102
+ def test_duplicate_ids_within_one_source_still_raise(changed):
103
+ original = orf("same")
104
+ other = replace(original, protein_sequence="MKPA") if changed else original
105
+ with pytest.raises(ValueError, match="Duplicate ORF identifiers"):
106
+ ORFCatalog([original, other], metadata("fixture-v1", "synthetic"))
107
+
108
+
109
+ def test_direct_collisions_keep_distinct_placements_and_proteome_records(genome): # noqa: F811
110
+ records = [replace(orf("shared"), source="a"),
111
+ replace(orf("shared", blocks=((218, 226),), protein="MK"), source="b")]
112
+ catalog = ORFCatalog(records, metadata("combined-v1", "combined"))
113
+ found = extra_orfs(genome, catalog=catalog)
114
+ assert {o.protein_sequence for o in found.for_orf("shared", source="a")} == {"MKPG"}
115
+ assert {o.protein_sequence for o in found.for_orf("shared", source="b")} == {"MK"}
116
+ with pytest.raises(ValueError, match="names several ORFs"):
117
+ found.for_orf("shared")
118
+ proteins = Proteome.from_genome(genome).with_extra_orfs(None, catalog=catalog)
119
+ assert {(p.accession, p.sequence) for p in proteins if p.kind == "extra_orf"} == {
120
+ ("a:shared", "MKPG"), ("b:shared", "MK")}
121
+
122
+
65
123
  def test_incompatible_catalogues_are_not_merged():
66
124
  first = make_catalog()
67
125
  assert merge_catalogs([first]) is first
@@ -1 +0,0 @@
1
- __version__ = "0.37.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes