openprotein-python 0.13.1__tar.gz → 0.14.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.13.1 → openprotein_python-0.14.1}/PKG-INFO +2 -2
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/__init__.py +12 -1
- openprotein_python-0.14.1/openprotein/clustering/__init__.py +14 -0
- openprotein_python-0.14.1/openprotein/clustering/api.py +117 -0
- openprotein_python-0.14.1/openprotein/clustering/clustering.py +191 -0
- openprotein_python-0.14.1/openprotein/clustering/models.py +75 -0
- openprotein_python-0.14.1/openprotein/clustering/schemas.py +85 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/data/data.py +3 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/ablang.py +1 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/api.py +35 -7
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/embeddings.py +5 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/esm.py +4 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/models.py +14 -4
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/openprotein.py +1 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/poet.py +5 -4
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/poet2.py +3 -2
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/__init__.py +6 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/api.py +5 -1
- openprotein_python-0.14.1/openprotein/fold/esmfold2.py +227 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/fold.py +8 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/future.py +98 -22
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/protenix.py +11 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/jobs/jobs.py +3 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/jobs/schemas.py +2 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/__init__.py +5 -0
- openprotein_python-0.14.1/openprotein/models/foundation/esmif1.py +213 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/foundation/proteinmpnn.py +8 -9
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/models.py +3 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/molecules/complex.py +2 -2
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/molecules/protein.py +19 -5
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/molecules/template.py +1 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/prompt/api.py +155 -103
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/prompt/models.py +85 -8
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/prompt/prompt.py +22 -15
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/prompt/schemas.py +2 -2
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/svd/api.py +13 -3
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/svd/models.py +7 -2
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/umap/api.py +13 -3
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/umap/models.py +7 -2
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/umap/umap.py +2 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/pyproject.toml +3 -1
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/.gitignore +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/LICENSE.txt +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/README.md +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/_version.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/align/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/align/align.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/align/api.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/align/future.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/align/msa.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/align/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/align.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/assaydata.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/deprecated/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/deprecated/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/deprecated/poet.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/deprecated/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/deprecated/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/designer.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/embedding.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/error.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/fold.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/job.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/predictor.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/prompt.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/svd.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/api/umap.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/deprecated.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/align/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/align/base.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/align/msa.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/align/prompt.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/assaydata.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/deprecated/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/deprecated/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/deprecated/poet.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/deprecated/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/deprecated/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/designer.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/base.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/esm.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/future.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/openprotein.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/poet.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/poet2.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/embeddings/test.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/fold/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/fold/alphafold2.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/fold/base.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/fold/boltz.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/fold/esmfold.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/fold/future.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/futures.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/predictor/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/predictor/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/predictor/predictor.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/predictor/validate.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/prompt.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/svd.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/models/umap.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/align.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/assaydata.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/deprecated/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/deprecated/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/deprecated/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/deprecated/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/designer.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/embeddings.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/fold.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/job.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/predictor.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/prompt.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/svd.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/app/services/umap.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/base.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/chains.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/common/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/common/features.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/common/model_metadata.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/common/reduction.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/common/residue_contants.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/config.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/csv.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/data/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/data/api.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/data/assaydataset.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/data/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/design/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/design/api.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/design/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/design/future.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/design/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/future.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/embeddings/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/errors.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fasta.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/alphafold2.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/boltz.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/common.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/complex.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/esmfold.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/minifold.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/models.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/rosettafold3.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/fold/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/jobs/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/jobs/api.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/jobs/futures.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/base.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/foundation/boltzgen.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/foundation/boltzgen_schema.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/foundation/rfdiffusion.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/models/structure_generation.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/molecules/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/molecules/chains.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/molecules/structure.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/api.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/models.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/prediction.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/predictor.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/predictor/validate.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/prompt/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/protein.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/scaffolds.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/align.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/assaydata.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/deprecated/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/deprecated/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/deprecated/poet.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/deprecated/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/deprecated/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/design.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/designer.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/embeddings.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/features.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/fold.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/job.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/predict.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/predictor.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/prompt.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/svd.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/train.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/schemas/umap.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/svd/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/svd/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/svd/svd.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/umap/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/umap/schemas.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/utils/__init__.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/utils/chain_id.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/utils/cif.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/utils/numpy.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/utils/sequence.py +0 -0
- {openprotein_python-0.13.1 → openprotein_python-0.14.1}/openprotein/utils/uuid.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openprotein-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.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
|
|
@@ -14,7 +14,7 @@ Requires-Dist: pandas<3,>=2.2.2
|
|
|
14
14
|
Requires-Dist: pydantic<3,>=2.5
|
|
15
15
|
Requires-Dist: requests<3,>=2.32.3
|
|
16
16
|
Requires-Dist: tomli<3,>=2.3.0
|
|
17
|
-
Requires-Dist: tqdm<5,>=4.66.
|
|
17
|
+
Requires-Dist: tqdm<5,>=4.66.4
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
|
|
20
20
|
[](https://pypi.org/project/openprotein-python/)
|
|
@@ -20,6 +20,7 @@ from openprotein.fold import FoldAPI
|
|
|
20
20
|
from openprotein.models import ModelsAPI
|
|
21
21
|
from openprotein.svd import SVDAPI
|
|
22
22
|
from openprotein.umap import UMAPAPI
|
|
23
|
+
from openprotein.clustering import ClusteringAPI
|
|
23
24
|
from openprotein.predictor import PredictorAPI
|
|
24
25
|
from openprotein.design import DesignAPI
|
|
25
26
|
from openprotein.jobs import Future
|
|
@@ -38,6 +39,7 @@ class OpenProtein(APISession):
|
|
|
38
39
|
_embeddings = None
|
|
39
40
|
_svd = None
|
|
40
41
|
_umap = None
|
|
42
|
+
_clustering = None
|
|
41
43
|
_fold = None
|
|
42
44
|
_predictor = None
|
|
43
45
|
_design = None
|
|
@@ -81,7 +83,7 @@ class OpenProtein(APISession):
|
|
|
81
83
|
@property
|
|
82
84
|
def prompt(self) -> PromptAPI:
|
|
83
85
|
"""
|
|
84
|
-
The
|
|
86
|
+
The prompt submodule gives access to creating and retrieving prompts and queries used to condition PoET models.
|
|
85
87
|
"""
|
|
86
88
|
if self._prompt is None:
|
|
87
89
|
self._prompt = PromptAPI(self)
|
|
@@ -120,6 +122,15 @@ class OpenProtein(APISession):
|
|
|
120
122
|
)
|
|
121
123
|
return self._umap
|
|
122
124
|
|
|
125
|
+
@property
|
|
126
|
+
def clustering(self) -> ClusteringAPI:
|
|
127
|
+
"""The clustering API for fitting hierarchical clustering jobs."""
|
|
128
|
+
if self._clustering is None:
|
|
129
|
+
self._clustering = ClusteringAPI(
|
|
130
|
+
session=self,
|
|
131
|
+
)
|
|
132
|
+
return self._clustering
|
|
133
|
+
|
|
123
134
|
@property
|
|
124
135
|
def predictor(self) -> PredictorAPI:
|
|
125
136
|
"""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Clustering module for OpenProtein.
|
|
2
|
+
|
|
3
|
+
isort:skip_file
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .schemas import (
|
|
7
|
+
ClusteringMetadata,
|
|
8
|
+
HierarchicalClusteringResult,
|
|
9
|
+
HierarchicalFitJob,
|
|
10
|
+
LinkageMethod,
|
|
11
|
+
Metric,
|
|
12
|
+
)
|
|
13
|
+
from .models import HierarchicalClusteringFuture
|
|
14
|
+
from .clustering import ClusteringAPI
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Clustering REST API — HTTP calls to the backend."""
|
|
2
|
+
|
|
3
|
+
from pydantic import TypeAdapter
|
|
4
|
+
|
|
5
|
+
from openprotein.base import APISession
|
|
6
|
+
from openprotein.errors import APIError, InvalidParameterError
|
|
7
|
+
|
|
8
|
+
from .schemas import (
|
|
9
|
+
ClusteringMetadata,
|
|
10
|
+
HierarchicalClusteringResult,
|
|
11
|
+
HierarchicalFitJob,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
PATH_PREFIX = "v1/clustering"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def clustering_list_get(
|
|
18
|
+
session: APISession,
|
|
19
|
+
method: str | None = None,
|
|
20
|
+
limit: int | None = None,
|
|
21
|
+
offset: int | None = None,
|
|
22
|
+
) -> list[ClusteringMetadata]:
|
|
23
|
+
"""List clustering jobs, optionally filtered by method."""
|
|
24
|
+
params: dict = {}
|
|
25
|
+
if method is not None:
|
|
26
|
+
params["method"] = method
|
|
27
|
+
if limit is not None:
|
|
28
|
+
params["limit"] = limit
|
|
29
|
+
if offset is not None:
|
|
30
|
+
params["offset"] = offset
|
|
31
|
+
response = session.get(PATH_PREFIX, params=params or None)
|
|
32
|
+
return TypeAdapter(list[ClusteringMetadata]).validate_python(response.json())
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def clustering_get(session: APISession, clustering_id: str) -> ClusteringMetadata:
|
|
36
|
+
"""Fetch clustering job metadata."""
|
|
37
|
+
response = session.get(f"{PATH_PREFIX}/{clustering_id}")
|
|
38
|
+
return ClusteringMetadata.model_validate(response.json())
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def clustering_get_result(
|
|
42
|
+
session: APISession, clustering_id: str
|
|
43
|
+
) -> HierarchicalClusteringResult:
|
|
44
|
+
"""Fetch the clustering result (linkage + leaf_order). Sequences are NOT
|
|
45
|
+
filled by this function — callers that need them should call
|
|
46
|
+
`clustering_get_sequences` and assign to `.sequences`."""
|
|
47
|
+
response = session.get(f"{PATH_PREFIX}/{clustering_id}/result")
|
|
48
|
+
return HierarchicalClusteringResult.model_validate(response.json())
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def clustering_get_sequences(session: APISession, clustering_id: str) -> list[bytes]:
|
|
52
|
+
"""Fetch the input sequences used for the clustering job."""
|
|
53
|
+
response = session.get(f"{PATH_PREFIX}/{clustering_id}/sequences")
|
|
54
|
+
return TypeAdapter(list[bytes]).validate_python(response.json())
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def clustering_delete(session: APISession, clustering_id: str) -> bool:
|
|
58
|
+
"""Delete a clustering job."""
|
|
59
|
+
response = session.delete(f"{PATH_PREFIX}/{clustering_id}")
|
|
60
|
+
if 200 <= response.status_code < 300:
|
|
61
|
+
return True
|
|
62
|
+
raise APIError(response.text)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def clustering_redispatch_post(
|
|
66
|
+
session: APISession, clustering_id: str
|
|
67
|
+
) -> HierarchicalFitJob:
|
|
68
|
+
"""Redispatch a clustering job."""
|
|
69
|
+
response = session.post(f"{PATH_PREFIX}/{clustering_id}/redispatch")
|
|
70
|
+
return HierarchicalFitJob.model_validate(response.json())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def clustering_hierarchical_post(
|
|
74
|
+
session: APISession,
|
|
75
|
+
model_id: str,
|
|
76
|
+
feature_type: str,
|
|
77
|
+
linkage_method: str,
|
|
78
|
+
metric: str,
|
|
79
|
+
sequences: list[bytes] | list[str] | None = None,
|
|
80
|
+
assay_id: str | None = None,
|
|
81
|
+
reduction: str | None = None,
|
|
82
|
+
svd_id: str | None = None,
|
|
83
|
+
force_recompute: bool = False,
|
|
84
|
+
**kwargs,
|
|
85
|
+
) -> HierarchicalFitJob:
|
|
86
|
+
"""POST to create a hierarchical clustering fit job.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
force_recompute : bool
|
|
91
|
+
If True, send ?force=true so the backend bypasses the result cache and recomputes. Default: False.
|
|
92
|
+
"""
|
|
93
|
+
body: dict = {
|
|
94
|
+
"model_id": model_id,
|
|
95
|
+
"feature_type": feature_type,
|
|
96
|
+
"linkage_method": linkage_method,
|
|
97
|
+
"metric": metric,
|
|
98
|
+
}
|
|
99
|
+
if reduction is not None:
|
|
100
|
+
body["reduction"] = reduction
|
|
101
|
+
if svd_id is not None:
|
|
102
|
+
body["svd_id"] = svd_id
|
|
103
|
+
if sequences is not None:
|
|
104
|
+
if assay_id is not None:
|
|
105
|
+
raise InvalidParameterError("Expected only either sequences or assay_id")
|
|
106
|
+
body["sequences"] = [
|
|
107
|
+
(s if isinstance(s, str) else s.decode()) for s in sequences
|
|
108
|
+
]
|
|
109
|
+
else:
|
|
110
|
+
if assay_id is None:
|
|
111
|
+
raise InvalidParameterError("Expected either sequences or assay_id")
|
|
112
|
+
body["assay_id"] = assay_id
|
|
113
|
+
body.update(**kwargs)
|
|
114
|
+
|
|
115
|
+
params = {"force": "true"} if force_recompute else None
|
|
116
|
+
response = session.post(f"{PATH_PREFIX}/hierarchical", json=body, params=params)
|
|
117
|
+
return HierarchicalFitJob.model_validate(response.json())
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""ClusteringAPI — user-facing entry point for clustering jobs."""
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
from openprotein.base import APISession
|
|
6
|
+
from openprotein.common import Feature, FeatureType, Reduction, ReductionType
|
|
7
|
+
from openprotein.data import AssayDataset, AssayMetadata
|
|
8
|
+
from openprotein.embeddings import EmbeddingModel, EmbeddingsAPI
|
|
9
|
+
from openprotein.errors import InvalidParameterError
|
|
10
|
+
from openprotein.svd import SVDAPI, SVDModel
|
|
11
|
+
|
|
12
|
+
from . import api
|
|
13
|
+
from .models import HierarchicalClusteringFuture
|
|
14
|
+
from .schemas import LinkageMethod, Metric
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ClusteringAPI:
|
|
18
|
+
"""Top-level clustering API. Use `session.clustering.hierarchical(...)` to
|
|
19
|
+
fit a hierarchical clustering job on a sequence set."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, session: APISession):
|
|
22
|
+
self.session = session
|
|
23
|
+
|
|
24
|
+
@typing.overload
|
|
25
|
+
def hierarchical(
|
|
26
|
+
self,
|
|
27
|
+
model: EmbeddingModel,
|
|
28
|
+
reduction: Reduction | ReductionType,
|
|
29
|
+
feature_type: FeatureType = FeatureType.PLM,
|
|
30
|
+
linkage_method: LinkageMethod | str = LinkageMethod.WARD,
|
|
31
|
+
metric: Metric | str = Metric.EUCLIDEAN,
|
|
32
|
+
sequences: list[bytes] | list[str] | None = None,
|
|
33
|
+
assay: AssayDataset | AssayMetadata | str | None = None,
|
|
34
|
+
**kwargs,
|
|
35
|
+
) -> HierarchicalClusteringFuture: ...
|
|
36
|
+
|
|
37
|
+
@typing.overload
|
|
38
|
+
def hierarchical(
|
|
39
|
+
self,
|
|
40
|
+
model: SVDModel,
|
|
41
|
+
reduction: None = None,
|
|
42
|
+
feature_type: FeatureType = FeatureType.SVD,
|
|
43
|
+
linkage_method: LinkageMethod | str = LinkageMethod.WARD,
|
|
44
|
+
metric: Metric | str = Metric.EUCLIDEAN,
|
|
45
|
+
sequences: list[bytes] | list[str] | None = None,
|
|
46
|
+
assay: AssayDataset | AssayMetadata | str | None = None,
|
|
47
|
+
**kwargs,
|
|
48
|
+
) -> HierarchicalClusteringFuture: ...
|
|
49
|
+
|
|
50
|
+
def hierarchical(
|
|
51
|
+
self,
|
|
52
|
+
model: EmbeddingModel | SVDModel | str,
|
|
53
|
+
reduction: Reduction | ReductionType | None = None,
|
|
54
|
+
feature_type: Feature | FeatureType | None = None,
|
|
55
|
+
linkage_method: LinkageMethod | str = LinkageMethod.WARD,
|
|
56
|
+
metric: Metric | str = Metric.EUCLIDEAN,
|
|
57
|
+
sequences: list[bytes] | list[str] | None = None,
|
|
58
|
+
assay: AssayDataset | AssayMetadata | str | None = None,
|
|
59
|
+
**kwargs,
|
|
60
|
+
) -> HierarchicalClusteringFuture:
|
|
61
|
+
"""Fit a hierarchical clustering on sequences, returning a future
|
|
62
|
+
that resolves to a HierarchicalClusteringResult (scipy linkage + leaf order)."""
|
|
63
|
+
# resolve assay_id
|
|
64
|
+
assay_id = (
|
|
65
|
+
assay.assay_id
|
|
66
|
+
if isinstance(assay, AssayMetadata)
|
|
67
|
+
else assay.id if isinstance(assay, AssayDataset) else assay
|
|
68
|
+
)
|
|
69
|
+
if sequences is not None and assay_id is not None:
|
|
70
|
+
raise InvalidParameterError(
|
|
71
|
+
"Expected only either sequences or assay, not both"
|
|
72
|
+
)
|
|
73
|
+
if sequences is not None:
|
|
74
|
+
n = len(sequences)
|
|
75
|
+
if n < 2:
|
|
76
|
+
raise InvalidParameterError(
|
|
77
|
+
f"clustering requires at least 2 sequences, got {n}"
|
|
78
|
+
)
|
|
79
|
+
if n > 10000:
|
|
80
|
+
raise InvalidParameterError(
|
|
81
|
+
f"clustering size cap exceeded: N={n} > 10000"
|
|
82
|
+
)
|
|
83
|
+
# infer feature_type from model type
|
|
84
|
+
feature_type = (
|
|
85
|
+
FeatureType.PLM
|
|
86
|
+
if isinstance(model, EmbeddingModel)
|
|
87
|
+
else FeatureType.SVD if isinstance(model, SVDModel) else feature_type
|
|
88
|
+
)
|
|
89
|
+
if feature_type is None:
|
|
90
|
+
raise InvalidParameterError(
|
|
91
|
+
"Expected feature_type to be provided if passing str model_id as model"
|
|
92
|
+
)
|
|
93
|
+
if isinstance(feature_type, str):
|
|
94
|
+
feature_type = FeatureType(feature_type)
|
|
95
|
+
if isinstance(reduction, str):
|
|
96
|
+
reduction = ReductionType(reduction)
|
|
97
|
+
# combo validation — mirrors the Go server rule
|
|
98
|
+
_WARD_ONLY_METRICS = {"ward", "centroid", "median"}
|
|
99
|
+
lm_val = (
|
|
100
|
+
linkage_method.value
|
|
101
|
+
if isinstance(linkage_method, LinkageMethod)
|
|
102
|
+
else str(linkage_method)
|
|
103
|
+
)
|
|
104
|
+
m_val = metric.value if isinstance(metric, Metric) else str(metric)
|
|
105
|
+
if lm_val in _WARD_ONLY_METRICS and m_val != "euclidean":
|
|
106
|
+
raise InvalidParameterError(
|
|
107
|
+
f"linkage_method={lm_val!r} requires metric='euclidean', got {m_val!r}"
|
|
108
|
+
)
|
|
109
|
+
# resolve model_id and svd_id
|
|
110
|
+
svd_id: str | None = None
|
|
111
|
+
if feature_type == FeatureType.PLM:
|
|
112
|
+
if reduction is None:
|
|
113
|
+
raise InvalidParameterError(
|
|
114
|
+
"Expected reduction when using PLM feature_type"
|
|
115
|
+
)
|
|
116
|
+
if isinstance(model, str):
|
|
117
|
+
embeddings_api = getattr(self.session, "embedding", None)
|
|
118
|
+
assert isinstance(embeddings_api, EmbeddingsAPI)
|
|
119
|
+
model = embeddings_api.get_model(model)
|
|
120
|
+
assert isinstance(model, EmbeddingModel), "Expected EmbeddingModel"
|
|
121
|
+
model_id = model.id
|
|
122
|
+
elif feature_type == FeatureType.SVD:
|
|
123
|
+
if reduction is not None:
|
|
124
|
+
raise InvalidParameterError(
|
|
125
|
+
"Unexpected reduction when using SVD feature_type"
|
|
126
|
+
)
|
|
127
|
+
if isinstance(model, str):
|
|
128
|
+
svd_api = getattr(self.session, "svd", None)
|
|
129
|
+
assert isinstance(svd_api, SVDAPI)
|
|
130
|
+
model = svd_api.get_svd(model)
|
|
131
|
+
assert isinstance(model, SVDModel), "Expected SVDModel"
|
|
132
|
+
model_id = model.id
|
|
133
|
+
svd_id = model.id
|
|
134
|
+
else:
|
|
135
|
+
raise InvalidParameterError(f"Unsupported feature_type: {feature_type}")
|
|
136
|
+
|
|
137
|
+
linkage_method = (
|
|
138
|
+
linkage_method.value
|
|
139
|
+
if isinstance(linkage_method, LinkageMethod)
|
|
140
|
+
else str(linkage_method)
|
|
141
|
+
)
|
|
142
|
+
metric = metric.value if isinstance(metric, Metric) else str(metric)
|
|
143
|
+
reduction_str = (
|
|
144
|
+
reduction.value if isinstance(reduction, ReductionType) else reduction
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Advanced flags such as `force_recompute` are accepted via **kwargs
|
|
148
|
+
# only (intentionally kept out of the typed signature / autocomplete):
|
|
149
|
+
# they bypass the backend result cache and are easy to misuse.
|
|
150
|
+
job = api.clustering_hierarchical_post(
|
|
151
|
+
session=self.session,
|
|
152
|
+
model_id=model_id,
|
|
153
|
+
feature_type=feature_type.value,
|
|
154
|
+
linkage_method=linkage_method,
|
|
155
|
+
metric=metric,
|
|
156
|
+
sequences=sequences,
|
|
157
|
+
assay_id=assay_id,
|
|
158
|
+
reduction=reduction_str,
|
|
159
|
+
svd_id=svd_id,
|
|
160
|
+
**kwargs,
|
|
161
|
+
)
|
|
162
|
+
return HierarchicalClusteringFuture(session=self.session, job=job)
|
|
163
|
+
|
|
164
|
+
def get(self, clustering_id: str) -> HierarchicalClusteringFuture:
|
|
165
|
+
"""Fetch a clustering job by ID."""
|
|
166
|
+
# Single-method dispatch today; when new methods are added,
|
|
167
|
+
# branch on metadata.method to pick the concrete future type.
|
|
168
|
+
metadata = api.clustering_get(self.session, clustering_id)
|
|
169
|
+
return HierarchicalClusteringFuture(session=self.session, metadata=metadata)
|
|
170
|
+
|
|
171
|
+
def list(
|
|
172
|
+
self,
|
|
173
|
+
method: str | None = None,
|
|
174
|
+
limit: int | None = None,
|
|
175
|
+
offset: int | None = None,
|
|
176
|
+
) -> list[HierarchicalClusteringFuture]:
|
|
177
|
+
"""List clustering jobs, optionally filtering by method.
|
|
178
|
+
|
|
179
|
+
Pass `limit` / `offset` to paginate (the clustering list endpoint
|
|
180
|
+
uses `limit`/`offset`, unlike the `jobs` endpoint's page_size/page_offset)."""
|
|
181
|
+
# Single-method dispatch today; when new methods are added,
|
|
182
|
+
# branch on metadata.method to pick the concrete future type.
|
|
183
|
+
return [
|
|
184
|
+
HierarchicalClusteringFuture(session=self.session, metadata=md)
|
|
185
|
+
for md in api.clustering_list_get(
|
|
186
|
+
self.session,
|
|
187
|
+
method=method,
|
|
188
|
+
limit=limit,
|
|
189
|
+
offset=offset,
|
|
190
|
+
)
|
|
191
|
+
]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""HierarchicalClusteringFuture — the future type returned by ClusteringAPI calls."""
|
|
2
|
+
|
|
3
|
+
from openprotein.base import APISession
|
|
4
|
+
from openprotein.jobs import Future, JobsAPI
|
|
5
|
+
|
|
6
|
+
from . import api
|
|
7
|
+
from .schemas import ClusteringMetadata, HierarchicalClusteringResult, HierarchicalFitJob
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HierarchicalClusteringFuture(Future["HierarchicalClusteringResult"]):
|
|
11
|
+
"""Future for a hierarchical clustering job. Waits for the fit job to complete, then
|
|
12
|
+
returns a HierarchicalClusteringResult (linkage + leaf_order + sequences)."""
|
|
13
|
+
|
|
14
|
+
job: HierarchicalFitJob
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
session: APISession,
|
|
19
|
+
job: HierarchicalFitJob | None = None,
|
|
20
|
+
metadata: ClusteringMetadata | None = None,
|
|
21
|
+
):
|
|
22
|
+
if metadata is None:
|
|
23
|
+
if job is None:
|
|
24
|
+
raise ValueError("Expected clustering metadata or job")
|
|
25
|
+
metadata = api.clustering_get(session, job.job_id)
|
|
26
|
+
self._metadata = metadata
|
|
27
|
+
if job is None:
|
|
28
|
+
jobs_api = getattr(session, "jobs", None)
|
|
29
|
+
assert isinstance(jobs_api, JobsAPI)
|
|
30
|
+
job = HierarchicalFitJob.create(
|
|
31
|
+
jobs_api.get_job(job_id=metadata.id)
|
|
32
|
+
)
|
|
33
|
+
self._sequences: list[bytes] | None = None
|
|
34
|
+
super().__init__(session, job)
|
|
35
|
+
|
|
36
|
+
def __str__(self) -> str:
|
|
37
|
+
return str(self.metadata)
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
return repr(self.metadata)
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def id(self) -> str:
|
|
44
|
+
return self._metadata.id
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def metadata(self) -> ClusteringMetadata:
|
|
48
|
+
"""Metadata — lazily refreshes until the job reaches a terminal state."""
|
|
49
|
+
if not self._metadata.is_done():
|
|
50
|
+
self._metadata = api.clustering_get(self.session, self._metadata.id)
|
|
51
|
+
return self._metadata
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def sequences(self) -> list[bytes]:
|
|
55
|
+
"""Input sequences used to fit the clustering job (cached)."""
|
|
56
|
+
if self._sequences is None:
|
|
57
|
+
self._sequences = api.clustering_get_sequences(
|
|
58
|
+
session=self.session, clustering_id=self.id
|
|
59
|
+
)
|
|
60
|
+
return self._sequences
|
|
61
|
+
|
|
62
|
+
def _get(self, verbose: bool = False) -> HierarchicalClusteringResult:
|
|
63
|
+
"""Fetch the clustering result. Called by Future.get after SUCCESS."""
|
|
64
|
+
result = api.clustering_get_result(self.session, self.id)
|
|
65
|
+
result.sequences = self.sequences
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
def delete(self) -> bool:
|
|
69
|
+
"""Delete this clustering job."""
|
|
70
|
+
return api.clustering_delete(self.session, self.id)
|
|
71
|
+
|
|
72
|
+
def redispatch(self) -> "HierarchicalClusteringFuture":
|
|
73
|
+
"""Redispatch this clustering job."""
|
|
74
|
+
job = api.clustering_redispatch_post(self.session, self.id)
|
|
75
|
+
return HierarchicalClusteringFuture(session=self.session, job=job)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Schemas for OpenProtein clustering."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
9
|
+
|
|
10
|
+
from openprotein.common import FeatureType
|
|
11
|
+
from openprotein.jobs import Job, JobStatus, JobType
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LinkageMethod(str, Enum):
|
|
15
|
+
"""Hierarchical clustering linkage methods (scipy.cluster.hierarchy)."""
|
|
16
|
+
|
|
17
|
+
WARD = "ward"
|
|
18
|
+
SINGLE = "single"
|
|
19
|
+
COMPLETE = "complete"
|
|
20
|
+
AVERAGE = "average"
|
|
21
|
+
WEIGHTED = "weighted"
|
|
22
|
+
CENTROID = "centroid"
|
|
23
|
+
MEDIAN = "median"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Metric(str, Enum):
|
|
27
|
+
"""Pairwise distance metrics supported by scipy.spatial.distance.pdist."""
|
|
28
|
+
|
|
29
|
+
EUCLIDEAN = "euclidean"
|
|
30
|
+
COSINE = "cosine"
|
|
31
|
+
CORRELATION = "correlation"
|
|
32
|
+
HAMMING = "hamming"
|
|
33
|
+
CHEBYSHEV = "chebyshev"
|
|
34
|
+
CITYBLOCK = "cityblock"
|
|
35
|
+
SQEUCLIDEAN = "sqeuclidean"
|
|
36
|
+
CANBERRA = "canberra"
|
|
37
|
+
BRAYCURTIS = "braycurtis"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ClusteringMetadata(BaseModel):
|
|
41
|
+
id: str
|
|
42
|
+
status: JobStatus
|
|
43
|
+
created_date: datetime | None = None
|
|
44
|
+
method: str
|
|
45
|
+
linkage_method: LinkageMethod | None = None
|
|
46
|
+
metric: Metric | None = None
|
|
47
|
+
model_id: str
|
|
48
|
+
feature_type: FeatureType
|
|
49
|
+
reduction: str | None = None
|
|
50
|
+
svd_id: str | None = None
|
|
51
|
+
|
|
52
|
+
def is_done(self) -> bool:
|
|
53
|
+
return self.status.done()
|
|
54
|
+
|
|
55
|
+
model_config = ConfigDict(protected_namespaces=())
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class HierarchicalFitJob(Job):
|
|
59
|
+
job_type: Literal[JobType.clustering_hierarchical]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class HierarchicalClusteringResult(BaseModel):
|
|
63
|
+
"""Result of a hierarchical clustering job.
|
|
64
|
+
|
|
65
|
+
`linkage` is the scipy linkage matrix with shape (N-1, 4); pass it
|
|
66
|
+
directly to `scipy.cluster.hierarchy.dendrogram` or `fcluster`.
|
|
67
|
+
`sequences` is filled by `HierarchicalClusteringFuture._get` after the API fetch.
|
|
68
|
+
|
|
69
|
+
Note: `linkage` is a numpy array, so this model is not JSON-serializable via
|
|
70
|
+
`model_dump_json()` (use `linkage.tolist()` first if you need to serialize).
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
n_leaves: int
|
|
74
|
+
linkage: np.ndarray
|
|
75
|
+
leaf_order: list[int]
|
|
76
|
+
sequences: list[bytes] = Field(default_factory=list)
|
|
77
|
+
|
|
78
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
79
|
+
|
|
80
|
+
@field_validator("linkage", mode="before")
|
|
81
|
+
@classmethod
|
|
82
|
+
def _to_ndarray(cls, v):
|
|
83
|
+
if isinstance(v, np.ndarray):
|
|
84
|
+
return v
|
|
85
|
+
return np.asarray(v, dtype=float)
|
|
@@ -14,9 +14,11 @@ class DataAPI:
|
|
|
14
14
|
def __init__(self, session: APISession):
|
|
15
15
|
self.session = session
|
|
16
16
|
|
|
17
|
+
# `list` shadows the builtin, so the return annotation is quoted to keep it
|
|
18
|
+
# resolving to the builtin (not this method) under PEP 649 deferred evaluation.
|
|
17
19
|
def list(
|
|
18
20
|
self, limit: int | None = None, offset: int | None = None
|
|
19
|
-
) -> list[AssayDataset]:
|
|
21
|
+
) -> "list[AssayDataset]":
|
|
20
22
|
"""
|
|
21
23
|
List all assay datasets.
|
|
22
24
|
|
|
@@ -11,7 +11,7 @@ class AbLang2Model(EmbeddingModel):
|
|
|
11
11
|
--------
|
|
12
12
|
View specific model details (inc supported tokens) with the `?` operator.
|
|
13
13
|
|
|
14
|
-
.. code-block::
|
|
14
|
+
.. code-block:: ipython3
|
|
15
15
|
|
|
16
16
|
>>> import openprotein
|
|
17
17
|
>>> session = openprotein.connect(username="user", password="password")
|