dyno-phi 0.2.0__tar.gz → 0.2.2__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.
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/CHANGELOG.md +10 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/CLI-REFERENCE.md +1 -1
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/PKG-INFO +18 -26
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/README.md +17 -25
- dyno_phi-0.2.2/src/phi/_version.py +1 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/cli.py +2 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/models.py +12 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/research.py +2 -6
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/structure.py +2 -4
- dyno_phi-0.2.2/src/phi/commands/tutorial.py +88 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/display.py +2 -1
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/parser.py +21 -9
- dyno_phi-0.2.0/src/phi/_version.py +0 -1
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.claude/settings.json +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.claude/skills/phi/SKILL.md +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.claude-plugin/marketplace.json +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.github/workflows/ci.yml +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.github/workflows/publish.yml +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.gitignore +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/.pre-commit-config.yaml +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/LICENSE +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/TEMPLATE_NEW_BIOMODAL.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/__init__.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/base.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_af2rank.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_align_structures.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_alphafold.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_bindcraft.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_boltz.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_boltzgen.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_chai1.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_esm2_predict_masked.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_esmfold.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_ligandmpnn.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_proteinmpnn.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_rf3.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_rfdiffusion3.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_rso.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/modal_tm_score.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/utils/__init__.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/utils/extract_chain_as_mol2.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/biomodals/utils/extract_ligands.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/README.md +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/binders/pdl1/binder_009.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/binders/pdl1/binder_047.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/binders/pdl1/binder_106.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/binders/pdl1/binder_188.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/binders/pdl1/binder_246.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/fixtures/pdl1/5O45.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/examples/fixtures/pdl1/pdl1_pdb_19_132.pdb +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/phi-plugin/.claude-plugin/plugin.json +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/phi-plugin/README.md +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/phi-plugin/skills/phi/SKILL.md +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/pyproject.toml +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/__init__.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/api.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/__init__.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/auth.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/datasets.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/filter.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/commands/jobs.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/config.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/download.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/polling.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/research.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/structure.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/types.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/src/phi/upload.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/__init__.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_api.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_config.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_display.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_download.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_research.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_structure.py +0 -0
- {dyno_phi-0.2.0 → dyno_phi-0.2.2}/tests/test_upload.py +0 -0
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.2] - 2026-03-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `phi tutorial` — downloads example PD-L1 binder structures from the API and prints a step-by-step scoring walkthrough
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- GCS internal paths (`gs://...`) no longer shown in status output, research notes, or `phi fetch` results
|
|
17
|
+
- `phi design` / `phi boltzgen` feature-flagged behind `DYNO_ENABLE_DESIGN=1` env var
|
|
18
|
+
- macOS SSL certificate error when downloading tutorial files via signed URLs
|
|
19
|
+
|
|
10
20
|
## [0.2.0] - 2026-03-17
|
|
11
21
|
|
|
12
22
|
### Added
|
|
@@ -5,7 +5,7 @@ Submit and monitor computational biology jobs, manage datasets, run structure
|
|
|
5
5
|
prediction and inverse-folding pipelines, and download results — all from your
|
|
6
6
|
terminal.
|
|
7
7
|
|
|
8
|
-
**Version:** 0.2.
|
|
8
|
+
**Version:** 0.2.2 · **Package:** `dyno-phi` · **Requires:** Python ≥ 3.9
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dyno-phi
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Phi CLI and biomodals for the dyno protein design platform
|
|
5
5
|
Project-URL: Homepage, https://dynotx.com
|
|
6
6
|
Project-URL: Repository, https://github.com/dynotx/phi-cli
|
|
@@ -97,43 +97,34 @@ phi login
|
|
|
97
97
|
|
|
98
98
|
## Quick start
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### Try the tutorial
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
phi folding --fasta sequences.fasta
|
|
105
|
-
|
|
106
|
-
# Complex structure prediction (AlphaFold2 multimer)
|
|
107
|
-
phi complex_folding --fasta binder_target.fasta
|
|
102
|
+
The fastest way to get started — downloads five example PD-L1 binder structures
|
|
103
|
+
and walks you through the full pipeline:
|
|
108
104
|
|
|
109
|
-
|
|
110
|
-
phi
|
|
105
|
+
```bash
|
|
106
|
+
phi tutorial
|
|
111
107
|
```
|
|
112
108
|
|
|
113
|
-
|
|
109
|
+
This fetches the example files, prints step-by-step instructions, and leaves
|
|
110
|
+
you ready to run `phi filter`.
|
|
111
|
+
|
|
112
|
+
### Scoring your own structures
|
|
114
113
|
|
|
115
114
|
```bash
|
|
116
|
-
# 1. Upload
|
|
115
|
+
# 1. Upload PDB/CIF files
|
|
117
116
|
phi upload ./designs/
|
|
118
117
|
|
|
119
|
-
#
|
|
120
|
-
|
|
121
|
-
# Dashboard: https://design.dynotx.com/dashboard/datasets/d7c3a1b2-...
|
|
122
|
-
# Run a job against this dataset:
|
|
123
|
-
# phi folding --dataset-id d7c3a1b2-...
|
|
124
|
-
# phi complex_folding --dataset-id d7c3a1b2-...
|
|
125
|
-
# phi inverse_folding --dataset-id d7c3a1b2-...
|
|
126
|
-
# phi filter --dataset-id d7c3a1b2-... --preset default --wait
|
|
127
|
-
|
|
128
|
-
# 2. Run the full filter pipeline (inverse folding → folding → complex folding → score)
|
|
129
|
-
phi filter --dataset-id d7c3a1b2-... --preset default --wait
|
|
118
|
+
# 2. Run the full filter pipeline
|
|
119
|
+
phi filter --preset default --wait
|
|
130
120
|
|
|
131
|
-
# 3.
|
|
121
|
+
# 3. View scores and download results
|
|
122
|
+
phi scores
|
|
132
123
|
phi download --out ./results/
|
|
133
124
|
```
|
|
134
125
|
|
|
135
|
-
After each command, `phi` prints the active dataset and
|
|
136
|
-
|
|
126
|
+
After each command, `phi` prints the active dataset and a link to the
|
|
127
|
+
dashboard:
|
|
137
128
|
|
|
138
129
|
```
|
|
139
130
|
Active: dataset [d7c3a1b2-...] · job [cb4553f5-...]
|
|
@@ -146,6 +137,7 @@ Dashboard: https://design.dynotx.com/dashboard/datasets/d7c3a1b2-...
|
|
|
146
137
|
|
|
147
138
|
| Command | Alias | Description |
|
|
148
139
|
|---|---|---|
|
|
140
|
+
| `phi tutorial` | — | Download example structures and print a step-by-step walkthrough |
|
|
149
141
|
| `phi login` | — | Verify API key and print identity |
|
|
150
142
|
| `phi upload` | — | Upload PDB/CIF files or a directory |
|
|
151
143
|
| `phi fetch` | — | Download a structure from RCSB PDB or AlphaFold DB, crop, and optionally upload |
|
|
@@ -56,43 +56,34 @@ phi login
|
|
|
56
56
|
|
|
57
57
|
## Quick start
|
|
58
58
|
|
|
59
|
-
###
|
|
59
|
+
### Try the tutorial
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
phi folding --fasta sequences.fasta
|
|
64
|
-
|
|
65
|
-
# Complex structure prediction (AlphaFold2 multimer)
|
|
66
|
-
phi complex_folding --fasta binder_target.fasta
|
|
61
|
+
The fastest way to get started — downloads five example PD-L1 binder structures
|
|
62
|
+
and walks you through the full pipeline:
|
|
67
63
|
|
|
68
|
-
|
|
69
|
-
phi
|
|
64
|
+
```bash
|
|
65
|
+
phi tutorial
|
|
70
66
|
```
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
This fetches the example files, prints step-by-step instructions, and leaves
|
|
69
|
+
you ready to run `phi filter`.
|
|
70
|
+
|
|
71
|
+
### Scoring your own structures
|
|
73
72
|
|
|
74
73
|
```bash
|
|
75
|
-
# 1. Upload
|
|
74
|
+
# 1. Upload PDB/CIF files
|
|
76
75
|
phi upload ./designs/
|
|
77
76
|
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
# Dashboard: https://design.dynotx.com/dashboard/datasets/d7c3a1b2-...
|
|
81
|
-
# Run a job against this dataset:
|
|
82
|
-
# phi folding --dataset-id d7c3a1b2-...
|
|
83
|
-
# phi complex_folding --dataset-id d7c3a1b2-...
|
|
84
|
-
# phi inverse_folding --dataset-id d7c3a1b2-...
|
|
85
|
-
# phi filter --dataset-id d7c3a1b2-... --preset default --wait
|
|
86
|
-
|
|
87
|
-
# 2. Run the full filter pipeline (inverse folding → folding → complex folding → score)
|
|
88
|
-
phi filter --dataset-id d7c3a1b2-... --preset default --wait
|
|
77
|
+
# 2. Run the full filter pipeline
|
|
78
|
+
phi filter --preset default --wait
|
|
89
79
|
|
|
90
|
-
# 3.
|
|
80
|
+
# 3. View scores and download results
|
|
81
|
+
phi scores
|
|
91
82
|
phi download --out ./results/
|
|
92
83
|
```
|
|
93
84
|
|
|
94
|
-
After each command, `phi` prints the active dataset and
|
|
95
|
-
|
|
85
|
+
After each command, `phi` prints the active dataset and a link to the
|
|
86
|
+
dashboard:
|
|
96
87
|
|
|
97
88
|
```
|
|
98
89
|
Active: dataset [d7c3a1b2-...] · job [cb4553f5-...]
|
|
@@ -105,6 +96,7 @@ Dashboard: https://design.dynotx.com/dashboard/datasets/d7c3a1b2-...
|
|
|
105
96
|
|
|
106
97
|
| Command | Alias | Description |
|
|
107
98
|
|---|---|---|
|
|
99
|
+
| `phi tutorial` | — | Download example structures and print a step-by-step walkthrough |
|
|
108
100
|
| `phi login` | — | Verify API key and print identity |
|
|
109
101
|
| `phi upload` | — | Upload PDB/CIF files or a directory |
|
|
110
102
|
| `phi fetch` | — | Download a structure from RCSB PDB or AlphaFold DB, crop, and optionally upload |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.2"
|
|
@@ -16,6 +16,7 @@ from phi.commands.models import (
|
|
|
16
16
|
)
|
|
17
17
|
from phi.commands.research import cmd_notes, cmd_research
|
|
18
18
|
from phi.commands.structure import cmd_fetch
|
|
19
|
+
from phi.commands.tutorial import cmd_tutorial
|
|
19
20
|
from phi.config import _load_state
|
|
20
21
|
from phi.display import _C_BLUE, _die, console
|
|
21
22
|
from phi.parser import build_parser
|
|
@@ -23,6 +24,7 @@ from phi.types import PhiApiError
|
|
|
23
24
|
|
|
24
25
|
COMMANDS = {
|
|
25
26
|
"login": cmd_login,
|
|
27
|
+
"tutorial": cmd_tutorial,
|
|
26
28
|
"upload": cmd_upload,
|
|
27
29
|
"ingest-session": cmd_ingest_session,
|
|
28
30
|
"datasets": cmd_datasets,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import argparse
|
|
4
|
+
import os
|
|
2
5
|
from pathlib import Path
|
|
3
6
|
|
|
4
7
|
from phi.api import _require_key, _submit
|
|
@@ -6,6 +9,13 @@ from phi.display import _die, _print_status, _print_submission, console
|
|
|
6
9
|
from phi.download import _download_job, _read_fasta
|
|
7
10
|
from phi.polling import _poll
|
|
8
11
|
|
|
12
|
+
_DESIGN_ENABLED = os.environ.get("DYNO_ENABLE_DESIGN", "").lower() in ("1", "true", "yes")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _require_design_flag() -> None:
|
|
16
|
+
if not _DESIGN_ENABLED:
|
|
17
|
+
_die("This command is not yet available.")
|
|
18
|
+
|
|
9
19
|
|
|
10
20
|
def _run_model_job(job_type: str, params: dict, args: argparse.Namespace) -> None:
|
|
11
21
|
from phi.config import POLL_INTERVAL as _INTERVAL
|
|
@@ -92,6 +102,7 @@ def cmd_boltz(args: argparse.Namespace) -> None:
|
|
|
92
102
|
|
|
93
103
|
|
|
94
104
|
def cmd_rfdiffusion3(args: argparse.Namespace) -> None:
|
|
105
|
+
_require_design_flag()
|
|
95
106
|
params: dict = {
|
|
96
107
|
"num_designs": args.num_designs,
|
|
97
108
|
"inference_steps": args.steps,
|
|
@@ -129,6 +140,7 @@ def cmd_rfdiffusion3(args: argparse.Namespace) -> None:
|
|
|
129
140
|
|
|
130
141
|
|
|
131
142
|
def cmd_boltzgen(args: argparse.Namespace) -> None:
|
|
143
|
+
_require_design_flag()
|
|
132
144
|
params: dict = {
|
|
133
145
|
"protocol": args.protocol,
|
|
134
146
|
"num_designs": args.num_designs,
|
|
@@ -111,8 +111,8 @@ def cmd_notes(args: argparse.Namespace) -> None:
|
|
|
111
111
|
return
|
|
112
112
|
|
|
113
113
|
content: str = data.get("content") or ""
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
data.get("gcs_url")
|
|
115
|
+
data.get("gcs_uri")
|
|
116
116
|
|
|
117
117
|
if args.out:
|
|
118
118
|
out = Path(args.out)
|
|
@@ -124,8 +124,6 @@ def cmd_notes(args: argparse.Namespace) -> None:
|
|
|
124
124
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
125
125
|
dest.write_text(content, encoding="utf-8")
|
|
126
126
|
console.print(f"[{_C_SAND}]Notes saved[/] → {dest}")
|
|
127
|
-
if gcs_url:
|
|
128
|
-
console.print(f"[dim]Download URL:[/] {gcs_url}")
|
|
129
127
|
return
|
|
130
128
|
|
|
131
129
|
if args.json:
|
|
@@ -141,5 +139,3 @@ def cmd_notes(args: argparse.Namespace) -> None:
|
|
|
141
139
|
padding=(1, 2),
|
|
142
140
|
)
|
|
143
141
|
)
|
|
144
|
-
if gcs_uri:
|
|
145
|
-
console.print(f"[dim]Storage URI:[/] {gcs_uri}")
|
|
@@ -153,14 +153,12 @@ def _fetch_and_upload(
|
|
|
153
153
|
("Source ", source_url),
|
|
154
154
|
("File ", str(out_path)),
|
|
155
155
|
("Dataset ", dataset_id),
|
|
156
|
-
("GCS URI ", gcs_uri),
|
|
157
156
|
]:
|
|
158
157
|
console.print(f" [bold]{label}[/bold] {value}")
|
|
159
158
|
console.print()
|
|
160
159
|
console.print(" [dim]Next steps:[/dim]")
|
|
161
|
-
console.print(
|
|
162
|
-
|
|
163
|
-
)
|
|
160
|
+
console.print(f" [dim] phi upload {out_path}[/dim]")
|
|
161
|
+
console.print(" [dim] phi filter --preset default --wait[/dim]")
|
|
164
162
|
console.rule()
|
|
165
163
|
|
|
166
164
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import urllib.request
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from phi.api import _request
|
|
8
|
+
from phi.config import _save_state, _ssl_context
|
|
9
|
+
from phi.display import _C_BLUE, _C_SAND, _die, console
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def cmd_tutorial(args: argparse.Namespace) -> None:
|
|
13
|
+
out = Path(args.out)
|
|
14
|
+
|
|
15
|
+
# ── 1. Fetch manifest (standard Clerk JWT auth, same as all endpoints) ───
|
|
16
|
+
console.print("[dim]Fetching tutorial dataset …[/]")
|
|
17
|
+
try:
|
|
18
|
+
manifest = _request("GET", "/tutorial")
|
|
19
|
+
except Exception as exc:
|
|
20
|
+
_die(
|
|
21
|
+
f"Could not reach the tutorial endpoint: {exc}\n"
|
|
22
|
+
" Check your connection and API key, then try again."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
files: list[dict] = manifest.get("files", [])
|
|
26
|
+
dataset_id: str | None = manifest.get("dataset_id")
|
|
27
|
+
message: str | None = manifest.get("message")
|
|
28
|
+
|
|
29
|
+
if not files:
|
|
30
|
+
_die("No tutorial files returned by the API.")
|
|
31
|
+
|
|
32
|
+
# ── 2. Download each file (plain HTTP — signed URLs are self-authenticating)
|
|
33
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
console.print(f" Downloading {len(files)} file(s) to [{_C_BLUE}]{out}/[/] …\n")
|
|
35
|
+
|
|
36
|
+
for entry in files:
|
|
37
|
+
filename: str = entry["filename"]
|
|
38
|
+
url: str = entry["url"]
|
|
39
|
+
dest = out / filename
|
|
40
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
try:
|
|
42
|
+
req = urllib.request.Request(url)
|
|
43
|
+
with urllib.request.urlopen(req, context=_ssl_context()) as resp:
|
|
44
|
+
dest.write_bytes(resp.read())
|
|
45
|
+
console.print(f" [bold {_C_SAND}]✓[/] {filename}")
|
|
46
|
+
except Exception as exc:
|
|
47
|
+
_die(f"Failed to download {filename}: {exc}")
|
|
48
|
+
|
|
49
|
+
# ── 3. Cache dataset_id so phi filter needs zero extra flags ─────────────
|
|
50
|
+
if dataset_id:
|
|
51
|
+
_save_state({"dataset_id": dataset_id})
|
|
52
|
+
console.print(
|
|
53
|
+
f"\n[dim]dataset_id [{_C_BLUE}]{dataset_id}[/] cached — "
|
|
54
|
+
f"run [bold]phi filter[/] to start scoring.[/]"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# ── 4. Print step-by-step guide ──────────────────────────────────────────
|
|
58
|
+
if message:
|
|
59
|
+
console.print(f"\n[dim]{message}[/]")
|
|
60
|
+
|
|
61
|
+
if dataset_id:
|
|
62
|
+
upload_step = "[dim] (skipped — dataset already ready)[/]"
|
|
63
|
+
else:
|
|
64
|
+
upload_step = f" [{_C_SAND}]phi upload {out}/[/]"
|
|
65
|
+
|
|
66
|
+
console.print(f"""
|
|
67
|
+
[bold]── Tutorial: PD-L1 binder scoring pipeline ──────────────────[/]
|
|
68
|
+
|
|
69
|
+
You have {len(files)} example binder structures in [{_C_BLUE}]{out}/[/].
|
|
70
|
+
|
|
71
|
+
[bold]Step 1 — Upload[/]
|
|
72
|
+
{upload_step}
|
|
73
|
+
|
|
74
|
+
[bold]Step 2 — Run the filter pipeline[/]
|
|
75
|
+
[{_C_SAND}]phi filter --preset default --wait[/]
|
|
76
|
+
|
|
77
|
+
Runs: ProteinMPNN → ESMFold → AlphaFold2 → score
|
|
78
|
+
Typical runtime: 10–30 min for {len(files)} structures.
|
|
79
|
+
|
|
80
|
+
[bold]Step 3 — View scores[/]
|
|
81
|
+
[{_C_SAND}]phi scores[/]
|
|
82
|
+
|
|
83
|
+
[bold]Step 4 — Download results[/]
|
|
84
|
+
[{_C_SAND}]phi download --out ./results[/]
|
|
85
|
+
|
|
86
|
+
[bold]Dashboard[/]
|
|
87
|
+
[{_C_BLUE}]https://design.dynotx.com/dashboard[/]
|
|
88
|
+
""")
|
|
@@ -272,7 +272,8 @@ def _print_status(s: dict) -> None:
|
|
|
272
272
|
table.add_column("filename", style=_C_BLUE, no_wrap=True)
|
|
273
273
|
table.add_column("type", style="dim")
|
|
274
274
|
for f in files[:10]:
|
|
275
|
-
|
|
275
|
+
raw = f.get("filename") or f.get("gcs_url", "?")
|
|
276
|
+
fname = raw.split("/")[-1] if raw.startswith("gs://") else raw
|
|
276
277
|
ftype = f.get("artifact_type", "")
|
|
277
278
|
table.add_row(fname, ftype)
|
|
278
279
|
if len(files) > 10:
|
|
@@ -4,15 +4,16 @@ from phi._version import __version__
|
|
|
4
4
|
from phi.config import _FILTER_PRESETS, POLL_INTERVAL
|
|
5
5
|
|
|
6
6
|
_CLI_EPILOG = """\
|
|
7
|
+
Quick start:
|
|
8
|
+
phi tutorial # download example structures + print step-by-step guide
|
|
9
|
+
phi filter --preset default --wait
|
|
10
|
+
phi scores
|
|
11
|
+
phi download --out ./results
|
|
12
|
+
|
|
7
13
|
Fetch and prepare target structures:
|
|
8
14
|
phi fetch --pdb 4ZQK --chain A --residues 56-290 --out target.pdb
|
|
9
15
|
phi fetch --uniprot Q9NZQ7 --trim-low-confidence 70 --upload
|
|
10
16
|
|
|
11
|
-
Design (backbone generation):
|
|
12
|
-
phi design --target-pdb target.pdb --hotspots A45,A67 --num-designs 50
|
|
13
|
-
phi design --length 80 --num-designs 20
|
|
14
|
-
phi boltzgen --yaml design.yaml --protocol protein-anything --num-designs 10
|
|
15
|
-
|
|
16
17
|
Validation (fold + score):
|
|
17
18
|
phi esmfold --fasta sequences.fasta
|
|
18
19
|
phi alphafold --fasta complex.fasta
|
|
@@ -20,10 +21,10 @@ Validation (fold + score):
|
|
|
20
21
|
phi esm2 --fasta sequences.fasta
|
|
21
22
|
phi boltz --fasta complex.fasta
|
|
22
23
|
|
|
23
|
-
Batch filter pipeline
|
|
24
|
-
phi upload
|
|
25
|
-
phi filter --
|
|
26
|
-
phi download
|
|
24
|
+
Batch filter pipeline:
|
|
25
|
+
phi upload ./designs/
|
|
26
|
+
phi filter --preset default --wait
|
|
27
|
+
phi download --out ./results
|
|
27
28
|
|
|
28
29
|
Dataset management:
|
|
29
30
|
phi datasets # list your datasets
|
|
@@ -253,6 +254,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
253
254
|
)
|
|
254
255
|
sub = root.add_subparsers(dest="command", required=True)
|
|
255
256
|
|
|
257
|
+
p = sub.add_parser(
|
|
258
|
+
"tutorial",
|
|
259
|
+
help="Download example structures and print a step-by-step scoring walkthrough",
|
|
260
|
+
)
|
|
261
|
+
p.add_argument(
|
|
262
|
+
"--out",
|
|
263
|
+
metavar="DIR",
|
|
264
|
+
default="examples",
|
|
265
|
+
help="Directory to download example files into (default: ./examples)",
|
|
266
|
+
)
|
|
267
|
+
|
|
256
268
|
p = sub.add_parser("login", help="Verify API key and print connection + identity details")
|
|
257
269
|
p.add_argument("--json", action="store_true")
|
|
258
270
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|