-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathvenv_manager.py
More file actions
105 lines (90 loc) · 4.31 KB
/
venv_manager.py
File metadata and controls
105 lines (90 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# venv_manager.py
import os
import subprocess
import sys
import platform
CLIPPY_DIR = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
def _get_venv_python_executable(venv_path: str) -> str:
"""
Determines the conventional path to the Python executable within a virtual environment.
"""
if platform.system() == "Windows":
return os.path.join(venv_path, "Scripts", "python.exe")
else:
# In a venv, 'bin/python' is typically the interpreter for that venv.
# The original script used 'bin/python3'. We will try 'bin/python3' first
# and fall back to 'bin/python' as it's more standard for venvs.
py3_exe = os.path.join(venv_path, "bin", "python3")
if os.path.exists(py3_exe):
return py3_exe
return os.path.join(venv_path, "bin", "python")
def ensure_venv(project_dir) -> str:
"""
Ensures a virtual environment exists in the specified project_dir.
If the venv directory ('venv') doesn't exist, it creates it using the
currently running Python interpreter and installs dependencies from
'requirements.txt' located in project_dir.
Args:
project_dir (str): The absolute path to the project directory where the 'venv'
folder and 'requirements.txt' are expected to be.
Returns:
str: The absolute path to the Python executable within the virtual environment.
Raises:
FileNotFoundError: If the Python executable in the venv is not found after setup.
subprocess.CalledProcessError: If any command (venv creation, pip install) fails.
Exception: For other unexpected errors during setup.
"""
if not os.path.isabs(project_dir):
project_dir = os.path.abspath(project_dir)
venv_path = os.path.join(project_dir, "venv")
requirements_path = os.path.join(project_dir, "requirements.txt")
current_python_executable = sys.executable # Python used to run this script
created_venv_now = False
if not os.path.isdir(venv_path):
print(f"Virtual environment not found at '{venv_path}'.")
print(f"Creating virtual environment using '{current_python_executable}'...")
try:
subprocess.run(
[current_python_executable, "-m", "venv", venv_path],
check=True,
stdout=sys.stdout, # stream output
stderr=sys.stderr
)
print(f"Virtual environment created at '{venv_path}'")
created_venv_now = True
except subprocess.CalledProcessError as e:
print(f"Error creating virtual environment: {e}", file=sys.stderr)
raise
except FileNotFoundError:
print(f"Error: The Python executable '{current_python_executable}' was not found.", file=sys.stderr)
raise
venv_python_exe = _get_venv_python_executable(venv_path)
if not os.path.isfile(venv_python_exe):
raise FileNotFoundError(
f"Python executable not found in virtual environment at '{venv_path}'. "
f"Expected at '{venv_python_exe}'. "
"The venv might be corrupted or was not created successfully."
)
if created_venv_now:
if os.path.exists(requirements_path):
print(f"Installing dependencies from '{requirements_path}' into virtual environment...")
try:
subprocess.run(
[venv_python_exe, "-m", "pip", "install", "-r", requirements_path],
check=True,
stdout=sys.stdout, # stream output
stderr=sys.stderr
)
print("Dependencies installed successfully.")
except subprocess.CalledProcessError as e:
print(f"Error installing dependencies: {e}", file=sys.stderr)
raise
except FileNotFoundError:
# Should be caught by the check above, but as a safeguard:
print(f"Error: The venv Python executable '{venv_python_exe}' was not found during pip install.", file=sys.stderr)
raise
else:
print(f"'{requirements_path}' not found. Skipping dependency installation.")
#else:
# print(f"Virtual environment already exists at '{venv_path}'. Skipping creation and dependency installation.")
return venv_python_exe