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.
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/PKG-INFO +2 -1
- openprotein_python-0.16.0/openprotein/auth_store.py +79 -0
- openprotein_python-0.16.0/openprotein/base.py +372 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/models.py +14 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/poet.py +14 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/poet2.py +14 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/common.py +15 -27
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/__init__.py +1 -0
- openprotein_python-0.16.0/openprotein/models/foundation/solublempnn.py +25 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/models.py +2 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/protein.py +9 -6
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/__init__.py +1 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/api.py +17 -4
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/predictor.py +33 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/schemas.py +15 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/models.py +14 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/pyproject.toml +1 -0
- openprotein_python-0.14.2/openprotein/base.py +0 -181
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/.gitignore +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/LICENSE.txt +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/README.md +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/_version.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/align.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/future.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/msa.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/align/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/align.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/assaydata.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/poet.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/deprecated/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/designer.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/embedding.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/error.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/fold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/job.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/predictor.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/prompt.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/svd.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/api/umap.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/deprecated.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/base.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/msa.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/align/prompt.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/assaydata.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/poet.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/deprecated/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/designer.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/base.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/esm.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/future.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/openprotein.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/poet.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/poet2.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/embeddings/test.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/alphafold2.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/base.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/boltz.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/esmfold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/fold/future.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/futures.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/predictor.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/predictor/validate.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/prompt.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/svd.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/models/umap.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/align.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/assaydata.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/deprecated/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/designer.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/embeddings.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/fold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/job.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/predictor.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/prompt.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/svd.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/app/services/umap.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/chains.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/clustering.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/models.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/clustering/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/features.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/model_metadata.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/reduction.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/common/residue_contants.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/config.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/csv.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/assaydataset.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/data.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/data/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/future.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/design/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/ablang.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/embeddings.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/esm.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/future.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/openprotein.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/embeddings/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/errors.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fasta.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/alphafold2.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/boltz.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/complex.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/esmfold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/esmfold2.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/fold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/future.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/minifold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/models.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/protenix.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/rosettafold3.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/fold/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/futures.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/jobs.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/jobs/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/base.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/boltzgen.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/boltzgen_schema.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/esmif1.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/proteinmpnn.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/foundation/rfdiffusion.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/models/structure_generation.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/chains.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/complex.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/structure.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/molecules/template.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/models.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/prediction.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/predictor/validate.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/models.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/prompt.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/prompt/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/protein.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/scaffolds.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/align.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/assaydata.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/poet.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/deprecated/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/design.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/designer.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/embeddings.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/features.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/fold.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/job.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/predict.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/predictor.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/prompt.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/svd.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/train.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/schemas/umap.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/svd/svd.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/api.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/models.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/schemas.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/umap/umap.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/__init__.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/chain_id.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/cif.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/numpy.py +0 -0
- {openprotein_python-0.14.2 → openprotein_python-0.16.0}/openprotein/utils/sequence.py +0 -0
- {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.
|
|
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,
|
|
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
|
-
#
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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"
|