#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Install project Python deps into embedded python/py (site-packages). No virtual environment.""" import os import subprocess import sys from pathlib import Path PIP_INDEX_URL = os.environ.get("PIP_INDEX_URL", "https://pypi.tuna.tsinghua.edu.cn/simple") PIP_TRUSTED_HOST = "pypi.tuna.tsinghua.edu.cn" PIP_INDEX_ARGS = f"-i {PIP_INDEX_URL} --trusted-host {PIP_TRUSTED_HOST}" SCRIPT_DIR = Path(__file__).parent.absolute() PROJECT_ROOT = SCRIPT_DIR.parent.absolute() PY_EMBED = SCRIPT_DIR / "py" / "python.exe" if not PY_EMBED.exists(): PY_EMBED = SCRIPT_DIR / "py" / "python" ENVIRONMENT_FILE = SCRIPT_DIR / "environment.txt" REQUIREMENTS_FILE = PROJECT_ROOT / "requirements.txt" def run_pip(args: str) -> subprocess.CompletedProcess: cmd = f'"{PY_EMBED}" -m pip {args}' return subprocess.run(cmd, shell=True, capture_output=True, text=True, encoding="utf-8") def installed_names() -> set: out = set() sp = SCRIPT_DIR / "py" / "Lib" / "site-packages" if not sp.exists(): return out for item in sp.iterdir(): if not item.is_dir(): continue name = item.name if name.endswith(".dist-info"): base = name.replace(".dist-info", "").rsplit("-", 1)[0] out.add(base.lower().replace("_", "-")) elif name.endswith(".egg-info"): base = name.replace(".egg-info", "").rsplit("-", 1)[0] out.add(base.lower().replace("_", "-")) elif (item / "__init__.py").exists() or any(item.glob("*.py")): out.add(name.lower()) out.add(name.lower().replace("_", "-")) if "cv2" in out: out.add("opencv-python") return out def pkg_key(line: str) -> str: line = line.strip() if not line or line.startswith("#"): return "" for sep in ("==", ">=", "<=", "~=", ">", "<"): if sep in line: line = line.split(sep)[0] break return line.strip().lower() def main() -> None: if not PY_EMBED.exists(): print(f"[X] Embedded Python not found: {PY_EMBED}") sys.exit(1) if run_pip("--version").returncode != 0: print("[X] pip not usable. Run enviroment-check.ps1 (copies from python/backup/site-packages first, then get-pip.py if needed).") sys.exit(1) if REQUIREMENTS_FILE.exists(): source = REQUIREMENTS_FILE elif ENVIRONMENT_FILE.exists(): source = ENVIRONMENT_FILE else: fr = run_pip("freeze") if fr.returncode == 0 and fr.stdout: ENVIRONMENT_FILE.write_text(fr.stdout, encoding="utf-8", newline="\n") print("[OK] Created environment.txt from pip freeze") sys.exit(0) lines = [ln.strip() for ln in source.read_text(encoding="utf-8").splitlines() if ln.strip() and not ln.strip().startswith("#")] if not lines: print("[OK] No packages listed") sys.exit(0) have = installed_names() missing = [] for ln in lines: k = pkg_key(ln) if not k: continue if k in have or k.replace("-", "_") in have: continue missing.append(ln) if missing: print(f"Installing {len(missing)} package(s) into python/py...") for pkg in missing: print(f" pip install {pkg}") ins = run_pip(f"install {PIP_INDEX_ARGS} --no-warn-script-location {pkg}") if ins.returncode != 0: print(ins.stderr or ins.stdout or "") sys.exit(1) fr = run_pip("freeze") if fr.returncode != 0: sys.exit(1) ENVIRONMENT_FILE.write_text(fr.stdout, encoding="utf-8", newline="\n") print(f"[OK] Synced {ENVIRONMENT_FILE}") sys.exit(0) if __name__ == "__main__": main()