openprotein-python 0.10.1__tar.gz → 0.11.1__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.
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/.gitignore +3 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/PKG-INFO +1 -1
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/poet.py +29 -11
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/poet2.py +12 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/boltz.py +112 -28
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/common.py +13 -14
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/molecules/__init__.py +2 -1
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/molecules/complex.py +39 -3
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/molecules/protein.py +28 -0
- openprotein_python-0.11.1/openprotein/molecules/template.py +122 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/utils/chain_id.py +4 -1
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/LICENSE.txt +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/README.md +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/_version.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/align/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/align/align.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/align/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/align/future.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/align/msa.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/align/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/align.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/assaydata.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/deprecated/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/deprecated/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/deprecated/poet.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/deprecated/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/deprecated/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/designer.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/embedding.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/error.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/fold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/job.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/predictor.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/prompt.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/svd.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/api/umap.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/deprecated.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/align/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/align/base.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/align/msa.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/align/prompt.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/assaydata.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/deprecated/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/deprecated/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/deprecated/poet.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/deprecated/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/deprecated/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/designer.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/base.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/esm.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/future.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/openprotein.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/poet.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/poet2.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/embeddings/test.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/fold/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/fold/alphafold2.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/fold/base.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/fold/boltz.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/fold/esmfold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/fold/future.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/futures.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/predictor/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/predictor/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/predictor/predictor.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/predictor/validate.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/prompt.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/svd.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/models/umap.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/align.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/assaydata.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/deprecated/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/deprecated/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/deprecated/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/deprecated/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/designer.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/embeddings.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/fold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/job.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/predictor.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/prompt.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/svd.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/app/services/umap.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/base.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/chains.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/common/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/common/features.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/common/model_metadata.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/common/reduction.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/common/residue_contants.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/config.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/csv.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/data/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/data/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/data/assaydataset.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/data/data.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/data/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/design/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/design/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/design/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/design/future.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/design/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/embeddings.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/esm.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/future.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/openprotein.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/embeddings/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/errors.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fasta.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/alphafold2.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/complex.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/esmfold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/fold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/future.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/minifold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/rosettafold3.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/fold/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/jobs/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/jobs/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/jobs/futures.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/jobs/jobs.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/jobs/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/base.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/foundation/boltzgen.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/foundation/boltzgen_schema.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/foundation/proteinmpnn.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/foundation/rfdiffusion.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/models/structure_generation.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/molecules/chains.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/molecules/structure.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/prediction.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/predictor.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/predictor/validate.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/prompt/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/prompt/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/prompt/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/prompt/prompt.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/prompt/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/protein.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/scaffolds.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/align.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/assaydata.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/deprecated/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/deprecated/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/deprecated/poet.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/deprecated/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/deprecated/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/design.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/designer.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/embeddings.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/features.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/fold.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/job.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/predict.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/predictor.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/prompt.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/svd.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/train.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/schemas/umap.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/svd/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/svd/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/svd/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/svd/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/svd/svd.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/umap/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/umap/api.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/umap/models.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/umap/schemas.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/umap/umap.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/utils/__init__.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/utils/cif.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/utils/numpy.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/utils/sequence.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/openprotein/utils/uuid.py +0 -0
- {openprotein_python-0.10.1 → openprotein_python-0.11.1}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openprotein-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.1
|
|
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:
|
|
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:
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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:
|
|
143
|
-
templates:
|
|
144
|
-
properties:
|
|
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[
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
260
|
+
if not isinstance(sequences, MSAFuture):
|
|
195
261
|
for protein in sequences:
|
|
196
262
|
if isinstance(protein, Complex):
|
|
197
263
|
complex = protein
|
|
198
|
-
for
|
|
264
|
+
for chain_id, chain in complex.get_chains().items():
|
|
199
265
|
if isinstance(chain, Ligand):
|
|
200
|
-
ligand_chain_ids.add(
|
|
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=
|
|
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:
|
|
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:
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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)
|
|
@@ -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,24 @@ class Complex:
|
|
|
43
46
|
self.name = x
|
|
44
47
|
return self
|
|
45
48
|
|
|
49
|
+
@property
|
|
50
|
+
def templates(self) -> "Sequence[Protein | Complex | Template]":
|
|
51
|
+
"""A list of templates for guiding the structure prediction of this molecular complex."""
|
|
52
|
+
return self._templates
|
|
53
|
+
|
|
54
|
+
@templates.setter
|
|
55
|
+
def templates(self, templates: "Sequence[Protein | Complex | Template]") -> None:
|
|
56
|
+
self._templates = tuple(templates)
|
|
57
|
+
|
|
58
|
+
def get_templates(self) -> "Sequence[Protein | Complex | Template]":
|
|
59
|
+
return self.templates
|
|
60
|
+
|
|
61
|
+
def set_templates(
|
|
62
|
+
self, templates: "Sequence[Protein | Complex | Template]"
|
|
63
|
+
) -> "Complex":
|
|
64
|
+
self.templates = templates
|
|
65
|
+
return self
|
|
66
|
+
|
|
46
67
|
def get_chains(self) -> Mapping[str, Protein | DNA | RNA | Ligand]:
|
|
47
68
|
return MappingProxyType(self._chains)
|
|
48
69
|
|
|
@@ -246,6 +267,21 @@ class Complex:
|
|
|
246
267
|
chains={k: v.copy() for k, v in self._chains.items()}, name=self._name
|
|
247
268
|
)
|
|
248
269
|
|
|
270
|
+
def _assert_valid_templates(self):
|
|
271
|
+
from .template import Template
|
|
272
|
+
|
|
273
|
+
for template in self.templates:
|
|
274
|
+
(
|
|
275
|
+
template if isinstance(template, Template) else Template(template)
|
|
276
|
+
).validate_for_target(self)
|
|
277
|
+
for chain_id, protein in self.get_proteins().items():
|
|
278
|
+
for template in protein.templates:
|
|
279
|
+
(
|
|
280
|
+
template
|
|
281
|
+
if isinstance(template, Template)
|
|
282
|
+
else Template(template, mapping=chain_id)
|
|
283
|
+
).validate_for_target(Complex({chain_id: protein}))
|
|
284
|
+
|
|
249
285
|
@staticmethod
|
|
250
286
|
def _from_structure_block(
|
|
251
287
|
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,24 @@ class Protein:
|
|
|
146
148
|
self._msa = x
|
|
147
149
|
return self
|
|
148
150
|
|
|
151
|
+
@property
|
|
152
|
+
def templates(self) -> "Sequence[Protein | Complex | Template]":
|
|
153
|
+
"""A list of templates for guiding the structure prediction of this protein."""
|
|
154
|
+
return self._templates
|
|
155
|
+
|
|
156
|
+
@templates.setter
|
|
157
|
+
def templates(self, templates: "Sequence[Protein | Complex | Template]") -> None:
|
|
158
|
+
self._templates = tuple(templates)
|
|
159
|
+
|
|
160
|
+
def get_templates(self) -> "Sequence[Protein | Complex | Template]":
|
|
161
|
+
return self.templates
|
|
162
|
+
|
|
163
|
+
def set_templates(
|
|
164
|
+
self, templates: "Sequence[Protein | Complex | Template]"
|
|
165
|
+
) -> "Protein":
|
|
166
|
+
self.templates = templates
|
|
167
|
+
return self
|
|
168
|
+
|
|
149
169
|
def __len__(self):
|
|
150
170
|
return len(self.sequence)
|
|
151
171
|
|
|
@@ -641,6 +661,14 @@ class Protein:
|
|
|
641
661
|
def copy(self) -> "Protein":
|
|
642
662
|
return self[:]
|
|
643
663
|
|
|
664
|
+
def _assert_valid_templates(self):
|
|
665
|
+
from .template import Template
|
|
666
|
+
|
|
667
|
+
for template in self.templates:
|
|
668
|
+
(
|
|
669
|
+
template if isinstance(template, Template) else Template(template)
|
|
670
|
+
).validate_for_target(self)
|
|
671
|
+
|
|
644
672
|
@staticmethod
|
|
645
673
|
def _from_structure_block(
|
|
646
674
|
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)}")
|