#!/usr/bin/env python3 import argparse import subprocess import os import shutil import sys import ctypes.util from pathlib import Path _DIR = Path(__file__).parent _PROGRAM_DIR = _DIR.parent _VENV_DIR = _PROGRAM_DIR / ".venv" parser = argparse.ArgumentParser() parser.add_argument("--dev", action="store_true", help="Install dev requirements") parser.add_argument("--cxxflags", type=str, help="CXXFLAGS for compilation (default: -O1 -g0)") parser.add_argument("--makeflags", type=str, help="MAKEFLAGS for compilation (default: -j1)") args = parser.parse_args() # Find Python 3.11+ interpreter def find_python_311(): for candidate in ["python3.13", "python3.12", "python3.11"]: path = shutil.which(candidate) if path: result = subprocess.run([path, "--version"], capture_output=True, text=True) version_str = result.stdout.strip() or result.stderr.strip() ver_parts = version_str.replace("Python ", "").split(".") if len(ver_parts) >= 2 and int(ver_parts[0]) == 3 and int(ver_parts[1]) >= 11: return path return None python_311_exe = find_python_311() if not python_311_exe: print("ERROR: Python 3.11+ is required but not found on this system.") print(" Ubuntu/Debian: sudo apt install python3.11 python3.11-venv python3.11-dev") print(" macOS: brew install python@3.11") sys.exit(1) print(f"Using Python: {python_311_exe}") subprocess.run([python_311_exe, "--version"]) # Check system dependencies (warning only, CI installs them separately) missing = [] try: if not ctypes.util.find_library("mpv"): missing.append("libmpv-dev") if not ctypes.util.find_library("asound"): missing.append("libasound2-dev") except Exception: pass # Ignore errors in environments without ctypes if missing: print(f"\nWARNING: Missing system libraries (required for audio): {', '.join(missing)}") print("For Docker/local dev: sudo apt install libmpv-dev pulseaudio pipewire alsa-utils") # Create virtual environment if _VENV_DIR.exists(): shutil.rmtree(_VENV_DIR) subprocess.check_call([python_311_exe, "-m", "venv", str(_VENV_DIR), "--symlinks"]) # Set environment variables env = {} if args.cxxflags: env["CXXFLAGS"] = args.cxxflags if args.makeflags: env["MAKEFLAGS"] = args.makeflags # Upgrade dependencies pip = [str(_VENV_DIR / "bin" / "python"), "-m", "pip"] subprocess.check_call(pip + ["install", "--upgrade", "pip"]) subprocess.check_call(pip + ["install", "--upgrade", "setuptools", "wheel"]) # Install requirements subprocess.check_call(pip + ["install", "-e", str(_PROGRAM_DIR)]) # Install dev requirements if args.dev: subprocess.check_call( pip + ["install", "-e", f"{_PROGRAM_DIR}[dev]"], env={**dict(os.environ), **env} )