pyscalpel.venv
This module provides reimplementations of Python virtual environnements scripts
This is designed to be used internally, but in the case where the user desires to dynamically switch venvs using this, they should ensure the selected venv has the dependencies required by Scalpel.
1""" 2This module provides reimplementations of Python virtual environnements scripts 3 4This is designed to be used internally, 5but in the case where the user desires to dynamically switch venvs using this, 6they should ensure the selected venv has the dependencies required by Scalpel. 7""" 8 9import os 10import sys 11import glob 12import subprocess 13 14_old_prefix = sys.prefix 15_old_exec_prefix = sys.exec_prefix 16 17# Python's virtualenv's activate/deactivate ported from the bash script to Python code. 18# https://docs.python.org/3/library/venv.html#:~:text=each%20provided%20path.-,How%20venvs%20work%C2%B6,-When%20a%20Python 19 20# pragma: no cover 21 22 23def deactivate() -> None: # pragma: no cover 24 """Deactivates the current virtual environment.""" 25 if "_OLD_VIRTUAL_PATH" in os.environ: 26 os.environ["PATH"] = os.environ["_OLD_VIRTUAL_PATH"] 27 del os.environ["_OLD_VIRTUAL_PATH"] 28 if "_OLD_VIRTUAL_PYTHONHOME" in os.environ: 29 os.environ["PYTHONHOME"] = os.environ["_OLD_VIRTUAL_PYTHONHOME"] 30 del os.environ["_OLD_VIRTUAL_PYTHONHOME"] 31 if "VIRTUAL_ENV" in os.environ: 32 del os.environ["VIRTUAL_ENV"] 33 34 sys.prefix = _old_prefix 35 sys.exec_prefix = _old_exec_prefix 36 37 38def activate(path: str | None) -> None: # pragma: no cover 39 """Activates the virtual environment at the given path.""" 40 deactivate() 41 42 if path is None: 43 return 44 45 virtual_env = os.path.abspath(path) 46 os.environ["_OLD_VIRTUAL_PATH"] = os.environ.get("PATH", "") 47 os.environ["VIRTUAL_ENV"] = virtual_env 48 49 old_pythonhome = os.environ.pop("PYTHONHOME", None) 50 if old_pythonhome: 51 os.environ["_OLD_VIRTUAL_PYTHONHOME"] = old_pythonhome 52 53 if os.name == "nt": 54 site_packages_paths = os.path.join(virtual_env, "Lib", "site-packages") 55 else: 56 site_packages_paths = glob.glob( 57 os.path.join(virtual_env, "lib", "python*", "site-packages") 58 ) 59 60 if not site_packages_paths: 61 raise RuntimeError( 62 f"No 'site-packages' directory found in virtual environment at {virtual_env}" 63 ) 64 65 site_packages = site_packages_paths[0] 66 sys.path.insert(0, site_packages) 67 sys.prefix = virtual_env 68 sys.exec_prefix = virtual_env 69 70 71def install(*packages: str) -> int: # pragma: no cover 72 """Install a Python package in the current venv. 73 74 Returns: 75 int: The pip install command exit code. 76 """ 77 pip = os.path.join(sys.prefix, "bin", "pip") 78 return subprocess.call([pip, "install", "--require-virtualenv", "--", *packages]) 79 80 81def uninstall(*packages: str) -> int: # pragma: no cover 82 """Uninstall a Python package from the current venv. 83 84 Returns: 85 int: The pip uninstall command exit code. 86 """ 87 pip = os.path.join(sys.prefix, "bin", "pip") 88 return subprocess.call( 89 [pip, "uninstall", "--require-virtualenv", "-y", "--", *packages] 90 ) 91 92 93def create(path: str) -> int: # pragma: no cover 94 """Creates a Python venv on the given path 95 96 Returns: 97 int: The `python3 -m venv` command exit code. 98 """ 99 return subprocess.call(["python3", "-m", "venv", "--", path]) 100 101 102def create_default() -> str: # pragma: no cover 103 """Creates a default venv in the user's home directory 104 Only creates it if the directory doesn't already exist 105 106 Returns: 107 str: The venv directory path. 108 """ 109 scalpel_venv = os.path.join(os.path.expanduser("~"), ".scalpel", "venv_default") 110 # Don't recreate the venv if it alreay exists 111 if not os.path.exists(scalpel_venv): 112 os.makedirs(scalpel_venv, exist_ok=True) 113 create(scalpel_venv) 114 return scalpel_venv
24def deactivate() -> None: # pragma: no cover 25 """Deactivates the current virtual environment.""" 26 if "_OLD_VIRTUAL_PATH" in os.environ: 27 os.environ["PATH"] = os.environ["_OLD_VIRTUAL_PATH"] 28 del os.environ["_OLD_VIRTUAL_PATH"] 29 if "_OLD_VIRTUAL_PYTHONHOME" in os.environ: 30 os.environ["PYTHONHOME"] = os.environ["_OLD_VIRTUAL_PYTHONHOME"] 31 del os.environ["_OLD_VIRTUAL_PYTHONHOME"] 32 if "VIRTUAL_ENV" in os.environ: 33 del os.environ["VIRTUAL_ENV"] 34 35 sys.prefix = _old_prefix 36 sys.exec_prefix = _old_exec_prefix
Deactivates the current virtual environment.
39def activate(path: str | None) -> None: # pragma: no cover 40 """Activates the virtual environment at the given path.""" 41 deactivate() 42 43 if path is None: 44 return 45 46 virtual_env = os.path.abspath(path) 47 os.environ["_OLD_VIRTUAL_PATH"] = os.environ.get("PATH", "") 48 os.environ["VIRTUAL_ENV"] = virtual_env 49 50 old_pythonhome = os.environ.pop("PYTHONHOME", None) 51 if old_pythonhome: 52 os.environ["_OLD_VIRTUAL_PYTHONHOME"] = old_pythonhome 53 54 if os.name == "nt": 55 site_packages_paths = os.path.join(virtual_env, "Lib", "site-packages") 56 else: 57 site_packages_paths = glob.glob( 58 os.path.join(virtual_env, "lib", "python*", "site-packages") 59 ) 60 61 if not site_packages_paths: 62 raise RuntimeError( 63 f"No 'site-packages' directory found in virtual environment at {virtual_env}" 64 ) 65 66 site_packages = site_packages_paths[0] 67 sys.path.insert(0, site_packages) 68 sys.prefix = virtual_env 69 sys.exec_prefix = virtual_env
Activates the virtual environment at the given path.
72def install(*packages: str) -> int: # pragma: no cover 73 """Install a Python package in the current venv. 74 75 Returns: 76 int: The pip install command exit code. 77 """ 78 pip = os.path.join(sys.prefix, "bin", "pip") 79 return subprocess.call([pip, "install", "--require-virtualenv", "--", *packages])
Install a Python package in the current venv.
Returns: int: The pip install command exit code.
82def uninstall(*packages: str) -> int: # pragma: no cover 83 """Uninstall a Python package from the current venv. 84 85 Returns: 86 int: The pip uninstall command exit code. 87 """ 88 pip = os.path.join(sys.prefix, "bin", "pip") 89 return subprocess.call( 90 [pip, "uninstall", "--require-virtualenv", "-y", "--", *packages] 91 )
Uninstall a Python package from the current venv.
Returns: int: The pip uninstall command exit code.
94def create(path: str) -> int: # pragma: no cover 95 """Creates a Python venv on the given path 96 97 Returns: 98 int: The `python3 -m venv` command exit code. 99 """ 100 return subprocess.call(["python3", "-m", "venv", "--", path])
Creates a Python venv on the given path
Returns:
int: The python3 -m venv
command exit code.
103def create_default() -> str: # pragma: no cover 104 """Creates a default venv in the user's home directory 105 Only creates it if the directory doesn't already exist 106 107 Returns: 108 str: The venv directory path. 109 """ 110 scalpel_venv = os.path.join(os.path.expanduser("~"), ".scalpel", "venv_default") 111 # Don't recreate the venv if it alreay exists 112 if not os.path.exists(scalpel_venv): 113 os.makedirs(scalpel_venv, exist_ok=True) 114 create(scalpel_venv) 115 return scalpel_venv
Creates a default venv in the user's home directory Only creates it if the directory doesn't already exist
Returns: str: The venv directory path.