0
# Environment Management
1
2
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.
3
4
## Capabilities
5
6
### Base Environment Interface
7
8
Abstract base class defining the common interface for all environment types in PDM.
9
10
```python { .api }
11
from abc import ABC, abstractmethod
12
from pathlib import Path
13
14
class BaseEnvironment(ABC):
15
"""
16
Abstract base class for Python environments.
17
18
Provides unified interface for environment operations including
19
path resolution, Python executable access, and package management.
20
"""
21
22
@property
23
@abstractmethod
24
def python_executable(self) -> Path:
25
"""Path to Python executable for this environment"""
26
27
@abstractmethod
28
def get_paths(self) -> dict[str, str]:
29
"""
30
Get environment paths following PEP 427.
31
32
Returns:
33
Dictionary with standard path keys:
34
- platlib: Platform-specific library directory
35
- purelib: Pure Python library directory
36
- headers: Header files directory
37
- scripts: Executable scripts directory
38
- data: Data files directory
39
"""
40
41
@abstractmethod
42
def get_python_executable(self) -> Path:
43
"""
44
Get Python executable path.
45
46
Returns:
47
Path to Python interpreter for this environment
48
"""
49
50
def is_global(self) -> bool:
51
"""
52
Check if this is a global/system environment.
53
54
Returns:
55
True if global system environment
56
"""
57
58
def get_working_set(self) -> list[Distribution]:
59
"""
60
Get currently installed packages in environment.
61
62
Returns:
63
List of installed package distributions
64
"""
65
```
66
67
### Bare Environment
68
69
Minimal environment implementation without package management capabilities.
70
71
```python { .api }
72
class BareEnvironment(BaseEnvironment):
73
"""
74
Minimal environment implementation for basic Python execution.
75
76
Provides Python executable access and path resolution without
77
package installation capabilities. Useful for read-only environments.
78
"""
79
80
def __init__(self, python_executable: Path | str):
81
"""
82
Initialize bare environment.
83
84
Args:
85
python_executable: Path to Python interpreter
86
"""
87
88
@property
89
def python_executable(self) -> Path:
90
"""Python executable path"""
91
92
def get_paths(self) -> dict[str, str]:
93
"""Get environment paths from sysconfig"""
94
95
def get_python_executable(self) -> Path:
96
"""Get Python executable path"""
97
```
98
99
### Python Environment
100
101
Full-featured Python environment with complete package management capabilities.
102
103
```python { .api }
104
class PythonEnvironment(BaseEnvironment):
105
"""
106
Full Python environment with package management capabilities.
107
108
Supports package installation, uninstallation, and environment
109
manipulation using pip and other standard tools.
110
"""
111
112
def __init__(
113
self,
114
python_executable: Path | str,
115
prefix: Path | str | None = None
116
):
117
"""
118
Initialize Python environment.
119
120
Args:
121
python_executable: Path to Python interpreter
122
prefix: Optional environment prefix path
123
"""
124
125
def install(self, requirements: list[str]) -> None:
126
"""
127
Install packages in this environment.
128
129
Args:
130
requirements: List of requirement specifications to install
131
132
Raises:
133
InstallationError: Package installation failed
134
"""
135
136
def uninstall(self, packages: list[str]) -> None:
137
"""
138
Uninstall packages from this environment.
139
140
Args:
141
packages: List of package names to uninstall
142
143
Raises:
144
UninstallError: Package uninstallation failed
145
"""
146
147
def update_shebangs(self, packages: list[str]) -> None:
148
"""
149
Update script shebangs for specified packages.
150
151
Args:
152
packages: Package names to update shebangs for
153
"""
154
155
def get_python_version(self) -> tuple[int, int, int]:
156
"""
157
Get Python version tuple.
158
159
Returns:
160
Python version as (major, minor, micro) tuple
161
"""
162
163
def run_command(
164
self,
165
command: list[str],
166
cwd: Path | str | None = None,
167
env: dict[str, str] | None = None
168
) -> subprocess.CompletedProcess:
169
"""
170
Run command in this environment.
171
172
Args:
173
command: Command and arguments to execute
174
cwd: Working directory for command
175
env: Environment variables for command
176
177
Returns:
178
Completed process result
179
"""
180
```
181
182
### Local Python Environment
183
184
Specialized environment for local/system Python installations with enhanced integration.
185
186
```python { .api }
187
class PythonLocalEnvironment(PythonEnvironment):
188
"""
189
Local Python environment for system installations.
190
191
Provides enhanced integration with system Python installations
192
and local development workflows.
193
"""
194
195
def __init__(self, python_executable: Path | str):
196
"""
197
Initialize local Python environment.
198
199
Args:
200
python_executable: Path to system Python interpreter
201
"""
202
203
def get_site_packages(self) -> list[Path]:
204
"""
205
Get site-packages directories.
206
207
Returns:
208
List of site-packages directory paths
209
"""
210
211
def is_venv(self) -> bool:
212
"""
213
Check if environment is a virtual environment.
214
215
Returns:
216
True if virtual environment
217
"""
218
219
def get_venv_root(self) -> Path | None:
220
"""
221
Get virtual environment root directory.
222
223
Returns:
224
Path to venv root, or None if not a venv
225
"""
226
```
227
228
### Environment Detection and Creation
229
230
Utilities for environment detection, creation, and management.
231
232
```python { .api }
233
def get_environment(python_executable: Path | str) -> BaseEnvironment:
234
"""
235
Get appropriate environment instance for Python executable.
236
237
Args:
238
python_executable: Path to Python interpreter
239
240
Returns:
241
Environment instance (PythonEnvironment or PythonLocalEnvironment)
242
"""
243
244
def find_python_executable(version_spec: str | None = None) -> Path:
245
"""
246
Find Python executable matching version specification.
247
248
Args:
249
version_spec: Python version specification (e.g., "3.9", ">=3.8")
250
251
Returns:
252
Path to matching Python executable
253
254
Raises:
255
NoPythonVersion: No matching Python found
256
"""
257
258
def create_venv(
259
location: Path | str,
260
python_executable: Path | str | None = None,
261
prompt: str | None = None
262
) -> PythonEnvironment:
263
"""
264
Create new virtual environment.
265
266
Args:
267
location: Directory for new virtual environment
268
python_executable: Python executable to use as base
269
prompt: Custom prompt for virtual environment
270
271
Returns:
272
New PythonEnvironment instance for created venv
273
"""
274
```
275
276
### Environment Information
277
278
Classes for gathering and representing Python environment information.
279
280
```python { .api }
281
@dataclass
282
class PythonInfo:
283
"""
284
Python interpreter information and capabilities.
285
286
Contains comprehensive information about a Python installation
287
including version, paths, and feature support.
288
"""
289
290
executable: Path
291
version: tuple[int, int, int]
292
implementation: str
293
architecture: str
294
abi_tag: str
295
296
@property
297
def version_string(self) -> str:
298
"""Formatted version string (e.g., '3.9.7')"""
299
300
@property
301
def interpreter_tag(self) -> str:
302
"""PEP 425 interpreter tag (e.g., 'cp39')"""
303
304
def supports_feature(self, feature: str) -> bool:
305
"""
306
Check if Python supports specific feature.
307
308
Args:
309
feature: Feature name to check
310
311
Returns:
312
True if feature is supported
313
"""
314
315
def get_python_info(executable: Path | str) -> PythonInfo:
316
"""
317
Get comprehensive Python interpreter information.
318
319
Args:
320
executable: Path to Python interpreter
321
322
Returns:
323
PythonInfo instance with interpreter details
324
"""
325
```
326
327
### Usage Examples
328
329
#### Basic Environment Operations
330
331
```python
332
from pdm.environments import get_environment, PythonEnvironment
333
from pathlib import Path
334
335
# Get environment for system Python
336
python_path = Path("/usr/bin/python3.9")
337
env = get_environment(python_path)
338
339
# Check environment type
340
print(f"Environment type: {type(env).__name__}")
341
print(f"Python executable: {env.python_executable}")
342
print(f"Is global: {env.is_global()}")
343
344
# Get environment paths
345
paths = env.get_paths()
346
for key, path in paths.items():
347
print(f"{key}: {path}")
348
349
# Get installed packages
350
working_set = env.get_working_set()
351
for dist in working_set:
352
print(f"{dist.name} {dist.version}")
353
```
354
355
#### Package Management in Environment
356
357
```python
358
from pdm.environments import PythonEnvironment
359
360
# Create environment instance
361
env = PythonEnvironment("/usr/bin/python3.9")
362
363
# Install packages
364
env.install([
365
"requests>=2.25.0",
366
"click>=8.0.0",
367
"rich"
368
])
369
370
# Check what's installed
371
working_set = env.get_working_set()
372
installed = {dist.name: dist.version for dist in working_set}
373
print("Installed packages:", installed)
374
375
# Uninstall packages
376
env.uninstall(["rich"])
377
378
# Update shebangs after installation
379
env.update_shebangs(["requests", "click"])
380
```
381
382
#### Virtual Environment Creation
383
384
```python
385
from pdm.environments import create_venv, find_python_executable
386
from pathlib import Path
387
388
# Find appropriate Python version
389
python_exe = find_python_executable(">=3.8")
390
print(f"Using Python: {python_exe}")
391
392
# Create virtual environment
393
venv_path = Path("./my-venv")
394
env = create_venv(
395
location=venv_path,
396
python_executable=python_exe,
397
prompt="my-project"
398
)
399
400
# Verify virtual environment
401
local_env = env
402
if hasattr(local_env, 'is_venv') and local_env.is_venv():
403
venv_root = local_env.get_venv_root()
404
print(f"Created virtual environment at: {venv_root}")
405
```
406
407
#### Environment Detection and Information
408
409
```python
410
from pdm.environments import get_environment, get_python_info
411
from pathlib import Path
412
413
# Detect environment type
414
env = get_environment("/usr/bin/python3")
415
print(f"Environment: {type(env).__name__}")
416
417
# Get detailed Python information
418
python_info = get_python_info(env.python_executable)
419
print(f"Python {python_info.version_string}")
420
print(f"Implementation: {python_info.implementation}")
421
print(f"Architecture: {python_info.architecture}")
422
print(f"Interpreter tag: {python_info.interpreter_tag}")
423
424
# Check feature support
425
if python_info.supports_feature("f-strings"):
426
print("F-strings are supported")
427
```
428
429
#### Running Commands in Environment
430
431
```python
432
from pdm.environments import PythonEnvironment
433
from pathlib import Path
434
import subprocess
435
436
env = PythonEnvironment("/usr/bin/python3.9")
437
438
# Run Python script in environment
439
result = env.run_command([
440
"python", "-c", "import sys; print(sys.version)"
441
])
442
print("Python version:", result.stdout.decode())
443
444
# Run with custom environment variables
445
result = env.run_command(
446
["python", "-c", "import os; print(os.environ.get('CUSTOM_VAR'))"],
447
env={"CUSTOM_VAR": "test_value"}
448
)
449
print("Custom variable:", result.stdout.decode())
450
451
# Run from specific working directory
452
result = env.run_command(
453
["python", "-m", "pip", "list"],
454
cwd=Path("/tmp")
455
)
456
```