openprotein-python 0.10.1__tar.gz → 0.11.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.
Files changed (203) hide show
  1. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/.gitignore +3 -0
  2. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/PKG-INFO +1 -1
  3. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/poet.py +29 -11
  4. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/poet2.py +12 -0
  5. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/boltz.py +112 -28
  6. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/common.py +13 -14
  7. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/molecules/__init__.py +2 -1
  8. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/molecules/complex.py +38 -3
  9. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/molecules/protein.py +27 -0
  10. openprotein_python-0.11.0/openprotein/molecules/template.py +122 -0
  11. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/utils/chain_id.py +4 -1
  12. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/LICENSE.txt +0 -0
  13. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/README.md +0 -0
  14. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/__init__.py +0 -0
  15. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/_version.py +0 -0
  16. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/align/__init__.py +0 -0
  17. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/align/align.py +0 -0
  18. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/align/api.py +0 -0
  19. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/align/future.py +0 -0
  20. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/align/msa.py +0 -0
  21. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/align/schemas.py +0 -0
  22. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/__init__.py +0 -0
  23. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/align.py +0 -0
  24. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/assaydata.py +0 -0
  25. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/deprecated/__init__.py +0 -0
  26. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/deprecated/design.py +0 -0
  27. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/deprecated/poet.py +0 -0
  28. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/deprecated/predict.py +0 -0
  29. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/deprecated/train.py +0 -0
  30. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/design.py +0 -0
  31. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/designer.py +0 -0
  32. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/embedding.py +0 -0
  33. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/error.py +0 -0
  34. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/fold.py +0 -0
  35. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/job.py +0 -0
  36. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/predict.py +0 -0
  37. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/predictor.py +0 -0
  38. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/prompt.py +0 -0
  39. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/svd.py +0 -0
  40. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/train.py +0 -0
  41. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/api/umap.py +0 -0
  42. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/__init__.py +0 -0
  43. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/deprecated.py +0 -0
  44. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/__init__.py +0 -0
  45. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/align/__init__.py +0 -0
  46. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/align/base.py +0 -0
  47. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/align/msa.py +0 -0
  48. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/align/prompt.py +0 -0
  49. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/assaydata.py +0 -0
  50. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/deprecated/__init__.py +0 -0
  51. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/deprecated/design.py +0 -0
  52. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/deprecated/poet.py +0 -0
  53. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/deprecated/predict.py +0 -0
  54. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/deprecated/train.py +0 -0
  55. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/design.py +0 -0
  56. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/designer.py +0 -0
  57. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/__init__.py +0 -0
  58. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/base.py +0 -0
  59. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/esm.py +0 -0
  60. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/future.py +0 -0
  61. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/openprotein.py +0 -0
  62. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/poet.py +0 -0
  63. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/poet2.py +0 -0
  64. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/embeddings/test.py +0 -0
  65. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/fold/__init__.py +0 -0
  66. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/fold/alphafold2.py +0 -0
  67. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/fold/base.py +0 -0
  68. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/fold/boltz.py +0 -0
  69. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/fold/esmfold.py +0 -0
  70. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/fold/future.py +0 -0
  71. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/futures.py +0 -0
  72. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/predict.py +0 -0
  73. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/predictor/__init__.py +0 -0
  74. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/predictor/predict.py +0 -0
  75. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/predictor/predictor.py +0 -0
  76. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/predictor/validate.py +0 -0
  77. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/prompt.py +0 -0
  78. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/svd.py +0 -0
  79. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/train.py +0 -0
  80. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/models/umap.py +0 -0
  81. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/__init__.py +0 -0
  82. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/align.py +0 -0
  83. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/assaydata.py +0 -0
  84. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/deprecated/__init__.py +0 -0
  85. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/deprecated/design.py +0 -0
  86. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/deprecated/predict.py +0 -0
  87. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/deprecated/train.py +0 -0
  88. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/design.py +0 -0
  89. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/designer.py +0 -0
  90. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/embeddings.py +0 -0
  91. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/fold.py +0 -0
  92. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/job.py +0 -0
  93. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/predict.py +0 -0
  94. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/predictor.py +0 -0
  95. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/prompt.py +0 -0
  96. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/svd.py +0 -0
  97. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/train.py +0 -0
  98. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/app/services/umap.py +0 -0
  99. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/base.py +0 -0
  100. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/chains.py +0 -0
  101. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/common/__init__.py +0 -0
  102. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/common/features.py +0 -0
  103. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/common/model_metadata.py +0 -0
  104. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/common/reduction.py +0 -0
  105. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/common/residue_contants.py +0 -0
  106. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/config.py +0 -0
  107. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/csv.py +0 -0
  108. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/data/__init__.py +0 -0
  109. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/data/api.py +0 -0
  110. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/data/assaydataset.py +0 -0
  111. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/data/data.py +0 -0
  112. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/data/schemas.py +0 -0
  113. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/design/__init__.py +0 -0
  114. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/design/api.py +0 -0
  115. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/design/design.py +0 -0
  116. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/design/future.py +0 -0
  117. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/design/schemas.py +0 -0
  118. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/__init__.py +0 -0
  119. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/api.py +0 -0
  120. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/embeddings.py +0 -0
  121. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/esm.py +0 -0
  122. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/future.py +0 -0
  123. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/models.py +0 -0
  124. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/openprotein.py +0 -0
  125. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/embeddings/schemas.py +0 -0
  126. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/errors.py +0 -0
  127. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fasta.py +0 -0
  128. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/__init__.py +0 -0
  129. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/alphafold2.py +0 -0
  130. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/api.py +0 -0
  131. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/complex.py +0 -0
  132. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/esmfold.py +0 -0
  133. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/fold.py +0 -0
  134. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/future.py +0 -0
  135. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/minifold.py +0 -0
  136. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/models.py +0 -0
  137. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/rosettafold3.py +0 -0
  138. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/fold/schemas.py +0 -0
  139. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/jobs/__init__.py +0 -0
  140. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/jobs/api.py +0 -0
  141. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/jobs/futures.py +0 -0
  142. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/jobs/jobs.py +0 -0
  143. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/jobs/schemas.py +0 -0
  144. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/__init__.py +0 -0
  145. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/base.py +0 -0
  146. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/foundation/boltzgen.py +0 -0
  147. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/foundation/boltzgen_schema.py +0 -0
  148. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/foundation/proteinmpnn.py +0 -0
  149. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/foundation/rfdiffusion.py +0 -0
  150. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/models.py +0 -0
  151. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/models/structure_generation.py +0 -0
  152. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/molecules/chains.py +0 -0
  153. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/molecules/structure.py +0 -0
  154. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/__init__.py +0 -0
  155. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/api.py +0 -0
  156. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/models.py +0 -0
  157. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/prediction.py +0 -0
  158. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/predictor.py +0 -0
  159. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/schemas.py +0 -0
  160. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/predictor/validate.py +0 -0
  161. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/prompt/__init__.py +0 -0
  162. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/prompt/api.py +0 -0
  163. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/prompt/models.py +0 -0
  164. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/prompt/prompt.py +0 -0
  165. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/prompt/schemas.py +0 -0
  166. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/protein.py +0 -0
  167. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/scaffolds.py +0 -0
  168. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/__init__.py +0 -0
  169. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/align.py +0 -0
  170. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/assaydata.py +0 -0
  171. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/deprecated/__init__.py +0 -0
  172. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/deprecated/design.py +0 -0
  173. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/deprecated/poet.py +0 -0
  174. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/deprecated/predict.py +0 -0
  175. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/deprecated/train.py +0 -0
  176. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/design.py +0 -0
  177. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/designer.py +0 -0
  178. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/embeddings.py +0 -0
  179. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/features.py +0 -0
  180. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/fold.py +0 -0
  181. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/job.py +0 -0
  182. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/predict.py +0 -0
  183. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/predictor.py +0 -0
  184. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/prompt.py +0 -0
  185. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/svd.py +0 -0
  186. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/train.py +0 -0
  187. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/schemas/umap.py +0 -0
  188. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/svd/__init__.py +0 -0
  189. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/svd/api.py +0 -0
  190. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/svd/models.py +0 -0
  191. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/svd/schemas.py +0 -0
  192. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/svd/svd.py +0 -0
  193. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/umap/__init__.py +0 -0
  194. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/umap/api.py +0 -0
  195. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/umap/models.py +0 -0
  196. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/umap/schemas.py +0 -0
  197. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/umap/umap.py +0 -0
  198. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/utils/__init__.py +0 -0
  199. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/utils/cif.py +0 -0
  200. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/utils/numpy.py +0 -0
  201. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/utils/sequence.py +0 -0
  202. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/openprotein/utils/uuid.py +0 -0
  203. {openprotein_python-0.10.1 → openprotein_python-0.11.0}/pyproject.toml +0 -0
@@ -367,3 +367,6 @@ __marimo__/
367
367
 
368
368
  .envrc
369
369
  /.direnv/
370
+
371
+ scratch.org
372
+ gptel
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openprotein-python
3
- Version: 0.10.1
3
+ Version: 0.11.0
4
4
  Summary: OpenProtein Python interface.
5
5
  Author-email: Mark Gee <markgee@ne47.bio>, "Timothy Truong Jr." <ttruong@ne47.bio>, Tristan Bepler <tbepler@ne47.bio>
6
6
  License-Expression: MIT
@@ -3,7 +3,7 @@
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from openprotein.base import APISession
6
- from openprotein.common import ModelMetadata, ReductionType
6
+ from openprotein.common import ModelMetadata, Reduction, ReductionType
7
7
  from openprotein.data import AssayDataset, AssayMetadata
8
8
  from openprotein.prompt import Prompt
9
9
 
@@ -51,9 +51,9 @@ class PoETModel(EmbeddingModel):
51
51
 
52
52
  def embed(
53
53
  self,
54
- sequences: list[bytes],
55
- prompt: str | Prompt | None = None,
54
+ sequences: list[bytes] | list[str],
56
55
  reduction: ReductionType | None = ReductionType.MEAN,
56
+ prompt: str | Prompt | None = None,
57
57
  **kwargs,
58
58
  ) -> EmbeddingsResultFuture:
59
59
  """
@@ -74,6 +74,12 @@ class PoETModel(EmbeddingModel):
74
74
  -------
75
75
  EmbeddingsResultFuture
76
76
  Future object that returns the embeddings of the submitted sequences.
77
+
78
+ Note: The embeddings for PoET can have an extra first dimension if using ensemble
79
+ prompts, where the first dimension is the number of replicates in the ensemble
80
+ prompt. i.e. the shape is ``(N, L, D)`` if ``N`` > 1 else ``(L, D)`` where ``N`` is
81
+ the number of replicates in the prompt, ``L`` is the length of the sequence, ``D`` is
82
+ the dimensions of the ensemble.
77
83
  """
78
84
  if prompt is None:
79
85
  prompt_id = None
@@ -88,7 +94,7 @@ class PoETModel(EmbeddingModel):
88
94
 
89
95
  def logits(
90
96
  self,
91
- sequences: list[bytes],
97
+ sequences: list[bytes] | list[str],
92
98
  prompt: str | Prompt | None = None,
93
99
  **kwargs,
94
100
  ) -> EmbeddingsResultFuture:
@@ -108,6 +114,12 @@ class PoETModel(EmbeddingModel):
108
114
  -------
109
115
  EmbeddingsResultFuture
110
116
  Future object that returns the logits of the submitted sequences.
117
+
118
+ Note: The logits for PoET can have an extra first dimension if using ensemble
119
+ prompts, where the first dimension is the number of replicates in the ensemble
120
+ prompt. i.e. the shape is ``(N, L, D)`` if ``N`` > 1 else ``(L, D)`` where ``N`` is
121
+ the number of replicates in the prompt, ``L`` is the length of the sequence, ``D`` is
122
+ the size of the vocabulary.
111
123
  """
112
124
  if prompt is None:
113
125
  prompt_id = None
@@ -317,11 +329,11 @@ class PoETModel(EmbeddingModel):
317
329
 
318
330
  def fit_svd(
319
331
  self,
320
- prompt: str | Prompt | None = None,
321
332
  sequences: list[bytes] | list[str] | None = None,
322
- assay: AssayDataset | None = None,
333
+ assay: AssayDataset | AssayMetadata | None = None,
323
334
  n_components: int = 1024,
324
- reduction: ReductionType | None = None,
335
+ reduction: Reduction | ReductionType | None = None,
336
+ prompt: str | Prompt | None = None,
325
337
  **kwargs,
326
338
  ) -> "SVDModel":
327
339
  """
@@ -365,11 +377,11 @@ class PoETModel(EmbeddingModel):
365
377
 
366
378
  def fit_umap(
367
379
  self,
368
- prompt: str | Prompt | None = None,
369
380
  sequences: list[bytes] | list[str] | None = None,
370
- assay: AssayDataset | None = None,
381
+ assay: AssayDataset | AssayMetadata | None = None,
371
382
  n_components: int = 2,
372
- reduction: ReductionType = ReductionType.MEAN,
383
+ reduction: Reduction | ReductionType = ReductionType.MEAN,
384
+ prompt: str | Prompt | None = None,
373
385
  **kwargs,
374
386
  ) -> "UMAPModel":
375
387
  """
@@ -413,8 +425,11 @@ class PoETModel(EmbeddingModel):
413
425
 
414
426
  def fit_gp(
415
427
  self,
416
- assay: AssayMetadata | AssayDataset | str,
428
+ assay: AssayDataset | AssayMetadata | str,
417
429
  properties: list[str],
430
+ reduction: ReductionType,
431
+ name: str | None = None,
432
+ description: str | None = None,
418
433
  prompt: str | Prompt | None = None,
419
434
  **kwargs,
420
435
  ) -> "PredictorModel":
@@ -444,6 +459,9 @@ class PoETModel(EmbeddingModel):
444
459
  return super().fit_gp(
445
460
  assay=assay,
446
461
  properties=properties,
462
+ reduction=reduction,
463
+ name=name,
464
+ description=description,
447
465
  prompt_id=prompt_id,
448
466
  **kwargs,
449
467
  )
@@ -86,6 +86,12 @@ class PoET2Model(PoETModel, EmbeddingModel):
86
86
  -------
87
87
  EmbeddingsResultFuture
88
88
  A future object that returns the embeddings of the submitted sequences.
89
+
90
+ Note: The embeddings for PoET can have an extra first dimension if using ensemble
91
+ prompts, where the first dimension is the number of replicates in the ensemble
92
+ prompt. i.e. the shape is ``(N, L, D)`` if ``N`` > 1 else ``(L, D)`` where ``N`` is
93
+ the number of replicates in the prompt, ``L`` is the length of the sequence, ``D`` is
94
+ the dimensions of the ensemble.
89
95
  """
90
96
  prompt_api = getattr(self.session, "prompt", None)
91
97
  assert isinstance(prompt_api, PromptAPI)
@@ -127,6 +133,12 @@ class PoET2Model(PoETModel, EmbeddingModel):
127
133
  -------
128
134
  EmbeddingsResultFuture
129
135
  A future object that returns the logits of the submitted sequences.
136
+
137
+ Note: The logits for PoET can have an extra first dimension if using ensemble
138
+ prompts, where the first dimension is the number of replicates in the ensemble
139
+ prompt. i.e. the shape is ``(N, L, D)`` if ``N`` > 1 else ``(L, D)`` where ``N`` is
140
+ the number of replicates in the prompt, ``L`` is the length of the sequence, ``D`` is
141
+ the size of the vocabulary.
130
142
  """
131
143
  prompt_api = getattr(self.session, "prompt", None)
132
144
  assert isinstance(prompt_api, PromptAPI)
@@ -1,7 +1,7 @@
1
1
  """Community-based Boltz models for complex structure prediction with ligands/dna/rna."""
2
2
 
3
3
  import warnings
4
- from typing import Sequence
4
+ from typing import Mapping, Sequence, cast
5
5
 
6
6
  from pydantic import BaseModel, Field, TypeAdapter, model_validator
7
7
 
@@ -10,6 +10,8 @@ from openprotein.base import APISession
10
10
  from openprotein.common import ModelMetadata
11
11
  from openprotein.fold.common import normalize_inputs, serialize_input
12
12
  from openprotein.molecules import Complex, Ligand, Protein
13
+ from openprotein.molecules.template import Template
14
+ from openprotein.prompt import PromptAPI
13
15
 
14
16
  from . import api
15
17
  from .complex import id_generator
@@ -40,7 +42,7 @@ class BoltzModel(FoldModel):
40
42
  num_steps: int = 200,
41
43
  step_scale: float = 1.638,
42
44
  use_potentials: bool = False,
43
- constraints: list[dict] | None = None,
45
+ constraints: Sequence[Mapping] | None = None,
44
46
  **kwargs,
45
47
  ) -> FoldResultFuture:
46
48
  """
@@ -83,19 +85,9 @@ class BoltzModel(FoldModel):
83
85
 
84
86
  # build the normalized_models from msa
85
87
  if isinstance(sequences, MSAFuture):
86
- id_gen = id_generator()
87
- align_api = getattr(self.session, "align", None)
88
- assert isinstance(align_api, AlignAPI)
89
- msa = sequences # rename
90
- seed = align_api.get_seed(job_id=msa.job.job_id)
91
- _proteins: dict[str, Protein] = {}
92
- for seq in seed.split(":"):
93
- protein = Protein(sequence=seq)
94
- id = next(id_gen)
95
- protein.msa = msa.id
96
- _proteins[id] = protein
97
- normalized_complexes = [Complex(chains=_proteins)]
98
-
88
+ normalized_complexes = [
89
+ _msa_future_to_complex(session=self.session, msa=sequences)
90
+ ]
99
91
  else:
100
92
  normalized_complexes = normalize_inputs(sequences)
101
93
 
@@ -139,9 +131,9 @@ class Boltz2Model(BoltzModel, FoldModel):
139
131
  num_steps: int = 200,
140
132
  step_scale: float = 1.638,
141
133
  use_potentials: bool = False,
142
- constraints: list[dict] | None = None,
143
- templates: list[dict] | None = None,
144
- properties: list[dict] | None = None,
134
+ constraints: Sequence[Mapping] | None = None,
135
+ templates: Sequence[Protein | Complex | Template] | None = None,
136
+ properties: Sequence[Mapping] | None = None,
145
137
  method: str | None = None,
146
138
  ) -> FoldResultFuture:
147
139
  """
@@ -163,7 +155,7 @@ class Boltz2Model(BoltzModel, FoldModel):
163
155
  Whether or not to use potentials.
164
156
  constraints : list[dict] | None = None
165
157
  List of constraints.
166
- templates: list[dict] | None = None
158
+ templates: list[Protein | Complex | Template] | None = None
167
159
  List of templates to use for structure prediction.
168
160
  properties: list[dict] | None = None
169
161
  List of additional properties to predict. Should match the `BoltzProperties`
@@ -180,24 +172,98 @@ class Boltz2Model(BoltzModel, FoldModel):
180
172
  Returns
181
173
  -------
182
174
  FoldResultFuture
183
- Future for the folding result.
175
+ Future for the folding result.
184
176
  """
185
-
177
+ prompt_api = getattr(self.session, "prompt", None)
178
+ assert isinstance(prompt_api, PromptAPI)
179
+
180
+ # validate templates
181
+ # mapping chain_id (to predict) to template
182
+ # needs to be consistent
183
+ templates_: list[Template] = []
184
+ if not isinstance(sequences, MSAFuture):
185
+ first_chain_id_to_template = {}
186
+ for batch_idx, seq in enumerate(sequences):
187
+ # validate templates and normalize to complex
188
+ if isinstance(seq, str) or isinstance(seq, bytes):
189
+ seq = Protein(seq)
190
+ seq._assert_valid_templates()
191
+ if isinstance(seq, Protein):
192
+ complex = Complex({"A": seq})
193
+ else:
194
+ complex = seq
195
+ # resolve chain-level templates
196
+ for chain_id, protein in complex.get_proteins().items():
197
+ # Verify same chain_id should have same templates
198
+ if batch_idx == 0:
199
+ first_chain_id_to_template[chain_id] = protein.templates
200
+ for template in protein.templates:
201
+ templates_.append(_to_template(template, chain_id=chain_id))
202
+ elif first_chain_id_to_template[chain_id] != protein.templates:
203
+ raise ValueError(
204
+ "Expected same chain across batches to have the same templates"
205
+ )
206
+ # resolve complex-level templates
207
+ if batch_idx == 0:
208
+ first_templates = complex.templates
209
+ for template in complex.templates:
210
+ templates_.append(_to_template(template))
211
+ elif first_templates != complex.templates:
212
+ raise ValueError(
213
+ "Expected templates across complexes in batch to be the same"
214
+ )
215
+ # method level argument
186
216
  if templates is not None:
187
- raise ValueError("`templates` not yet supported!")
217
+ if isinstance(sequences, MSAFuture):
218
+ # need to convert to complex for template validation
219
+ sequences = [
220
+ _msa_future_to_complex(session=self.session, msa=sequences)
221
+ ]
222
+ for template in templates:
223
+ template = _to_template(template)
224
+ # validate the template for all sequences before accepting it
225
+ for seq in sequences:
226
+ if isinstance(seq, str) or isinstance(seq, bytes):
227
+ seq = Protein(seq)
228
+ template.validate_for_target(seq)
229
+ templates_.append(template)
230
+
231
+ # resolve list of Templates into expected dict arg
232
+ template_dicts: list[dict] = []
233
+ # track resolved queries to reduce network calls - use id() for identity-based caching
234
+ struct_id_to_query_id = {}
235
+
236
+ for template in templates_:
237
+ # Use id() for caching - only resolve each unique structure once
238
+ struct_id = id(template.template)
239
+ if struct_id not in struct_id_to_query_id:
240
+ struct_id_to_query_id[struct_id] = prompt_api._resolve_query(
241
+ query=template.template
242
+ )
243
+
244
+ template_dict = {"query_id": struct_id_to_query_id[struct_id]}
245
+
246
+ if template.mapping is not None:
247
+ if isinstance(template.mapping, str):
248
+ template_dict["chain_id"] = template.mapping
249
+ else:
250
+ template_dict["chain_id"] = list(template.mapping.values())
251
+ template_dict["template_id"] = list(template.mapping.keys())
252
+
253
+ template_dicts.append(template_dict)
188
254
 
189
255
  # validate properties
190
256
  if properties is not None:
191
257
  props = TypeAdapter(list[BoltzProperty]).validate_python(properties)
192
258
  # Only allow affinity for ligands, and check binder refers to a ligand chain_id (str, not list)
193
259
  ligand_chain_ids = set()
194
- if isinstance(sequences, list):
260
+ if not isinstance(sequences, MSAFuture):
195
261
  for protein in sequences:
196
262
  if isinstance(protein, Complex):
197
263
  complex = protein
198
- for id, chain in complex.get_chains().items():
264
+ for chain_id, chain in complex.get_chains().items():
199
265
  if isinstance(chain, Ligand):
200
- ligand_chain_ids.add(id)
266
+ ligand_chain_ids.add(chain_id)
201
267
  for prop in props:
202
268
  if hasattr(prop, "affinity") and prop.affinity is not None:
203
269
  binder_id = prop.affinity.binder
@@ -214,7 +280,7 @@ class Boltz2Model(BoltzModel, FoldModel):
214
280
  step_scale=step_scale,
215
281
  use_potentials=use_potentials,
216
282
  constraints=constraints,
217
- templates=templates,
283
+ templates=template_dicts or None,
218
284
  properties=properties,
219
285
  method=method,
220
286
  )
@@ -235,7 +301,7 @@ class Boltz1Model(BoltzModel, FoldModel):
235
301
  num_steps: int = 200,
236
302
  step_scale: float = 1.638,
237
303
  use_potentials: bool = False,
238
- constraints: list[dict] | None = None,
304
+ constraints: Sequence[Mapping] | None = None,
239
305
  ) -> FoldResultFuture:
240
306
  """
241
307
  Request structure prediction with Boltz-1 model.
@@ -305,7 +371,7 @@ class Boltz1xModel(Boltz1Model, BoltzModel, FoldModel):
305
371
  num_recycles: int = 3,
306
372
  num_steps: int = 200,
307
373
  step_scale: float = 1.638,
308
- constraints: list[dict] | None = None,
374
+ constraints: Sequence[Mapping] | None = None,
309
375
  ) -> FoldResultFuture:
310
376
  """
311
377
  Request structure prediction with Boltz-1x model. Uses potentials with Boltz-1 model.
@@ -516,3 +582,21 @@ class BoltzAffinity(BaseModel):
516
582
 
517
583
  class Config:
518
584
  extra = "allow" # Allow extra fields
585
+
586
+
587
+ def _msa_future_to_complex(session: APISession, msa: MSAFuture) -> Complex:
588
+ align_api = getattr(session, "align", None)
589
+ assert isinstance(align_api, AlignAPI)
590
+ seed = align_api.get_seed(job_id=msa.job.job_id)
591
+ proteins: dict[str, Protein] = {}
592
+ for chain_id, seq in zip(id_generator(), seed.split(":")):
593
+ protein = Protein(sequence=seq)
594
+ protein.msa = msa.id
595
+ proteins[chain_id] = protein
596
+ return Complex(chains=proteins)
597
+
598
+
599
+ def _to_template(obj, chain_id: str | None = None):
600
+ if not isinstance(obj, Template):
601
+ obj = Template(template=obj, mapping=chain_id)
602
+ return obj
@@ -16,21 +16,20 @@ def normalize_inputs(
16
16
  normalized_complexes: list[Complex] = []
17
17
  remaining_proteins: list[Protein] = []
18
18
  remaining_protein_strings: list[str] = []
19
- if isinstance(proteins, list):
20
- for protein in proteins:
21
- if isinstance(protein, Protein):
19
+ for protein in proteins:
20
+ if isinstance(protein, Protein):
21
+ # collate these to init with id_gen
22
+ remaining_proteins.append(protein)
23
+ elif isinstance(protein, Complex):
24
+ used_ids.extend(list(protein.get_chains().keys()))
25
+ normalized_complexes.append(protein)
26
+ else:
27
+ if isinstance(protein, bytes):
28
+ protein = protein.decode()
29
+ # handle ':'-delimited
30
+ for seq in protein.split(":"):
22
31
  # collate these to init with id_gen
23
- remaining_proteins.append(protein)
24
- elif isinstance(protein, Complex):
25
- used_ids.extend(list(protein.get_chains().keys()))
26
- normalized_complexes.append(protein)
27
- else:
28
- if isinstance(protein, bytes):
29
- protein = protein.decode()
30
- # handle ':'-delimited
31
- for seq in protein.split(":"):
32
- # collate these to init with id_gen
33
- remaining_protein_strings.append(seq)
32
+ remaining_protein_strings.append(seq)
34
33
 
35
34
  # auto generate the chain ids
36
35
  id_gen = id_generator(used_ids)
@@ -1,4 +1,5 @@
1
1
  from .chains import DNA, RNA, Ligand
2
2
  from .complex import Complex
3
- from .protein import Protein, Binding
3
+ from .protein import Binding, Protein
4
4
  from .structure import Structure
5
+ from .template import Template
@@ -4,19 +4,21 @@ from collections.abc import Mapping, Sequence
4
4
  from functools import reduce
5
5
  from pathlib import Path
6
6
  from types import MappingProxyType
7
- from typing import Literal, overload
7
+ from typing import TYPE_CHECKING, Literal, overload
8
8
 
9
+ import gemmi
9
10
  import numpy as np
10
11
  import numpy.typing as npt
11
12
 
12
- import gemmi
13
-
14
13
  import openprotein.utils.chain_id as _chain_id_utils
15
14
  import openprotein.utils.cif as _cif_utils
16
15
 
17
16
  from .chains import DNA, RNA, Ligand
18
17
  from .protein import Protein
19
18
 
19
+ if TYPE_CHECKING:
20
+ from .template import Template
21
+
20
22
 
21
23
  # TODO: deserialization note about plddt parsed per residue
22
24
  class Complex:
@@ -26,6 +28,7 @@ class Complex:
26
28
  name: bytes | str | None = None,
27
29
  ):
28
30
  self._chains = dict(sorted(chains.items())) if chains is not None else {}
31
+ self._templates: "Sequence[Protein | Complex | Template]" = ()
29
32
  self.name = name
30
33
 
31
34
  @property
@@ -43,6 +46,23 @@ class Complex:
43
46
  self.name = x
44
47
  return self
45
48
 
49
+ @property
50
+ def templates(self) -> "Sequence[Protein | Complex | Template]":
51
+ return self._templates
52
+
53
+ @templates.setter
54
+ def templates(self, templates: "Sequence[Protein | Complex | Template]") -> None:
55
+ self._templates = tuple(templates)
56
+
57
+ def get_templates(self) -> "Sequence[Protein | Complex | Template]":
58
+ return self.templates
59
+
60
+ def set_templates(
61
+ self, templates: "Sequence[Protein | Complex | Template]"
62
+ ) -> "Complex":
63
+ self.templates = templates
64
+ return self
65
+
46
66
  def get_chains(self) -> Mapping[str, Protein | DNA | RNA | Ligand]:
47
67
  return MappingProxyType(self._chains)
48
68
 
@@ -246,6 +266,21 @@ class Complex:
246
266
  chains={k: v.copy() for k, v in self._chains.items()}, name=self._name
247
267
  )
248
268
 
269
+ def _assert_valid_templates(self):
270
+ from .template import Template
271
+
272
+ for template in self.templates:
273
+ (
274
+ template if isinstance(template, Template) else Template(template)
275
+ ).validate_for_target(self)
276
+ for chain_id, protein in self.get_proteins().items():
277
+ for template in protein.templates:
278
+ (
279
+ template
280
+ if isinstance(template, Template)
281
+ else Template(template, mapping=chain_id)
282
+ ).validate_for_target(Complex({chain_id: protein}))
283
+
249
284
  @staticmethod
250
285
  def _from_structure_block(
251
286
  structure_block: _cif_utils.StructureCIFBlock,
@@ -20,6 +20,7 @@ from .. import fasta
20
20
  if TYPE_CHECKING:
21
21
  from ..align.msa import MSAFuture
22
22
  from .complex import Complex
23
+ from .template import Template
23
24
 
24
25
  V = TypeVar("V")
25
26
 
@@ -70,6 +71,7 @@ class Protein:
70
71
  # sequence-level properties
71
72
  self._cyclic: bool = False
72
73
  self._msa: "str | MSAFuture | None | Type[Protein.NullMSA]" = None
74
+ self._templates: "Sequence[Protein | Complex | Template]" = ()
73
75
  # per-residue arrays
74
76
  self._data: dict[str, npt.NDArray] = {}
75
77
 
@@ -146,6 +148,23 @@ class Protein:
146
148
  self._msa = x
147
149
  return self
148
150
 
151
+ @property
152
+ def templates(self) -> "Sequence[Protein | Complex | Template]":
153
+ return self._templates
154
+
155
+ @templates.setter
156
+ def templates(self, templates: "Sequence[Protein | Complex | Template]") -> None:
157
+ self._templates = tuple(templates)
158
+
159
+ def get_templates(self) -> "Sequence[Protein | Complex | Template]":
160
+ return self.templates
161
+
162
+ def set_templates(
163
+ self, templates: "Sequence[Protein | Complex | Template]"
164
+ ) -> "Protein":
165
+ self.templates = templates
166
+ return self
167
+
149
168
  def __len__(self):
150
169
  return len(self.sequence)
151
170
 
@@ -641,6 +660,14 @@ class Protein:
641
660
  def copy(self) -> "Protein":
642
661
  return self[:]
643
662
 
663
+ def _assert_valid_templates(self):
664
+ from .template import Template
665
+
666
+ for template in self.templates:
667
+ (
668
+ template if isinstance(template, Template) else Template(template)
669
+ ).validate_for_target(self)
670
+
644
671
  @staticmethod
645
672
  def _from_structure_block(
646
673
  structure_block: _cif_utils.StructureCIFBlock,
@@ -0,0 +1,122 @@
1
+ import dataclasses
2
+ from collections.abc import Mapping
3
+ from types import NoneType
4
+
5
+ from .complex import Complex
6
+ from .protein import Protein
7
+
8
+ TemplateSource = Protein | Complex
9
+ TargetMolecule = Protein | Complex
10
+ ChainMapping = Mapping[str, str] | str | None
11
+
12
+
13
+ @dataclasses.dataclass(frozen=True)
14
+ class Template:
15
+ """
16
+ A structural template used to guide the folding of a target chain or complex.
17
+
18
+ This class wraps a structural source (Protein or Complex) and defines how it
19
+ should map to the target(s).
20
+
21
+ Attributes:
22
+ template (Protein | Complex): The structural object to be used as a template.
23
+ Must contain structural data (coordinates).
24
+ mapping (Mapping[str, str] | str | None): The rule for assigning this template
25
+ to the target.
26
+ - Mapping[str, str]: Explicitly maps {template_chain_id: target_chain_id}.
27
+ - str: Apply this template to a specific target_chain_id. (If template is
28
+ a Complex, a selection algorithm is used to pick the best source chain).
29
+ - None: Automatic assignment. The folding algorithm will determine which
30
+ chain(s) this template applies to.
31
+ """
32
+
33
+ template: TemplateSource
34
+ mapping: ChainMapping = None
35
+
36
+ def __post_init__(self) -> None:
37
+ """Validates the template upon initialization."""
38
+ self._validate_self()
39
+
40
+ def _validate_self(self) -> None:
41
+ """Checks internal consistency of the Template."""
42
+ if isinstance(self.template, Protein):
43
+ if not self.template.has_structure:
44
+ raise ValueError("Provided template Protein has no structural data.")
45
+ # A single Protein object is treated as an atomic unit (anonymous chain).
46
+ # It cannot support a dictionary mapping because it has no internal Chain IDs
47
+ # to map *from*.
48
+ if not isinstance(self.mapping, (str, NoneType)):
49
+ raise ValueError(
50
+ f"Invalid mapping type '{type(self.mapping)}' for Protein template. "
51
+ "Expected 'str' (target ID) or 'None'. A dict mapping is only valid "
52
+ "if the template is a Complex with named chains."
53
+ )
54
+ elif isinstance(self.template, Complex):
55
+ # Ensure all parts of the complex have structure
56
+ for chain_id, protein in self.template.get_proteins().items():
57
+ if not protein.has_structure:
58
+ raise ValueError(
59
+ f"Template Chain '{chain_id}' has no structural data."
60
+ )
61
+ # If mapping is explicit (dict), ensure source keys exist in the template
62
+ if not isinstance(self.mapping, (str, NoneType)):
63
+ template_chains = set(self.template.get_chains().keys())
64
+ mapping_keys = set(self.mapping.keys())
65
+ if not mapping_keys.issubset(template_chains):
66
+ missing = mapping_keys - template_chains
67
+ raise ValueError(
68
+ f"Mapping contains source chain IDs {missing} that do not "
69
+ f"exist in the template complex (available: {template_chains})."
70
+ )
71
+ else:
72
+ raise TypeError(
73
+ f"Template source must be Protein or Complex, got {type(self.template)}"
74
+ )
75
+
76
+ def validate_for_target(self, target: TargetMolecule) -> None:
77
+ """
78
+ Ensures this Template is compatible with a specific target Molecule.
79
+
80
+ Args:
81
+ target: The Protein or Complex that is being folded.
82
+
83
+ Raises:
84
+ ValueError: If this Template is invalid, or if chain IDs referenced in
85
+ mapping do not exist in the target.
86
+ TypeError: If the template/target combination is structurally incompatible.
87
+ """
88
+ self._validate_self()
89
+ if isinstance(target, Protein):
90
+ # Target is a single Protein (implies anonymous/single context).
91
+ # We cannot map to a specific chain ID because the target Protein object
92
+ # doesn't have a chain ID.
93
+ if self.mapping is not None:
94
+ raise ValueError(
95
+ "Cannot use a specific chain mapping when the target is a standalone Protein. "
96
+ "Mapping must be None."
97
+ )
98
+ elif isinstance(target, Complex):
99
+ target_chains = {
100
+ chain_id
101
+ for chain_id, chain in target.get_chains().items()
102
+ if isinstance(self.template, Complex)
103
+ or isinstance(chain, type(self.template))
104
+ }
105
+ if isinstance(self.mapping, str):
106
+ # Mapping points to a specific target chain ID
107
+ if self.mapping not in target_chains:
108
+ raise ValueError(
109
+ f"Template maps to target chain '{self.mapping}', but this chain "
110
+ f"does not exist in the target Complex (available: {target_chains})."
111
+ )
112
+ elif self.mapping is not None:
113
+ # Mapping points from Source -> specific target chain IDs
114
+ target_values = set(self.mapping.values())
115
+ if not target_values.issubset(target_chains):
116
+ missing = target_values - target_chains
117
+ raise ValueError(
118
+ f"Template maps to target chains {missing} which do not exist "
119
+ f"in the target Complex (available: {target_chains})."
120
+ )
121
+ else:
122
+ raise TypeError(f"Target must be Protein or Complex, got {type(target)}")