0
# Exception Handling
1
2
Comprehensive exception hierarchy for handling various error conditions including file operations, command execution, and dependency resolution failures. Pipenv provides specific exception types for different error scenarios to enable proper error handling and debugging.
3
4
## Capabilities
5
6
### Base Exception Class
7
8
The foundation exception class for all pipenv-specific errors.
9
10
```python { .api }
11
class PipenvException(Exception):
12
"""
13
Base exception class for all pipenv-specific errors.
14
15
All pipenv exceptions inherit from this class, allowing for
16
broad exception catching when needed.
17
"""
18
```
19
20
Usage examples:
21
```python
22
from pipenv.exceptions import PipenvException
23
24
try:
25
# Some pipenv operation
26
pass
27
except PipenvException as e:
28
print(f"Pipenv error occurred: {e}")
29
except Exception as e:
30
print(f"Unexpected error: {e}")
31
```
32
33
### Command Execution Errors
34
35
Errors related to subprocess execution and command failures.
36
37
```python { .api }
38
class PipenvCmdError(PipenvException):
39
"""
40
Command execution errors.
41
42
Raised when external commands (pip, python, etc.) fail
43
or return non-zero exit codes.
44
"""
45
46
class PipenvUsageError(PipenvException):
47
"""
48
Usage and argument errors.
49
50
Raised when commands are called with invalid arguments
51
or in inappropriate contexts.
52
"""
53
```
54
55
Usage examples:
56
```python
57
from pipenv.exceptions import PipenvCmdError, PipenvUsageError
58
import subprocess
59
60
def run_pip_command(args):
61
try:
62
result = subprocess.run(["pip"] + args, check=True, capture_output=True, text=True)
63
return result.stdout
64
except subprocess.CalledProcessError as e:
65
raise PipenvCmdError(f"Pip command failed: {e}")
66
67
def validate_python_version(version):
68
if not version or not version.replace(".", "").isdigit():
69
raise PipenvUsageError(f"Invalid Python version specification: {version}")
70
71
# Usage
72
try:
73
run_pip_command(["install", "nonexistent-package"])
74
except PipenvCmdError as e:
75
print(f"Command error: {e}")
76
77
try:
78
validate_python_version("invalid.version")
79
except PipenvUsageError as e:
80
print(f"Usage error: {e}")
81
```
82
83
### File Operation Errors
84
85
Errors related to file system operations and file handling.
86
87
```python { .api }
88
class PipenvFileError(PipenvException):
89
"""
90
File operation errors.
91
92
Raised when file read/write operations fail or
93
when required files are corrupted or inaccessible.
94
"""
95
96
class PipfileNotFound(PipenvException):
97
"""
98
Pipfile not found error.
99
100
Raised when operations require a Pipfile but none
101
can be found in the current directory or parents.
102
"""
103
104
class LockfileNotFound(PipenvException):
105
"""
106
Lockfile not found error.
107
108
Raised when operations require a Pipfile.lock but
109
none exists or is inaccessible.
110
"""
111
```
112
113
Usage examples:
114
```python
115
from pipenv.exceptions import PipenvFileError, PipfileNotFound, LockfileNotFound
116
import json
117
from pathlib import Path
118
119
def load_pipfile(path="Pipfile"):
120
pipfile_path = Path(path)
121
if not pipfile_path.exists():
122
raise PipfileNotFound(f"Pipfile not found at {pipfile_path}")
123
124
try:
125
with open(pipfile_path, 'r') as f:
126
return f.read()
127
except (IOError, OSError) as e:
128
raise PipenvFileError(f"Cannot read Pipfile: {e}")
129
130
def load_lockfile(path="Pipfile.lock"):
131
lockfile_path = Path(path)
132
if not lockfile_path.exists():
133
raise LockfileNotFound(f"Pipfile.lock not found at {lockfile_path}")
134
135
try:
136
with open(lockfile_path, 'r') as f:
137
return json.load(f)
138
except (IOError, OSError, json.JSONDecodeError) as e:
139
raise PipenvFileError(f"Cannot read or parse Pipfile.lock: {e}")
140
141
# Usage
142
try:
143
pipfile_content = load_pipfile()
144
lockfile_data = load_lockfile()
145
except PipfileNotFound as e:
146
print(f"Pipfile missing: {e}")
147
except LockfileNotFound as e:
148
print(f"Lockfile missing: {e}")
149
except PipenvFileError as e:
150
print(f"File error: {e}")
151
```
152
153
### Virtual Environment Errors
154
155
Errors related to virtual environment creation and management.
156
157
```python { .api }
158
class VirtualenvCreationException(PipenvException):
159
"""
160
Virtual environment creation errors.
161
162
Raised when virtual environment creation fails due to
163
permissions, disk space, or other system issues.
164
"""
165
```
166
167
Usage examples:
168
```python
169
from pipenv.exceptions import VirtualenvCreationException
170
import subprocess
171
import os
172
173
def create_virtualenv(path, python_version=None):
174
"""Create virtual environment with error handling."""
175
cmd = ["python", "-m", "venv", path]
176
if python_version:
177
cmd[0] = f"python{python_version}"
178
179
try:
180
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
181
return path
182
except subprocess.CalledProcessError as e:
183
raise VirtualenvCreationException(
184
f"Failed to create virtual environment at {path}: {e.stderr}"
185
)
186
except FileNotFoundError:
187
python_exe = cmd[0]
188
raise VirtualenvCreationException(
189
f"Python executable not found: {python_exe}"
190
)
191
192
# Usage
193
try:
194
venv_path = create_virtualenv("/tmp/test_venv", "3.9")
195
print(f"Virtual environment created at: {venv_path}")
196
except VirtualenvCreationException as e:
197
print(f"Virtualenv creation failed: {e}")
198
```
199
200
### Package Installation Errors
201
202
Errors related to package installation and removal.
203
204
```python { .api }
205
class InstallError(PipenvException):
206
"""
207
Package installation errors.
208
209
Raised when package installation fails due to dependency
210
conflicts, network issues, or other installation problems.
211
"""
212
213
class UninstallError(PipenvException):
214
"""
215
Package uninstall errors.
216
217
Raised when package removal fails due to dependencies
218
or system restrictions.
219
"""
220
```
221
222
Usage examples:
223
```python
224
from pipenv.exceptions import InstallError, UninstallError
225
import subprocess
226
227
def install_package(package_name, environment_path=None):
228
"""Install package with error handling."""
229
cmd = ["pip", "install", package_name]
230
env = os.environ.copy()
231
232
if environment_path:
233
env["VIRTUAL_ENV"] = environment_path
234
cmd = [f"{environment_path}/bin/pip", "install", package_name]
235
236
try:
237
result = subprocess.run(cmd, check=True, capture_output=True, text=True, env=env)
238
return result.stdout
239
except subprocess.CalledProcessError as e:
240
raise InstallError(f"Failed to install {package_name}: {e.stderr}")
241
242
def uninstall_package(package_name, environment_path=None):
243
"""Uninstall package with error handling."""
244
cmd = ["pip", "uninstall", "-y", package_name]
245
env = os.environ.copy()
246
247
if environment_path:
248
env["VIRTUAL_ENV"] = environment_path
249
cmd = [f"{environment_path}/bin/pip", "uninstall", "-y", package_name]
250
251
try:
252
result = subprocess.run(cmd, check=True, capture_output=True, text=True, env=env)
253
return result.stdout
254
except subprocess.CalledProcessError as e:
255
raise UninstallError(f"Failed to uninstall {package_name}: {e.stderr}")
256
257
# Usage
258
try:
259
install_package("requests")
260
print("Package installed successfully")
261
except InstallError as e:
262
print(f"Installation failed: {e}")
263
264
try:
265
uninstall_package("requests")
266
print("Package uninstalled successfully")
267
except UninstallError as e:
268
print(f"Uninstall failed: {e}")
269
```
270
271
### Dependency Resolution Errors
272
273
Errors related to dependency resolution and version conflicts.
274
275
```python { .api }
276
class ResolutionFailure(PipenvException):
277
"""
278
Dependency resolution errors.
279
280
Raised when pip resolver cannot find a compatible
281
set of package versions that satisfy all requirements.
282
"""
283
284
class DependencyConflict(PipenvException):
285
"""
286
Dependency conflict errors.
287
288
Raised when package dependencies have incompatible
289
version requirements that cannot be resolved.
290
"""
291
292
class RequirementError(PipenvException):
293
"""
294
Requirement specification errors.
295
296
Raised when package requirement specifications are
297
invalid or cannot be parsed.
298
"""
299
300
class JSONParseError(PipenvException):
301
"""
302
JSON parsing errors.
303
304
Raised when JSON files (lockfiles, etc.) cannot be
305
parsed due to syntax errors or corruption.
306
"""
307
308
class DeployException(PipenvException):
309
"""
310
Deployment errors.
311
312
Raised when deployment operations fail due to
313
missing requirements or environment issues.
314
"""
315
316
class PipenvOptionsError(PipenvException):
317
"""
318
Options validation errors.
319
320
Raised when command-line options or configuration
321
values are invalid or conflicting.
322
"""
323
324
class SystemUsageError(PipenvException):
325
"""
326
System usage errors.
327
328
Raised when pipenv is used inappropriately on the
329
system or in unsupported configurations.
330
"""
331
332
class SetupException(PipenvException):
333
"""
334
Setup and initialization errors.
335
336
Raised when project setup or initialization
337
operations fail.
338
"""
339
340
class VirtualenvException(PipenvException):
341
"""
342
Virtual environment errors.
343
344
Raised when virtual environment operations fail
345
beyond creation (activation, deactivation, etc.).
346
"""
347
348
class VirtualenvActivationException(VirtualenvException):
349
"""
350
Virtual environment activation errors.
351
352
Raised specifically when virtual environment
353
activation fails or is not supported.
354
"""
355
```
356
357
Usage examples:
358
```python
359
from pipenv.exceptions import ResolutionFailure
360
361
def resolve_dependencies(requirements):
362
"""Resolve package dependencies with error handling."""
363
# Simulate dependency resolution
364
conflicts = []
365
366
# Check for version conflicts
367
for req1 in requirements:
368
for req2 in requirements:
369
if req1 != req2 and req1.name == req2.name:
370
if req1.version != req2.version:
371
conflicts.append((req1, req2))
372
373
if conflicts:
374
conflict_msg = ", ".join([
375
f"{req1.name} {req1.version} vs {req2.version}"
376
for req1, req2 in conflicts
377
])
378
raise ResolutionFailure(f"Version conflicts detected: {conflict_msg}")
379
380
return requirements
381
382
# Example requirement class
383
class Requirement:
384
def __init__(self, name, version):
385
self.name = name
386
self.version = version
387
388
# Usage
389
try:
390
requirements = [
391
Requirement("requests", "2.25.0"),
392
Requirement("requests", "2.24.0"), # Conflict!
393
]
394
resolved = resolve_dependencies(requirements)
395
except ResolutionFailure as e:
396
print(f"Resolution failed: {e}")
397
```
398
399
## Exception Handling Patterns
400
401
Common patterns for handling pipenv exceptions.
402
403
### Comprehensive Error Handling
404
405
```python
406
from pipenv.exceptions import (
407
PipenvException, PipenvCmdError, PipenvFileError,
408
PipfileNotFound, LockfileNotFound, VirtualenvCreationException,
409
InstallError, UninstallError, ResolutionFailure
410
)
411
412
def robust_pipenv_operation():
413
"""Example of comprehensive error handling."""
414
try:
415
# Attempt pipenv operations
416
load_pipfile()
417
create_virtualenv("/tmp/venv")
418
install_package("requests")
419
420
except PipfileNotFound as e:
421
print(f"Setup required: {e}")
422
# Could create new Pipfile here
423
424
except LockfileNotFound as e:
425
print(f"Lock file missing: {e}")
426
# Could generate lock file here
427
428
except VirtualenvCreationException as e:
429
print(f"Environment setup failed: {e}")
430
# Could try alternative environment creation
431
432
except (InstallError, UninstallError) as e:
433
print(f"Package operation failed: {e}")
434
# Could retry with different options
435
436
except ResolutionFailure as e:
437
print(f"Dependency conflict: {e}")
438
# Could suggest resolution strategies
439
440
except PipenvCmdError as e:
441
print(f"Command failed: {e}")
442
# Could provide command-specific help
443
444
except PipenvFileError as e:
445
print(f"File operation failed: {e}")
446
# Could check permissions or disk space
447
448
except PipenvException as e:
449
print(f"General pipenv error: {e}")
450
# Catch-all for other pipenv errors
451
452
except Exception as e:
453
print(f"Unexpected error: {e}")
454
# Handle non-pipenv errors
455
```
456
457
### Retry Logic with Exceptions
458
459
```python
460
import time
461
from pipenv.exceptions import InstallError, PipenvCmdError
462
463
def install_with_retry(package_name, max_retries=3):
464
"""Install package with retry logic."""
465
for attempt in range(max_retries):
466
try:
467
return install_package(package_name)
468
except (InstallError, PipenvCmdError) as e:
469
if attempt == max_retries - 1:
470
raise e
471
print(f"Install attempt {attempt + 1} failed: {e}")
472
print(f"Retrying in {2 ** attempt} seconds...")
473
time.sleep(2 ** attempt)
474
475
raise InstallError(f"Failed to install {package_name} after {max_retries} attempts")
476
```
477
478
### Context-Aware Error Handling
479
480
```python
481
from pipenv.exceptions import PipenvException
482
import logging
483
484
class PipenvErrorHandler:
485
"""Context-aware error handler for pipenv operations."""
486
487
def __init__(self, context=""):
488
self.context = context
489
self.logger = logging.getLogger(__name__)
490
491
def handle_error(self, error, operation=""):
492
"""Handle pipenv errors with context."""
493
full_context = f"{self.context} - {operation}" if operation else self.context
494
495
if isinstance(error, PipfileNotFound):
496
self.logger.error(f"{full_context}: Pipfile not found. Run 'pipenv install' to initialize.")
497
elif isinstance(error, VirtualenvCreationException):
498
self.logger.error(f"{full_context}: Virtual environment creation failed. Check Python installation.")
499
elif isinstance(error, ResolutionFailure):
500
self.logger.error(f"{full_context}: Dependency resolution failed. Check version requirements.")
501
elif isinstance(error, PipenvException):
502
self.logger.error(f"{full_context}: Pipenv error - {error}")
503
else:
504
self.logger.error(f"{full_context}: Unexpected error - {error}")
505
506
# Usage
507
handler = PipenvErrorHandler("Project Setup")
508
509
try:
510
# Pipenv operations
511
pass
512
except Exception as e:
513
handler.handle_error(e, "Installing dependencies")
514
```
515
516
## Custom Exception Extensions
517
518
You can extend pipenv exceptions for application-specific error handling.
519
520
```python
521
from pipenv.exceptions import PipenvException, InstallError
522
523
class ProjectSetupError(PipenvException):
524
"""Custom exception for project setup failures."""
525
pass
526
527
class DependencyConflictError(ResolutionFailure):
528
"""Enhanced dependency conflict error with resolution suggestions."""
529
530
def __init__(self, message, conflicts=None, suggestions=None):
531
super().__init__(message)
532
self.conflicts = conflicts or []
533
self.suggestions = suggestions or []
534
535
def get_resolution_help(self):
536
"""Get suggested resolutions for conflicts."""
537
if not self.suggestions:
538
return "No automatic resolution suggestions available."
539
540
help_text = "Suggested resolutions:\n"
541
for i, suggestion in enumerate(self.suggestions, 1):
542
help_text += f"{i}. {suggestion}\n"
543
return help_text
544
545
# Usage
546
try:
547
# Some operation that might conflict
548
pass
549
except ResolutionFailure as e:
550
# Convert to enhanced exception
551
enhanced_error = DependencyConflictError(
552
str(e),
553
conflicts=["requests 2.25.0 vs 2.24.0"],
554
suggestions=["Update all packages to compatible versions", "Use dependency_links for specific versions"]
555
)
556
print(enhanced_error.get_resolution_help())
557
```