openprotein-python 0.14.2__tar.gz → 0.16.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 (215) hide show
  1. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/PKG-INFO +2 -1
  2. openprotein_python-0.16.0/openprotein/auth_store.py +79 -0
  3. openprotein_python-0.16.0/openprotein/base.py +372 -0
  4. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/models.py +14 -0
  5. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/poet.py +14 -0
  6. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/poet2.py +14 -0
  7. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/common.py +15 -27
  8. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/__init__.py +1 -0
  9. openprotein_python-0.16.0/openprotein/models/foundation/solublempnn.py +25 -0
  10. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/models.py +2 -0
  11. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/protein.py +9 -6
  12. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/__init__.py +1 -0
  13. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/api.py +17 -4
  14. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/predictor.py +33 -0
  15. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/schemas.py +15 -0
  16. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/models.py +14 -0
  17. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/pyproject.toml +1 -0
  18. openprotein_python-0.14.2/openprotein/base.py +0 -181
  19. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/.gitignore +0 -0
  20. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/LICENSE.txt +0 -0
  21. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/README.md +0 -0
  22. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/__init__.py +0 -0
  23. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/_version.py +0 -0
  24. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/__init__.py +0 -0
  25. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/align.py +0 -0
  26. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/api.py +0 -0
  27. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/future.py +0 -0
  28. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/msa.py +0 -0
  29. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/schemas.py +0 -0
  30. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/__init__.py +0 -0
  31. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/align.py +0 -0
  32. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/assaydata.py +0 -0
  33. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/__init__.py +0 -0
  34. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/design.py +0 -0
  35. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/poet.py +0 -0
  36. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/predict.py +0 -0
  37. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/train.py +0 -0
  38. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/design.py +0 -0
  39. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/designer.py +0 -0
  40. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/embedding.py +0 -0
  41. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/error.py +0 -0
  42. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/fold.py +0 -0
  43. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/job.py +0 -0
  44. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/predict.py +0 -0
  45. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/predictor.py +0 -0
  46. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/prompt.py +0 -0
  47. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/svd.py +0 -0
  48. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/train.py +0 -0
  49. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/umap.py +0 -0
  50. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/__init__.py +0 -0
  51. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/deprecated.py +0 -0
  52. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/__init__.py +0 -0
  53. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/__init__.py +0 -0
  54. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/base.py +0 -0
  55. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/msa.py +0 -0
  56. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/prompt.py +0 -0
  57. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/assaydata.py +0 -0
  58. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/__init__.py +0 -0
  59. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/design.py +0 -0
  60. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/poet.py +0 -0
  61. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/predict.py +0 -0
  62. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/train.py +0 -0
  63. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/design.py +0 -0
  64. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/designer.py +0 -0
  65. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/__init__.py +0 -0
  66. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/base.py +0 -0
  67. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/esm.py +0 -0
  68. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/future.py +0 -0
  69. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/openprotein.py +0 -0
  70. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/poet.py +0 -0
  71. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/poet2.py +0 -0
  72. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/test.py +0 -0
  73. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/__init__.py +0 -0
  74. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/alphafold2.py +0 -0
  75. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/base.py +0 -0
  76. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/boltz.py +0 -0
  77. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/esmfold.py +0 -0
  78. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/future.py +0 -0
  79. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/futures.py +0 -0
  80. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predict.py +0 -0
  81. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/__init__.py +0 -0
  82. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/predict.py +0 -0
  83. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/predictor.py +0 -0
  84. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/validate.py +0 -0
  85. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/prompt.py +0 -0
  86. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/svd.py +0 -0
  87. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/train.py +0 -0
  88. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/umap.py +0 -0
  89. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/__init__.py +0 -0
  90. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/align.py +0 -0
  91. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/assaydata.py +0 -0
  92. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/__init__.py +0 -0
  93. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/design.py +0 -0
  94. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/predict.py +0 -0
  95. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/train.py +0 -0
  96. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/design.py +0 -0
  97. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/designer.py +0 -0
  98. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/embeddings.py +0 -0
  99. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/fold.py +0 -0
  100. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/job.py +0 -0
  101. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/predict.py +0 -0
  102. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/predictor.py +0 -0
  103. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/prompt.py +0 -0
  104. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/svd.py +0 -0
  105. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/train.py +0 -0
  106. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/umap.py +0 -0
  107. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/chains.py +0 -0
  108. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/__init__.py +0 -0
  109. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/api.py +0 -0
  110. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/clustering.py +0 -0
  111. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/models.py +0 -0
  112. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/schemas.py +0 -0
  113. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/__init__.py +0 -0
  114. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/features.py +0 -0
  115. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/model_metadata.py +0 -0
  116. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/reduction.py +0 -0
  117. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/residue_contants.py +0 -0
  118. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/config.py +0 -0
  119. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/csv.py +0 -0
  120. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/__init__.py +0 -0
  121. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/api.py +0 -0
  122. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/assaydataset.py +0 -0
  123. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/data.py +0 -0
  124. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/schemas.py +0 -0
  125. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/__init__.py +0 -0
  126. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/api.py +0 -0
  127. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/design.py +0 -0
  128. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/future.py +0 -0
  129. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/schemas.py +0 -0
  130. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/__init__.py +0 -0
  131. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/ablang.py +0 -0
  132. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/api.py +0 -0
  133. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/embeddings.py +0 -0
  134. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/esm.py +0 -0
  135. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/future.py +0 -0
  136. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/openprotein.py +0 -0
  137. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/schemas.py +0 -0
  138. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/errors.py +0 -0
  139. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fasta.py +0 -0
  140. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/__init__.py +0 -0
  141. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/alphafold2.py +0 -0
  142. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/api.py +0 -0
  143. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/boltz.py +0 -0
  144. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/complex.py +0 -0
  145. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/esmfold.py +0 -0
  146. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/esmfold2.py +0 -0
  147. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/fold.py +0 -0
  148. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/future.py +0 -0
  149. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/minifold.py +0 -0
  150. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/models.py +0 -0
  151. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/protenix.py +0 -0
  152. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/rosettafold3.py +0 -0
  153. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/schemas.py +0 -0
  154. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/__init__.py +0 -0
  155. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/api.py +0 -0
  156. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/futures.py +0 -0
  157. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/jobs.py +0 -0
  158. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/schemas.py +0 -0
  159. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/base.py +0 -0
  160. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/boltzgen.py +0 -0
  161. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/boltzgen_schema.py +0 -0
  162. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/esmif1.py +0 -0
  163. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/proteinmpnn.py +0 -0
  164. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/rfdiffusion.py +0 -0
  165. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/structure_generation.py +0 -0
  166. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/__init__.py +0 -0
  167. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/chains.py +0 -0
  168. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/complex.py +0 -0
  169. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/structure.py +0 -0
  170. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/template.py +0 -0
  171. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/models.py +0 -0
  172. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/prediction.py +0 -0
  173. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/validate.py +0 -0
  174. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/__init__.py +0 -0
  175. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/api.py +0 -0
  176. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/models.py +0 -0
  177. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/prompt.py +0 -0
  178. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/schemas.py +0 -0
  179. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/protein.py +0 -0
  180. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/scaffolds.py +0 -0
  181. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/__init__.py +0 -0
  182. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/align.py +0 -0
  183. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/assaydata.py +0 -0
  184. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/__init__.py +0 -0
  185. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/design.py +0 -0
  186. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/poet.py +0 -0
  187. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/predict.py +0 -0
  188. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/train.py +0 -0
  189. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/design.py +0 -0
  190. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/designer.py +0 -0
  191. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/embeddings.py +0 -0
  192. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/features.py +0 -0
  193. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/fold.py +0 -0
  194. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/job.py +0 -0
  195. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/predict.py +0 -0
  196. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/predictor.py +0 -0
  197. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/prompt.py +0 -0
  198. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/svd.py +0 -0
  199. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/train.py +0 -0
  200. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/umap.py +0 -0
  201. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/__init__.py +0 -0
  202. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/api.py +0 -0
  203. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/schemas.py +0 -0
  204. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/svd.py +0 -0
  205. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/__init__.py +0 -0
  206. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/api.py +0 -0
  207. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/models.py +0 -0
  208. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/schemas.py +0 -0
  209. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/umap.py +0 -0
  210. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/__init__.py +0 -0
  211. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/chain_id.py +0 -0
  212. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/cif.py +0 -0
  213. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/numpy.py +0 -0
  214. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/sequence.py +0 -0
  215. {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/uuid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openprotein-python
3
- Version: 0.14.2
3
+ Version: 0.16.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
@@ -8,6 +8,7 @@ License-File: LICENSE.txt
8
8
  Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Requires-Python: <3.15,>=3.10
11
+ Requires-Dist: filelock<4,>=3.13
11
12
  Requires-Dist: gemmi<0.8,>=0.6.0
12
13
  Requires-Dist: numpy<3,>=1.9
13
14
  Requires-Dist: pandas<3,>=2.2.2
@@ -0,0 +1,79 @@
1
+ import json
2
+ import os
3
+ import tempfile
4
+ from pathlib import Path
5
+
6
+ from filelock import FileLock
7
+ from pydantic import BaseModel, ValidationError
8
+
9
+
10
+ class TokenRecord(BaseModel):
11
+ """A persisted auth record for one identity."""
12
+
13
+ access_token: str
14
+ refresh_token: str | None = None
15
+ expires_at: float = 0.0
16
+
17
+
18
+ class TokenStore:
19
+ """Persist the rotating refresh token across processes.
20
+
21
+ The on-disk file is a JSON object keyed by identity
22
+ ``"{backend}|{username}"`` -> ``TokenRecord``. The read-modify-write
23
+ critical section is guarded by a cross-process ``filelock`` so two
24
+ processes never refresh the same rotating token concurrently.
25
+ """
26
+
27
+ def __init__(self, dir: Path | None = None):
28
+ self.dir = Path(dir) if dir is not None else Path.home() / ".openprotein"
29
+ self.dir.mkdir(parents=True, exist_ok=True)
30
+ self.path = self.dir / "token.json"
31
+ # One FileLock instance per store -> reentrant within this process.
32
+ self._lock = FileLock(str(self.dir / "token.lock"))
33
+
34
+ @staticmethod
35
+ def identity(backend: str, username: str) -> str:
36
+ return f"{backend}|{username}"
37
+
38
+ def lock(self):
39
+ """Context manager for the cross-process critical section."""
40
+ return self._lock
41
+
42
+ def _read_all(self) -> dict:
43
+ # Caller must hold self._lock: this is the read half of the
44
+ # read-modify-write critical section in load()/save().
45
+ try:
46
+ return json.loads(self.path.read_text())
47
+ except (OSError, json.JSONDecodeError):
48
+ # Missing or corrupt file -> behave as if there were no records.
49
+ return {}
50
+
51
+ def load(self, identity: str) -> TokenRecord | None:
52
+ with self._lock:
53
+ data = self._read_all()
54
+ entry = data.get(identity)
55
+ if entry is None:
56
+ return None
57
+ try:
58
+ return TokenRecord.model_validate(entry)
59
+ except ValidationError:
60
+ return None
61
+
62
+ def save(self, identity: str, record: TokenRecord) -> None:
63
+ with self._lock:
64
+ data = self._read_all()
65
+ data[identity] = record.model_dump()
66
+ self._atomic_write(data)
67
+
68
+ def _atomic_write(self, data: dict) -> None:
69
+ fd, tmp = tempfile.mkstemp(dir=str(self.dir), prefix="token.", suffix=".tmp")
70
+ try:
71
+ with os.fdopen(fd, "w") as f:
72
+ json.dump(data, f)
73
+ os.chmod(tmp, 0o600)
74
+ os.replace(tmp, self.path)
75
+ except BaseException:
76
+ # Don't leave a temp file behind on failure.
77
+ if os.path.exists(tmp):
78
+ os.unlink(tmp)
79
+ raise
@@ -0,0 +1,372 @@
1
+ import sys
2
+ import threading
3
+ import time
4
+ import warnings
5
+ from typing import Mapping, Sequence
6
+ from urllib.parse import urljoin
7
+
8
+ import requests
9
+ import requests.auth
10
+ from requests.adapters import HTTPAdapter
11
+ from requests.packages.urllib3.util.retry import Retry # type: ignore
12
+
13
+ from openprotein._version import __version__
14
+ from openprotein.auth_store import TokenRecord, TokenStore
15
+ from openprotein.errors import AuthError, HTTPError
16
+
17
+ # Refresh the access token this many seconds before it actually expires,
18
+ # to absorb clock skew and request latency. 30s is a conservative buffer for
19
+ # typical clock drift plus a round-trip against a ~15-minute access token.
20
+ SKEW_SECONDS = 30
21
+
22
+
23
+ class BearerAuth(requests.auth.AuthBase):
24
+ """
25
+ See https://stackoverflow.com/a/58055668
26
+ """
27
+
28
+ def __init__(self, username, token):
29
+ self._username = username
30
+ self._token = token
31
+
32
+ @property
33
+ def token(self):
34
+ warnings.warn(
35
+ "DeprecationWarning: Accessing session.auth.token is deprecated and will throw an error in the future. Use session.auth._token if you need it."
36
+ )
37
+ return self._token
38
+
39
+ def __call__(self, r):
40
+ r.headers["Authorization"] = "Bearer " + self._token
41
+ return r
42
+
43
+
44
+ class APISession(requests.Session):
45
+ """
46
+ A class to handle API sessions. This class provides a connection session to the OpenProtein API.
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ username: str,
52
+ password: str,
53
+ backend: str,
54
+ timeout: int = 180,
55
+ ):
56
+ if not username or not password:
57
+ raise AuthError(
58
+ "Expected username and password. Or use environment variables `OPENPROTEIN_USERNAME` and `OPENPROTEIN_PASSWORD`. Or provide these variables (`username` and `password`) in ~/.openprotein/config.toml."
59
+ )
60
+ super().__init__()
61
+ self.backend = backend
62
+ self.verify = True
63
+ self.timeout = timeout
64
+
65
+ # Custom retry strategies
66
+ # auto retry for pesky connection reset errors and others
67
+ # 503 will catch if BE is refreshing
68
+ retry = Retry(
69
+ total=4,
70
+ backoff_factor=3, # 0,1,4,13s
71
+ status_forcelist=[500, 502, 503, 504, 101, 104],
72
+ )
73
+ adapter = HTTPAdapter(max_retries=retry)
74
+ self.mount("https://", adapter)
75
+ self.headers["User-Agent"] = f"openprotein-python/{__version__}"
76
+
77
+ # Auth / refresh state. Initialised before any network call so that
78
+ # request() can read _refreshing / _legacy_mode safely.
79
+ self._username = username
80
+ self._password = password
81
+ self._token_store = TokenStore()
82
+ self._identity = self._token_store.identity(backend, username)
83
+ # _refresh_lock serializes concurrent refreshes across threads.
84
+ # _refreshing (see the _refreshing property) is a thread-local recursion
85
+ # guard: the refresh POST flows back through request(), so the refreshing
86
+ # thread must skip the refresh logic, but OTHER threads sharing this
87
+ # session (e.g. via stream_parallel) must not be suppressed by it.
88
+ self._refresh_lock = threading.Lock()
89
+ self._tl = threading.local()
90
+ self._refresh_token: str | None = None
91
+ self._expires_at: float = 0.0
92
+ self._legacy_mode: bool = False
93
+
94
+ self._init_auth()
95
+
96
+ @property
97
+ def _refreshing(self) -> bool:
98
+ return getattr(self._tl, "refreshing", False)
99
+
100
+ @_refreshing.setter
101
+ def _refreshing(self, value: bool) -> None:
102
+ self._tl.refreshing = value
103
+
104
+ def _init_auth(self):
105
+ """Adopt a valid stored record if present, otherwise log in fresh."""
106
+ record = self._token_store.load(self._identity)
107
+ if record is not None and record.refresh_token:
108
+ self._adopt(record)
109
+ else:
110
+ self.login(self._username, self._password)
111
+
112
+ def post(self, url, data=None, json=None, **kwargs):
113
+ r"""Sends a POST request. Returns :class:`Response` object.
114
+
115
+ :param url: URL for the new :class:`Request` object.
116
+ :param data: (optional) Dictionary, list of tuples, bytes, or file-like
117
+ object to send in the body of the :class:`Request`.
118
+ :param json: (optional) json to send in the body of the :class:`Request`.
119
+ :param \*\*kwargs: Optional arguments that ``request`` takes.
120
+ :rtype: requests.Response
121
+ """
122
+ timeout = self.timeout
123
+ if "timeout" in kwargs:
124
+ timeout = kwargs.pop("timeout")
125
+
126
+ return self.request(
127
+ "POST", url, data=data, json=json, timeout=timeout, **kwargs
128
+ )
129
+
130
+ def login(self, username: str, password: str):
131
+ """
132
+ Authenticate connection to OpenProtein with your credentials.
133
+
134
+ Parameters
135
+ -----------
136
+ username: str
137
+ username
138
+ password: str
139
+ password
140
+ """
141
+ # unset the auth first
142
+ self.auth = None
143
+ self._get_auth_token(username, password)
144
+
145
+ def _auth_post(self, url: str, **kwargs):
146
+ """POST for the auth endpoints, with the refresh logic suppressed.
147
+
148
+ Sets ``_refreshing`` so the proactive/reactive refresh in request()
149
+ does not recurse while we are logging in or refreshing.
150
+ """
151
+ self._refreshing = True
152
+ try:
153
+ return self.post(url, **kwargs)
154
+ finally:
155
+ self._refreshing = False
156
+
157
+ def _get_auth_token(self, username: str, password: str):
158
+ url = urljoin(self.backend, "v1/auth/login")
159
+ try:
160
+ response = self._auth_post(
161
+ url,
162
+ data={"username": username, "password": password},
163
+ headers={"X-Token-Delivery": "body"},
164
+ timeout=3,
165
+ )
166
+ except HTTPError as e:
167
+ if e.status_code == 404:
168
+ # Backend not yet upgraded -> use the legacy endpoint.
169
+ return self._legacy_login(username, password)
170
+ raise AuthError(
171
+ "Authentication failed. Please check your credentials and connection."
172
+ ) from e
173
+ self._apply_token_response(response.json(), username)
174
+
175
+ def _legacy_login(self, username: str, password: str):
176
+ url = urljoin(self.backend, "v1/login/access-token")
177
+ try:
178
+ response = self._auth_post(
179
+ url,
180
+ data={"username": username, "password": password},
181
+ timeout=3,
182
+ )
183
+ except HTTPError as e:
184
+ raise AuthError(
185
+ "Authentication failed. Please check your credentials and connection."
186
+ ) from e
187
+ token = response.json().get("access_token")
188
+ if token is None:
189
+ raise AuthError("Unable to authenticate with given credentials.")
190
+ self._legacy_mode = True
191
+ self._refresh_token = None
192
+ self._expires_at = 0.0
193
+ self._set_token(username, token)
194
+
195
+ def _apply_token_response(self, result: dict, username: str):
196
+ """Parse a login/refresh response, update memory + store, set the bearer."""
197
+ access_token = result.get("access_token")
198
+ if access_token is None:
199
+ raise AuthError("Unable to authenticate with given credentials.")
200
+ refresh_token = result.get("refresh_token")
201
+ if refresh_token is None:
202
+ # Cookie-mode / pre-rotation backend -> no refresh available.
203
+ self._legacy_mode = True
204
+ self._refresh_token = None
205
+ self._expires_at = 0.0
206
+ else:
207
+ self._legacy_mode = False
208
+ self._refresh_token = refresh_token
209
+ # A missing/zero expires_in is treated as "expired now", which makes
210
+ # the proactive check refresh on the next request rather than trust a
211
+ # token of unknown lifetime.
212
+ self._expires_at = time.time() + (result.get("expires_in") or 0)
213
+ self._token_store.save(
214
+ self._identity,
215
+ TokenRecord(
216
+ access_token=access_token,
217
+ refresh_token=refresh_token,
218
+ expires_at=self._expires_at,
219
+ ),
220
+ )
221
+ self._set_token(username, access_token)
222
+
223
+ def _set_token(self, username: str, access_token: str):
224
+ if isinstance(self.auth, BearerAuth):
225
+ self.auth._token = access_token
226
+ else:
227
+ self.auth = BearerAuth(username=username, token=access_token)
228
+
229
+ def _adopt(self, record: TokenRecord):
230
+ """Adopt an existing token record (from disk or a fresher in-store copy).
231
+
232
+ Callers must only pass a record whose ``refresh_token`` is set — a
233
+ record without one is not adoptable (it would leave the session in
234
+ non-legacy mode with nothing to refresh).
235
+ """
236
+ self._legacy_mode = False
237
+ self._refresh_token = record.refresh_token
238
+ self._expires_at = record.expires_at
239
+ self._set_token(self._username, record.access_token)
240
+
241
+ def _refresh(self):
242
+ """Refresh the access token, serialized across threads and processes.
243
+
244
+ Re-reads the store under the lock first: if another thread/process
245
+ already rotated the token, adopt that instead of refreshing again
246
+ (replaying a superseded refresh token would revoke the session).
247
+ """
248
+ with self._refresh_lock, self._token_store.lock():
249
+ record = self._token_store.load(self._identity)
250
+ if (
251
+ record is not None
252
+ and record.refresh_token
253
+ and record.expires_at > self._expires_at
254
+ ):
255
+ self._adopt(record)
256
+ return
257
+
258
+ if self._refresh_token is None:
259
+ self._relogin()
260
+ return
261
+
262
+ url = urljoin(self.backend, "v1/auth/refresh")
263
+ try:
264
+ response = self._auth_post(
265
+ url,
266
+ json={"refresh_token": self._refresh_token},
267
+ headers={"X-Token-Delivery": "body"},
268
+ timeout=10,
269
+ )
270
+ except HTTPError as e:
271
+ # Recover by re-logging-in when the refresh token is rejected
272
+ # (401/403) or when the endpoint is absent (404 from a backend
273
+ # that issued a refresh token but doesn't expose /auth/refresh,
274
+ # e.g. mid-rollback) — re-login itself drops to legacy mode if
275
+ # the backend has no refresh support. Other statuses are real
276
+ # errors and propagate.
277
+ if e.status_code in (401, 403, 404):
278
+ self._relogin()
279
+ return
280
+ raise
281
+ self._apply_token_response(response.json(), self._username)
282
+
283
+ def _relogin(self):
284
+ """Re-establish a session from the in-memory credentials."""
285
+ try:
286
+ self.login(self._username, self._password)
287
+ except AuthError:
288
+ raise
289
+ except Exception as e:
290
+ raise AuthError("Session expired and re-login failed.") from e
291
+
292
+ def _should_refresh_proactively(self) -> bool:
293
+ return (
294
+ not self._refreshing
295
+ and not self._legacy_mode
296
+ and self._refresh_token is not None
297
+ and time.time() >= self._expires_at - SKEW_SECONDS
298
+ )
299
+
300
+ def request(self, method: str, url: str, *args, **kwargs):
301
+ if self._should_refresh_proactively():
302
+ self._refresh()
303
+
304
+ full_url = urljoin(self.backend, url)
305
+ response = super().request(method, full_url, *args, **kwargs)
306
+
307
+ # Reactive refresh: a 401 means the access token expired between the
308
+ # proactive check and the call (or skew). Refresh once and retry once.
309
+ if (
310
+ response.status_code == 401
311
+ and not self._refreshing
312
+ and not self._legacy_mode
313
+ ):
314
+ self._refresh()
315
+ response = super().request(method, full_url, *args, **kwargs)
316
+
317
+ if (js := kwargs.get("json")) and js is not None:
318
+ if _total_size(js) > 1e6:
319
+ warnings.warn(
320
+ "The requested payload is >1MB. There might be some delays or issues in processing. If the request fails, please try again with smaller sizes."
321
+ )
322
+
323
+ # intercept CloudFront errors
324
+ if "cloudfront" in response.headers.get("Server", "").lower():
325
+ if response.status_code in (502, 503):
326
+ raise CloudFrontError(
327
+ f"We're experiencing a temporary backend issue via CloudFront. Please try again later. Error {response.status_code}."
328
+ )
329
+ elif response.status_code == 504:
330
+ raise TimeoutError(
331
+ "Your request took too long to process likely due to it's size. Please try breaking it up into smaller requests if possible."
332
+ )
333
+ elif not response.ok:
334
+ # raise custom exception that prints better error message than requests.HTTPError
335
+ raise HTTPError(response)
336
+ return response
337
+
338
+
339
+ def _total_size(o: Sequence | Mapping | object, seen=None):
340
+ """Recursively finds size of objects including contents."""
341
+ if seen is None:
342
+ seen = set()
343
+ obj_id = id(o)
344
+ if obj_id in seen:
345
+ return 0
346
+ seen.add(obj_id)
347
+ size = sys.getsizeof(o)
348
+ if isinstance(o, dict):
349
+ size += sum((_total_size(k, seen) + _total_size(v, seen)) for k, v in o.items())
350
+ elif isinstance(o, (list, tuple, set, frozenset)):
351
+ size += sum(_total_size(i, seen) for i in o)
352
+ return size
353
+
354
+
355
+ class TimeoutError(requests.exceptions.HTTPError):
356
+ """
357
+ An Exception raised due to timeout, possibly from overly large
358
+ requests.
359
+ """
360
+
361
+
362
+ class CloudFrontError(requests.exceptions.HTTPError):
363
+ """
364
+ An Exception raised due to CloudFront.
365
+
366
+ This is usually due to the strict timeout from CloudFront.
367
+ AWS CloudFront limits responses to return within 2 minutes.
368
+ This can be a bit prohibitive for our system that tends to
369
+ deal with large data. It is usually safe to just ignore/retry upon
370
+ hitting this error. Our system will scale up and still handle
371
+ the job.
372
+ """
@@ -17,6 +17,7 @@ from . import api
17
17
  from .future import EmbeddingsResultFuture
18
18
 
19
19
  if TYPE_CHECKING:
20
+ from openprotein.predictor.schemas import KernelType
20
21
  from openprotein.predictor import PredictorModel
21
22
  from openprotein.svd import SVDModel
22
23
  from openprotein.umap import UMAPModel
@@ -352,6 +353,9 @@ class EmbeddingModel:
352
353
  reduction: ReductionType,
353
354
  name: str | None = None,
354
355
  description: str | None = None,
356
+ kernel: "KernelType | str" = "rbf",
357
+ period: float | None = None,
358
+ alpha: float | None = None,
355
359
  **kwargs,
356
360
  ) -> "PredictorModel":
357
361
  """
@@ -363,6 +367,13 @@ class EmbeddingModel:
363
367
  Assay to fit GP on.
364
368
  properties : list of str
365
369
  Properties in the assay to fit the GP on.
370
+ kernel : KernelType or str, optional
371
+ Kernel for the GP, e.g. "rbf", "matern52", "periodic",
372
+ "rational_quadratic". Defaults to "rbf".
373
+ period : float or None, optional
374
+ Period length; only valid for the "periodic" kernel (must be > 0).
375
+ alpha : float or None, optional
376
+ Scale-mixture parameter; only valid for "rational_quadratic" (must be > 0).
366
377
  reduction : ReductionType
367
378
  Type of embedding reduction to use for computing features. PLM must use reduction.
368
379
  name : str or None, optional
@@ -398,6 +409,9 @@ class EmbeddingModel:
398
409
  reduction=reduction,
399
410
  name=name,
400
411
  description=description,
412
+ kernel=kernel,
413
+ period=period,
414
+ alpha=alpha,
401
415
  **kwargs,
402
416
  )
403
417
 
@@ -17,6 +17,7 @@ from .future import (
17
17
  from .models import EmbeddingModel
18
18
 
19
19
  if TYPE_CHECKING:
20
+ from openprotein.predictor.schemas import KernelType
20
21
  from openprotein.predictor import PredictorModel
21
22
  from openprotein.svd import SVDModel
22
23
  from openprotein.umap import UMAPModel
@@ -432,6 +433,9 @@ class PoETModel(EmbeddingModel):
432
433
  name: str | None = None,
433
434
  description: str | None = None,
434
435
  prompt: str | Prompt | None = None,
436
+ kernel: "KernelType | str" = "rbf",
437
+ period: float | None = None,
438
+ alpha: float | None = None,
435
439
  **kwargs,
436
440
  ) -> "PredictorModel":
437
441
  """
@@ -443,6 +447,13 @@ class PoETModel(EmbeddingModel):
443
447
  Assay to fit GP on.
444
448
  properties : list of str
445
449
  Properties in the assay to fit the GP on.
450
+ kernel : KernelType or str, optional
451
+ Kernel for the GP, e.g. "rbf", "matern52", "periodic",
452
+ "rational_quadratic". Defaults to "rbf".
453
+ period : float or None, optional
454
+ Period length; only valid for the "periodic" kernel (must be > 0).
455
+ alpha : float or None, optional
456
+ Scale-mixture parameter; only valid for "rational_quadratic" (must be > 0).
446
457
  prompt : str or Prompt or None, optional
447
458
  Prompt from an align workflow to condition the PoET model.
448
459
  **kwargs
@@ -464,5 +475,8 @@ class PoETModel(EmbeddingModel):
464
475
  name=name,
465
476
  description=description,
466
477
  prompt_id=prompt_id,
478
+ kernel=kernel,
479
+ period=period,
480
+ alpha=alpha,
467
481
  **kwargs,
468
482
  )
@@ -21,6 +21,7 @@ from .models import EmbeddingModel
21
21
  from .poet import PoETModel
22
22
 
23
23
  if TYPE_CHECKING:
24
+ from openprotein.predictor.schemas import KernelType
24
25
  from openprotein.models.structure_generation import StructureGenerationFuture
25
26
  from openprotein.predictor import PredictorModel
26
27
  from openprotein.svd import SVDModel
@@ -533,6 +534,9 @@ class PoET2Model(PoETModel, EmbeddingModel):
533
534
  query: str | bytes | Protein | Complex | Query | None = None,
534
535
  use_query_structure_in_decoder: bool = True,
535
536
  decoder_type: Literal["mlm", "clm"] | None = None,
537
+ kernel: "KernelType | str" = "rbf",
538
+ period: float | None = None,
539
+ alpha: float | None = None,
536
540
  **kwargs,
537
541
  ) -> "PredictorModel":
538
542
  """
@@ -544,6 +548,13 @@ class PoET2Model(PoETModel, EmbeddingModel):
544
548
  Assay to fit GP on.
545
549
  properties : list of str
546
550
  Properties in the assay to fit the GP on.
551
+ kernel : KernelType or str, optional
552
+ Kernel for the GP, e.g. "rbf", "matern52", "periodic",
553
+ "rational_quadratic". Defaults to "rbf".
554
+ period : float or None, optional
555
+ Period length; only valid for the "periodic" kernel (must be > 0).
556
+ alpha : float or None, optional
557
+ Scale-mixture parameter; only valid for "rational_quadratic" (must be > 0).
547
558
  prompt : str or Prompt or None, optional
548
559
  Prompt from an align workflow to condition PoET model.
549
560
  query : str or bytes or Protein or Complex or Query or None, optional
@@ -570,5 +581,8 @@ class PoET2Model(PoETModel, EmbeddingModel):
570
581
  query_id=query_id,
571
582
  use_query_structure_in_decoder=use_query_structure_in_decoder,
572
583
  decoder_type=decoder_type,
584
+ kernel=kernel,
585
+ period=period,
586
+ alpha=alpha,
573
587
  **kwargs,
574
588
  )
@@ -13,40 +13,28 @@ from openprotein.prompt import PromptAPI
13
13
  def normalize_inputs(
14
14
  proteins: Sequence[Complex | Protein | str | bytes],
15
15
  ):
16
- # collate the id's used
17
- used_ids = []
18
16
  normalized_complexes: list[Complex] = []
19
- remaining_proteins: list[Protein] = []
20
- remaining_protein_strings: list[str] = []
21
17
  for protein in proteins:
22
- if isinstance(protein, Protein):
23
- # collate these to init with id_gen
24
- remaining_proteins.append(protein)
25
- elif isinstance(protein, Complex):
26
- used_ids.extend(list(protein.get_chains().keys()))
18
+ if isinstance(protein, Complex):
27
19
  normalized_complexes.append(protein)
20
+ elif isinstance(protein, Protein):
21
+ # a lone protein becomes a single-chain complex
22
+ id_gen = id_generator()
23
+ normalized_complexes.append(Complex(chains={next(id_gen): protein}))
28
24
  else:
29
25
  if isinstance(protein, bytes):
30
26
  protein = protein.decode()
31
- # handle ':'-delimited
27
+ # a ':'-delimited string is one complex, one chain per split sequence.
28
+ # chain ids only need to be unique within the complex, so use a fresh
29
+ # generator per complex.
30
+ id_gen = id_generator()
31
+ chains: dict[str, Protein] = {}
32
32
  for seq in protein.split(":"):
33
- # collate these to init with id_gen
34
- remaining_protein_strings.append(seq)
35
-
36
- # auto generate the chain ids
37
- id_gen = id_generator(used_ids)
38
-
39
- # add the remaining proteins with id gen
40
- for protein in remaining_proteins:
41
- id = next(id_gen)
42
- normalized_complexes.append(Complex(chains={id: protein}))
43
-
44
- for protein_str in remaining_protein_strings:
45
- id = next(id_gen)
46
- protein = Protein(sequence=protein_str)
47
- # protein strings default to null msa
48
- protein.msa = Protein.NullMSA
49
- normalized_complexes.append(Complex(chains={id: protein}))
33
+ chain = Protein(sequence=seq)
34
+ # protein strings default to null msa
35
+ chain.msa = Protein.NullMSA
36
+ chains[next(id_gen)] = chain
37
+ normalized_complexes.append(Complex(chains=chains))
50
38
 
51
39
  return normalized_complexes
52
40
 
@@ -19,6 +19,7 @@ from .foundation.boltzgen import BoltzGenFuture, BoltzGenModel
19
19
  from .foundation.esmif1 import ESMIF1Model
20
20
  from .foundation.proteinmpnn import ProteinMPNNModel
21
21
  from .foundation.rfdiffusion import RFdiffusionFuture, RFdiffusionModel
22
+ from .foundation.solublempnn import SolubleMPNNModel
22
23
  from .models import ModelsAPI
23
24
  from .structure_generation import (
24
25
  StructureGenerationFuture,
@@ -0,0 +1,25 @@
1
+ """SolubleMPNN model: ProteinMPNN variant tuned for soluble protein targets."""
2
+
3
+ from .proteinmpnn import ProteinMPNNModel
4
+
5
+
6
+ class SolubleMPNNModel(ProteinMPNNModel):
7
+ """
8
+ Class for SolubleMPNN model.
9
+
10
+ Soluble-protein variant of ProteinMPNN.
11
+
12
+ Examples
13
+ --------
14
+ View specific model details (including supported tokens) with the `?` operator.
15
+
16
+ Examples
17
+ --------
18
+ .. code-block:: ipython3
19
+
20
+ >>> import openprotein
21
+ >>> session = openprotein.connect(username="user", password="password")
22
+ >>> session.models.solublempnn?
23
+ """
24
+
25
+ model_id = "solublempnn"