Download run_script_venv.py from Agents-MCP-Hackathon/run_my_script: direct link, hf CLI and curl.
- Browser
- Download file 6.66 kB
-
https://huggingface.co/spaces/Agents-MCP-Hackathon/run_my_script/resolve/main/run_script_venv.py
- Command line
-
hf download hf://spaces/Agents-MCP-Hackathon/run_my_script/run_script_venv.py
-
curl -L -o run_script_venv.py https://huggingface.co/spaces/Agents-MCP-Hackathon/run_my_script/resolve/main/run_script_venv.py
6.66 kB
| #!/usr/bin/env python3 | |
| """ | |
| run_script_venv.py | |
| ================== | |
| A utility that | |
| 1. Accepts a path to a Python script. | |
| 2. Creates an isolated working directory. | |
| 3. Creates a virtual environment inside that directory using **uv**. | |
| 4. Statically analyses the target script to discover third‑party dependencies. | |
| 5. Installs the detected dependencies into the environment. | |
| 6. Executes the target script inside the environment. | |
| Usage | |
| ----- | |
| $ python run_script_venv.py path/to/script.py [--workdir ./my_dir] [--keep-workdir] | |
| Requirements | |
| ------------ | |
| * Python ≥ 3.10 (for ``sys.stdlib_module_names``) | |
| * ``uv`` must be available on the host Python used to run this helper. | |
| Notes | |
| ----- | |
| * The dependency detection is based on import statements only. Runtime/optional | |
| dependencies that are conditionally imported or loaded by plugins are not | |
| detected; you can pass extra packages manually via ``--extra``. | |
| * A small mapping translates common import‑name↔package‑name mismatches | |
| (e.g. ``cv2`` → ``opencv‑python``). | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import ast | |
| import os | |
| import shutil | |
| import subprocess | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| from typing import Iterable, Set | |
| # --------------------------- Helpers ----------------------------------------- | |
| # Map import names to PyPI package names where they differ. | |
| NAME_MAP: dict[str, str] = { | |
| "cv2": "opencv-python", | |
| "sklearn": "scikit-learn", | |
| "PIL": "pillow", | |
| "yaml": "pyyaml", | |
| "Crypto": "pycryptodome", | |
| } | |
| def find_imports(script_path: Path) -> Set[str]: | |
| """Return a set of *import names* found in *script_path*.""" | |
| root = ast.parse(script_path.read_text()) | |
| imports: set[str] = set() | |
| for node in ast.walk(root): | |
| if isinstance(node, ast.Import): | |
| for alias in node.names: | |
| imports.add(alias.name.split(".")[0]) | |
| elif isinstance(node, ast.ImportFrom): | |
| if node.level == 0 and node.module: # skip relative imports | |
| imports.add(node.module.split(".")[0]) | |
| return imports | |
| def third_party_modules(modules: Iterable[str]) -> Set[str]: | |
| """Filter *modules* to those not in the Python stdlib.""" | |
| stdlib = set(sys.stdlib_module_names) # Python ≥ 3.10 | |
| return {m for m in modules if m not in stdlib} | |
| def translate_names(modules: Iterable[str]) -> Set[str]: | |
| """Translate *modules* to their PyPI names using NAME_MAP.""" | |
| pkgs: set[str] = set() | |
| for m in modules: | |
| pkgs.add(NAME_MAP.get(m, m)) | |
| return pkgs | |
| def create_venv(venv_dir: Path) -> Path: | |
| """Create a venv at *venv_dir* using ``uv venv`` and return the Python exe.""" | |
| subprocess.check_call(["uv", "venv", str(venv_dir)]) | |
| python_exe = venv_dir / ("Scripts" if os.name == "nt" else "bin") / "python" | |
| return python_exe | |
| def install_packages(python_exe: Path, packages: Iterable[str]) -> None: | |
| if not packages: | |
| print("[+] No third‑party packages detected; skipping installation.") | |
| return | |
| print(f"[+] Installing: {' '.join(packages)}") | |
| # subprocess.check_call([str(python_exe), "-m", "pip", "install", *packages]) | |
| subprocess.check_call(["uv", "pip", "install", "-p", str(python_exe), *packages]) | |
| # --------------------------- Main routine ------------------------------------ | |
| def main() -> None: | |
| p = argparse.ArgumentParser(prog="run_script_venv") | |
| p.add_argument("script", type=Path, help="Python script to execute") | |
| p.add_argument( | |
| "--workdir", | |
| type=Path, | |
| help="Directory to create the environment in (defaults to a temp dir)", | |
| ) | |
| p.add_argument( | |
| "--extra", | |
| nargs="*", | |
| default=[], | |
| metavar="PKG", | |
| help="Extra PyPI packages to install in addition to auto‑detected ones", | |
| ) | |
| p.add_argument( | |
| "--keep-workdir", | |
| action="store_true", | |
| help="Do not delete the temporary working directory on success", | |
| ) | |
| args = p.parse_args() | |
| script_path: Path = args.script.resolve() | |
| if not script_path.is_file(): | |
| p.error(f"Script '{script_path}' not found.") | |
| # --------------------------------------------------------------------- | |
| # Prepare working directory and venv | |
| # --------------------------------------------------------------------- | |
| workdir: Path | |
| temp_created = False | |
| if args.workdir: | |
| workdir = args.workdir.resolve() | |
| workdir.mkdir(parents=True, exist_ok=True) | |
| else: | |
| workdir = Path(tempfile.mkdtemp(prefix=f"{script_path.stem}_work_")) | |
| temp_created = True | |
| venv_dir = workdir / ".venv" | |
| print(f"[+] Working directory: {workdir}") | |
| # --------------------------------------------------------------------- | |
| # Detect and install dependencies | |
| # --------------------------------------------------------------------- | |
| mods = find_imports(script_path) | |
| third_party = translate_names(third_party_modules(mods)) | set(args.extra) | |
| print(f"[+] Third‑party imports: {sorted(third_party) if third_party else 'None'}") | |
| py = create_venv(venv_dir) | |
| install_packages(py, third_party) | |
| # --------------------------------------------------------------------- | |
| # Run the target script inside the environment | |
| # --------------------------------------------------------------------- | |
| env = os.environ.copy() | |
| env["VIRTUAL_ENV"] = str(venv_dir) | |
| env["PATH"] = str(py.parent) + os.pathsep + env["PATH"] | |
| print("[+] Running script …\n----------------------------------------") | |
| proc = subprocess.Popen( | |
| [str(py), str(script_path)], | |
| env=env, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True, | |
| bufsize=1, | |
| ) | |
| # Stream the script output line by line | |
| assert proc.stdout is not None | |
| for line in proc.stdout: | |
| print(line, end="") | |
| retcode = proc.wait() | |
| print("----------------------------------------") | |
| if retcode == 0: | |
| print("[+] Script finished successfully.") | |
| else: | |
| print(f"[!] Script exited with return code {retcode}.") | |
| sys.exit(retcode) | |
| # --------------------------------------------------------------------- | |
| # Cleanup | |
| # --------------------------------------------------------------------- | |
| if temp_created and not args.keep_workdir: | |
| shutil.rmtree(workdir) | |
| print(f"[+] Removed temporary directory {workdir}") | |
| if __name__ == "__main__": | |
| try: | |
| main() | |
| except subprocess.CalledProcessError as e: | |
| print("[!] A subprocess exited with a non‑zero status:", e, file=sys.stderr) | |
| sys.exit(e.returncode) | |