|
3 | 3 | import json |
4 | 4 | import logging |
5 | 5 | import os |
| 6 | +import platform |
6 | 7 | import re |
7 | 8 | import subprocess |
8 | 9 | import sys |
9 | 10 | import urllib.request |
| 11 | +import venv |
10 | 12 | from collections.abc import Sequence |
11 | 13 | from itertools import chain, combinations |
12 | 14 | from typing import AnyStr, Optional, Any |
@@ -235,3 +237,37 @@ def powerset(iterable): |
235 | 237 | "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" |
236 | 238 | s = list(iterable) |
237 | 239 | return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) |
| 240 | + |
| 241 | + |
| 242 | +def ensure_venv(): |
| 243 | + VENV_DIR = local_path(".venv") |
| 244 | + PYTHON_BIN = os.path.abspath(os.path.join(VENV_DIR, "bin", "python3")) |
| 245 | + if platform.system() == 'Windows': |
| 246 | + PYTHON_BIN = os.path.abspath(os.path.join(VENV_DIR, "Scripts", "python.exe")) |
| 247 | + REQUIREMENTS = local_path("requirements.txt") |
| 248 | + |
| 249 | + # If venv doesn’t exist, create it |
| 250 | + if not os.path.exists(PYTHON_BIN): |
| 251 | + print("Creating virtual environment...") |
| 252 | + venv.create(VENV_DIR, with_pip=True) |
| 253 | + requirements_not_met = False |
| 254 | + if '--no-pip' not in sys.argv: |
| 255 | + # Running pip twice lets us both capture output cleanly to see if |
| 256 | + # we need to reload the venv and send output live to the user on |
| 257 | + # actual install. |
| 258 | + print("Checking for required python dependencies") |
| 259 | + req_check = subprocess.run([PYTHON_BIN, "-m", "pip", "install", "-r", REQUIREMENTS, "--dry-run"], capture_output=True, text=True) |
| 260 | + if req_check.returncode != 0: |
| 261 | + raise ImportError(f"pip failed to verify required dependencies:\n{req_check.stderr}") |
| 262 | + requirements_not_met = "collecting " in req_check.stdout.lower() |
| 263 | + if requirements_not_met: |
| 264 | + print("Installing missing python dependencies") |
| 265 | + req_check = subprocess.run([PYTHON_BIN, "-m", "pip", "install", "-r", REQUIREMENTS], capture_output=True, text=True) |
| 266 | + if req_check.returncode != 0: |
| 267 | + raise ImportError(f"pip failed to install required dependencies:\n{req_check.stderr}") |
| 268 | + |
| 269 | + # If we're not already running inside the venv, restart with it |
| 270 | + if sys.executable != PYTHON_BIN or requirements_not_met: |
| 271 | + print('Re-launching in virtual environment') |
| 272 | + subprocess.check_call([PYTHON_BIN] + sys.argv + ['--no-pip']) |
| 273 | + sys.exit(0) |
0 commit comments