/usr/lib/rads/venv/lib/python3.13/site-packages/pip/_internal/build_env
Edit: /usr/lib/rads/venv/lib/python3.13/site-packages/pip/_internal/build_env/venv.py (5692B)
from __future__ import annotations
import os
import sys
import sysconfig
from collections.abc import Iterable
from types import TracebackType
from typing import TYPE_CHECKING
from pip._internal.build_env.base import (
BuildEnvironment,
BuildEnvironmentInstaller,
Prefix,
)
from pip._internal.exceptions import VenvCreationError, VenvImportError
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
if TYPE_CHECKING:
from pip._internal.req.req_install import InstallRequirement
def _get_venv_path_from_sysconfig(name: str, env_dir: str) -> str:
vars = {
"base": env_dir,
"platbase": env_dir,
}
return sysconfig.get_path(name, scheme="venv", vars=vars)
class VenvBuildEnvironment(BuildEnvironment):
"""A venv-based build environment."""
def __init__(self, installer: BuildEnvironmentInstaller) -> None:
# We defer this import because certain distributions of Python do not include
# a functional venv out of the box.
try:
import venv
except ImportError:
raise VenvImportError
self._env_path = TempDirectory(
kind=tempdir_kinds.BUILD_ENV, globally_managed=True
).path
# Use symlinks to support relocatable Python installations on POSIX, including
# python-build-standalone. This matches upstream venv CLI's behaviour.
env = venv.EnvBuilder(symlinks=(os.name != "nt"))
try:
context = env.ensure_directories(self._env_path)
env.create(self._env_path)
except OSError as e:
raise VenvCreationError(str(e))
if sys.version_info >= (3, 12):
# The context object was only documented in Python 3.12
self.lib_dirs = [context.lib_path]
self._bin_path = context.bin_path
elif sys.version_info[:2] == (3, 11):
# On Python 3.11, we can use sysconfig.
self.lib_dirs = [_get_venv_path_from_sysconfig("purelib", self._env_path)]
self._bin_path = _get_venv_path_from_sysconfig("scripts", self._env_path)
else:
# Otherwise, we need to manually construct all the paths... sigh.
if sys.platform == "win32":
libpath = os.path.join(self._env_path, "Lib", "site-packages")
else:
python = "pypy" if sys.implementation.name == "pypy" else "python"
libpath = os.path.join(
self._env_path,
"lib",
f"{python}{sys.version_info.major}.{sys.version_info.minor}",
"site-packages",
)
self.lib_dirs = [libpath]
# Same reasoning for try-except as for python_executable below.
try:
self._bin_path = context.bin_path
except AttributeError:
scripts_dir = "Scripts" if os.name == "nt" else "bin"
self._bin_path = os.path.join(self._env_path, scripts_dir)
# There are enough ways trying to construct the Python executable path can go
# wrong that we're better off assuming that the context object has the right
# attributes, and only when they don't exist do we try to guess.
#
# These attributes seem to exist in every CPython version after 3.10.1 and
# are documented to exist on 3.12 and higher.
try:
self.python_executable = context.env_exec_cmd
except AttributeError:
try:
self.python_executable = context.env_exe
except AttributeError:
executable_name = "python.exe" if os.name == "nt" else "python"
self.python_executable = os.path.join(self._bin_path, executable_name)
self._save_env: dict[str, str | None] = {}
self._installer = installer
if not os.path.exists(self.python_executable):
# This error is only likely on Windows due to interference from AV software.
raise VenvCreationError(
f"Python executable failed to copy to {self.python_executable}"
)
def __enter__(self) -> None:
# We want backend calls to be able to use binaries installed as if this
# virtual environment was "activated".
self._save_env = {
name: os.environ.get(name, None) for name in ("PATH", "PYTHONPATH")
}
new_path = [self._bin_path]
if old_path := self._save_env["PATH"]:
new_path.extend(old_path.split(os.pathsep))
# However, we don't want a pre-existing PYTHONPATH to influence the
# backend calls.
os.environ.update({"PATH": os.pathsep.join(new_path), "PYTHONPATH": ""})
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
for varname, old_value in self._save_env.items():
if old_value is None:
os.environ.pop(varname, None)
else:
os.environ[varname] = old_value
def install_requirements(
self,
requirements: Iterable[str],
prefix_as_string: str,
*,
kind: str,
for_req: InstallRequirement | None = None,
) -> None:
if not requirements:
return
# TODO: when better support for installing to arbitrary Python environments
# is added, replace this prefix hack with that.
prefix = Prefix(self._env_path, venv_executable=self.python_executable)
self._installer.install(requirements, prefix, kind=kind, for_req=for_req)