""" Centralized path resolution for bioai. All runtime paths are derived from the project root, which is the directory containing the ``bioai/`` package. This makes the codebase portable across machines (no hardcoded ``/home/z/my-project`` paths). Resolution order: 1. Walk up from this file (``bioai/paths.py``) until we find a directory that contains a ``bioai`` subdirectory. That's the project root. 2. If that fails (e.g., we're inside a frozen binary), fall back to the current working directory. Override the project root by setting the ``BIOAI_PROJECT_ROOT`` env var (useful for Docker, where WORKDIR=/app is the project root). """ from __future__ import annotations import os from pathlib import Path def _find_project_root() -> Path: # Allow explicit override env = os.environ.get("BIOAI_PROJECT_ROOT") if env: p = Path(env).expanduser().resolve() if p.is_dir(): return p # Walk up from this file until we find a directory containing bioai/ here = Path(__file__).resolve().parent # .../bioai/ for candidate in [here, *here.parents]: if (candidate / "bioai").is_dir(): return candidate # Last resort: current working directory return Path.cwd() PROJECT_ROOT: Path = _find_project_root() # Standard subdirectories DATA_DIR: Path = PROJECT_ROOT / "data" SYNTHETIC_DIR: Path = DATA_DIR / "synthetic" EXTERNAL_DIR: Path = DATA_DIR / "external" PROCESSED_DIR: Path = DATA_DIR / "processed" CHECKPOINTS_DIR: Path = PROJECT_ROOT / "checkpoints" CACHE_DIR: Path = PROJECT_ROOT / ".fireworks_cache" # Standard file paths DEFAULT_PEST_FASTA: Path = SYNTHETIC_DIR / "pest_transcripts.fasta" DEFAULT_SAFETY_FASTA: Path = SYNTHETIC_DIR / "safety_transcripts.fasta" DEFAULT_TRAINING_CSV: Path = PROCESSED_DIR / "training_data.csv" SIRNA_CHECKPOINT: Path = CHECKPOINTS_DIR / "sirna_best.pt" VAE_CHECKPOINT: Path = CHECKPOINTS_DIR / "vae_best.pt" PINN_CHECKPOINT: Path = CHECKPOINTS_DIR / "pinn_best.pt" def ensure_dirs() -> None: """Create the standard subdirectories if they don't exist. Called at module import so any subsequent path is safe to write to. """ for d in (DATA_DIR, SYNTHETIC_DIR, EXTERNAL_DIR, PROCESSED_DIR, CHECKPOINTS_DIR, CACHE_DIR): d.mkdir(parents=True, exist_ok=True) # Run once on import ensure_dirs()