A modern Python package and dependency manager supporting the latest PEP standards
—
Python environment abstraction supporting virtual environments, system Python, and containerized environments with comprehensive package management capabilities. PDM's environment system provides a unified interface for different Python execution contexts.
Abstract base class defining the common interface for all environment types in PDM.
from abc import ABC, abstractmethod
from pathlib import Path
class BaseEnvironment(ABC):
"""
Abstract base class for Python environments.
Provides unified interface for environment operations including
path resolution, Python executable access, and package management.
"""
@property
@abstractmethod
def python_executable(self) -> Path:
"""Path to Python executable for this environment"""
@abstractmethod
def get_paths(self) -> dict[str, str]:
"""
Get environment paths following PEP 427.
Returns:
Dictionary with standard path keys:
- platlib: Platform-specific library directory
- purelib: Pure Python library directory
- headers: Header files directory
- scripts: Executable scripts directory
- data: Data files directory
"""
@abstractmethod
def get_python_executable(self) -> Path:
"""
Get Python executable path.
Returns:
Path to Python interpreter for this environment
"""
def is_global(self) -> bool:
"""
Check if this is a global/system environment.
Returns:
True if global system environment
"""
def get_working_set(self) -> list[Distribution]:
"""
Get currently installed packages in environment.
Returns:
List of installed package distributions
"""Minimal environment implementation without package management capabilities.
class BareEnvironment(BaseEnvironment):
"""
Minimal environment implementation for basic Python execution.
Provides Python executable access and path resolution without
package installation capabilities. Useful for read-only environments.
"""
def __init__(self, python_executable: Path | str):
"""
Initialize bare environment.
Args:
python_executable: Path to Python interpreter
"""
@property
def python_executable(self) -> Path:
"""Python executable path"""
def get_paths(self) -> dict[str, str]:
"""Get environment paths from sysconfig"""
def get_python_executable(self) -> Path:
"""Get Python executable path"""Full-featured Python environment with complete package management capabilities.
class PythonEnvironment(BaseEnvironment):
"""
Full Python environment with package management capabilities.
Supports package installation, uninstallation, and environment
manipulation using pip and other standard tools.
"""
def __init__(
self,
python_executable: Path | str,
prefix: Path | str | None = None
):
"""
Initialize Python environment.
Args:
python_executable: Path to Python interpreter
prefix: Optional environment prefix path
"""
def install(self, requirements: list[str]) -> None:
"""
Install packages in this environment.
Args:
requirements: List of requirement specifications to install
Raises:
InstallationError: Package installation failed
"""
def uninstall(self, packages: list[str]) -> None:
"""
Uninstall packages from this environment.
Args:
packages: List of package names to uninstall
Raises:
UninstallError: Package uninstallation failed
"""
def update_shebangs(self, packages: list[str]) -> None:
"""
Update script shebangs for specified packages.
Args:
packages: Package names to update shebangs for
"""
def get_python_version(self) -> tuple[int, int, int]:
"""
Get Python version tuple.
Returns:
Python version as (major, minor, micro) tuple
"""
def run_command(
self,
command: list[str],
cwd: Path | str | None = None,
env: dict[str, str] | None = None
) -> subprocess.CompletedProcess:
"""
Run command in this environment.
Args:
command: Command and arguments to execute
cwd: Working directory for command
env: Environment variables for command
Returns:
Completed process result
"""Specialized environment for local/system Python installations with enhanced integration.
class PythonLocalEnvironment(PythonEnvironment):
"""
Local Python environment for system installations.
Provides enhanced integration with system Python installations
and local development workflows.
"""
def __init__(self, python_executable: Path | str):
"""
Initialize local Python environment.
Args:
python_executable: Path to system Python interpreter
"""
def get_site_packages(self) -> list[Path]:
"""
Get site-packages directories.
Returns:
List of site-packages directory paths
"""
def is_venv(self) -> bool:
"""
Check if environment is a virtual environment.
Returns:
True if virtual environment
"""
def get_venv_root(self) -> Path | None:
"""
Get virtual environment root directory.
Returns:
Path to venv root, or None if not a venv
"""Utilities for environment detection, creation, and management.
def get_environment(python_executable: Path | str) -> BaseEnvironment:
"""
Get appropriate environment instance for Python executable.
Args:
python_executable: Path to Python interpreter
Returns:
Environment instance (PythonEnvironment or PythonLocalEnvironment)
"""
def find_python_executable(version_spec: str | None = None) -> Path:
"""
Find Python executable matching version specification.
Args:
version_spec: Python version specification (e.g., "3.9", ">=3.8")
Returns:
Path to matching Python executable
Raises:
NoPythonVersion: No matching Python found
"""
def create_venv(
location: Path | str,
python_executable: Path | str | None = None,
prompt: str | None = None
) -> PythonEnvironment:
"""
Create new virtual environment.
Args:
location: Directory for new virtual environment
python_executable: Python executable to use as base
prompt: Custom prompt for virtual environment
Returns:
New PythonEnvironment instance for created venv
"""Classes for gathering and representing Python environment information.
@dataclass
class PythonInfo:
"""
Python interpreter information and capabilities.
Contains comprehensive information about a Python installation
including version, paths, and feature support.
"""
executable: Path
version: tuple[int, int, int]
implementation: str
architecture: str
abi_tag: str
@property
def version_string(self) -> str:
"""Formatted version string (e.g., '3.9.7')"""
@property
def interpreter_tag(self) -> str:
"""PEP 425 interpreter tag (e.g., 'cp39')"""
def supports_feature(self, feature: str) -> bool:
"""
Check if Python supports specific feature.
Args:
feature: Feature name to check
Returns:
True if feature is supported
"""
def get_python_info(executable: Path | str) -> PythonInfo:
"""
Get comprehensive Python interpreter information.
Args:
executable: Path to Python interpreter
Returns:
PythonInfo instance with interpreter details
"""from pdm.environments import get_environment, PythonEnvironment
from pathlib import Path
# Get environment for system Python
python_path = Path("/usr/bin/python3.9")
env = get_environment(python_path)
# Check environment type
print(f"Environment type: {type(env).__name__}")
print(f"Python executable: {env.python_executable}")
print(f"Is global: {env.is_global()}")
# Get environment paths
paths = env.get_paths()
for key, path in paths.items():
print(f"{key}: {path}")
# Get installed packages
working_set = env.get_working_set()
for dist in working_set:
print(f"{dist.name} {dist.version}")from pdm.environments import PythonEnvironment
# Create environment instance
env = PythonEnvironment("/usr/bin/python3.9")
# Install packages
env.install([
"requests>=2.25.0",
"click>=8.0.0",
"rich"
])
# Check what's installed
working_set = env.get_working_set()
installed = {dist.name: dist.version for dist in working_set}
print("Installed packages:", installed)
# Uninstall packages
env.uninstall(["rich"])
# Update shebangs after installation
env.update_shebangs(["requests", "click"])from pdm.environments import create_venv, find_python_executable
from pathlib import Path
# Find appropriate Python version
python_exe = find_python_executable(">=3.8")
print(f"Using Python: {python_exe}")
# Create virtual environment
venv_path = Path("./my-venv")
env = create_venv(
location=venv_path,
python_executable=python_exe,
prompt="my-project"
)
# Verify virtual environment
local_env = env
if hasattr(local_env, 'is_venv') and local_env.is_venv():
venv_root = local_env.get_venv_root()
print(f"Created virtual environment at: {venv_root}")from pdm.environments import get_environment, get_python_info
from pathlib import Path
# Detect environment type
env = get_environment("/usr/bin/python3")
print(f"Environment: {type(env).__name__}")
# Get detailed Python information
python_info = get_python_info(env.python_executable)
print(f"Python {python_info.version_string}")
print(f"Implementation: {python_info.implementation}")
print(f"Architecture: {python_info.architecture}")
print(f"Interpreter tag: {python_info.interpreter_tag}")
# Check feature support
if python_info.supports_feature("f-strings"):
print("F-strings are supported")from pdm.environments import PythonEnvironment
from pathlib import Path
import subprocess
env = PythonEnvironment("/usr/bin/python3.9")
# Run Python script in environment
result = env.run_command([
"python", "-c", "import sys; print(sys.version)"
])
print("Python version:", result.stdout.decode())
# Run with custom environment variables
result = env.run_command(
["python", "-c", "import os; print(os.environ.get('CUSTOM_VAR'))"],
env={"CUSTOM_VAR": "test_value"}
)
print("Custom variable:", result.stdout.decode())
# Run from specific working directory
result = env.run_command(
["python", "-m", "pip", "list"],
cwd=Path("/tmp")
)Install with Tessl CLI
npx tessl i tessl/pypi-pdm