File size: 2,639 Bytes
4c02fbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"""`casmd-ui` — launch the Streamlit web app."""
from __future__ import annotations
import argparse
import os
import subprocess
import sys
from pathlib import Path


def _ensure_streamlit_credentials() -> None:
    """Write a blank credentials file so Streamlit skips the email prompt."""
    creds = Path.home() / ".streamlit" / "credentials.toml"
    if not creds.exists():
        creds.parent.mkdir(parents=True, exist_ok=True)
        creds.write_text('[general]\nemail = ""\n')


def main(argv: list[str] | None = None) -> int:
    p = argparse.ArgumentParser(prog="casmd-ui", description="Launch the CasMD Streamlit app.")
    p.add_argument("--port", type=int, default=8501)
    p.add_argument("--host", default="127.0.0.1")
    args = p.parse_args(argv)

    here = Path(__file__).resolve()
    repo_root = here.parent.parent.parent  # src/casmd/cli.py → repo root
    app_entry = repo_root / "app" / "streamlit_app.py"
    if not app_entry.exists():
        print(f"error: app/streamlit_app.py not found at {app_entry}", file=sys.stderr)
        print("CasMD's UI requires running from a dev install (`pip install -e .`).", file=sys.stderr)
        return 2

    _ensure_streamlit_credentials()

    cmd = [
        sys.executable, "-m", "streamlit", "run", str(app_entry),
        "--server.port", str(args.port),
        "--server.address", args.host,
        "--browser.gatherUsageStats", "false",
    ]
    # Put the repo root on PYTHONPATH so `from app.shared import ...` works
    # when Streamlit runs `app/streamlit_app.py` (which doesn't put the repo
    # root on sys.path automatically).
    env = os.environ.copy()
    existing_pp = env.get("PYTHONPATH", "")
    env["PYTHONPATH"] = (
        f"{repo_root}{os.pathsep}{existing_pp}" if existing_pp else str(repo_root)
    )

    # Ensure the Python interpreter's bin/ directory is on PATH so the build
    # subprocesses (pdb4amber, tleap, gmx) are findable even when the user
    # invokes `casmd-ui` from a shell without conda activated. `sys.executable`
    # points at e.g. /opt/miniconda3/envs/foo/bin/python3.11 — its parent
    # holds the AmberTools + GROMACS binaries installed alongside it.
    python_bin_dir = str(Path(sys.executable).resolve().parent)
    existing_path = env.get("PATH", "")
    if python_bin_dir not in existing_path.split(os.pathsep):
        env["PATH"] = (
            f"{python_bin_dir}{os.pathsep}{existing_path}"
            if existing_path
            else python_bin_dir
        )
    print(f"Launching: {' '.join(cmd)}")
    return subprocess.call(cmd, env=env)


if __name__ == "__main__":
    raise SystemExit(main())