0
# Exception Handling
1
2
RequirementsLib provides comprehensive exception classes for handling various error conditions during requirement parsing, file operations, and format conversions. These exceptions enable proper error handling and debugging in applications using the library.
3
4
## Capabilities
5
6
### Base Exceptions
7
8
Core exception classes that serve as the foundation for more specific error types.
9
10
```python { .api }
11
class RequirementError(Exception):
12
"""
13
Base exception for requirement-related errors.
14
15
Raised when parsing or processing requirements fails due to
16
malformed input, invalid specifications, or processing errors.
17
"""
18
```
19
20
### Parameter Validation Exceptions
21
22
Handle missing or invalid parameters during requirement processing.
23
24
```python { .api }
25
class MissingParameter(Exception):
26
"""
27
Raised when required parameters are missing.
28
29
Provides methods for generating and displaying helpful error messages
30
to assist with debugging parameter-related issues.
31
"""
32
33
def __init__(self, param):
34
"""
35
Initialize with missing parameter name.
36
37
Parameters:
38
- param: Name of the missing parameter
39
"""
40
41
@classmethod
42
def get_message(cls, param):
43
"""
44
Generate error message for missing parameter.
45
46
Parameters:
47
- param: Parameter name
48
49
Returns:
50
str: Formatted error message
51
"""
52
53
def show(self, param):
54
"""
55
Display error message to stderr.
56
57
Parameters:
58
- param: Parameter name
59
"""
60
```
61
62
### File Corruption Exceptions
63
64
Handle various types of file corruption and parsing errors.
65
66
```python { .api }
67
class FileCorruptException(OSError):
68
"""
69
Base exception for corrupt file errors.
70
71
Extends OSError to provide file-specific error handling with
72
support for backup file paths and detailed error messages.
73
"""
74
75
def __init__(self, path, *args, backup_path=None):
76
"""
77
Initialize with file path and optional backup path.
78
79
Parameters:
80
- path: Path to the corrupt file
81
- backup_path: Optional path to backup file
82
"""
83
84
def get_message(self, path, backup_path=None):
85
"""
86
Generate error message for file corruption.
87
88
Parameters:
89
- path: Path to corrupt file
90
- backup_path: Optional backup file path
91
92
Returns:
93
str: Formatted error message
94
"""
95
96
def show(self):
97
"""Display error message to user."""
98
```
99
100
### Lockfile-Specific Exceptions
101
102
Handle errors specific to Pipfile.lock operations.
103
104
```python { .api }
105
class LockfileCorruptException(FileCorruptException):
106
"""
107
Raised when lockfile is corrupt or unreadable.
108
109
Occurs when Pipfile.lock files have invalid JSON, missing required
110
sections, or other structural problems that prevent parsing.
111
"""
112
113
def __init__(self, path, backup_path=None):
114
"""
115
Initialize with lockfile path.
116
117
Parameters:
118
- path: Path to corrupt lockfile
119
- backup_path: Optional backup file path
120
"""
121
122
def get_message(self, path, backup_path=None):
123
"""
124
Generate lockfile-specific error message.
125
126
Parameters:
127
- path: Path to corrupt lockfile
128
- backup_path: Optional backup file path
129
130
Returns:
131
str: Formatted error message
132
"""
133
134
def show(self, path, backup_path=None):
135
"""
136
Display lockfile error message.
137
138
Parameters:
139
- path: Path to corrupt lockfile
140
- backup_path: Optional backup file path
141
"""
142
```
143
144
### Pipfile-Specific Exceptions
145
146
Handle errors specific to Pipfile operations.
147
148
```python { .api }
149
class PipfileCorruptException(FileCorruptException):
150
"""
151
Raised when Pipfile is corrupt or unreadable.
152
153
Occurs when Pipfile has invalid TOML syntax, missing required
154
sections, or other structural problems that prevent parsing.
155
"""
156
157
def __init__(self, path, backup_path=None):
158
"""
159
Initialize with Pipfile path.
160
161
Parameters:
162
- path: Path to corrupt Pipfile
163
- backup_path: Optional backup file path
164
"""
165
166
def get_message(self, path, backup_path=None):
167
"""
168
Generate Pipfile-specific error message.
169
170
Parameters:
171
- path: Path to corrupt Pipfile
172
- backup_path: Optional backup file path
173
174
Returns:
175
str: Formatted error message
176
"""
177
178
def show(self, path, backup_path=None):
179
"""
180
Display Pipfile error message.
181
182
Parameters:
183
- path: Path to corrupt Pipfile
184
- backup_path: Optional backup file path
185
"""
186
```
187
188
### File Not Found Exceptions
189
190
Handle missing file errors.
191
192
```python { .api }
193
class PipfileNotFound(FileNotFoundError):
194
"""
195
Raised when Pipfile cannot be found.
196
197
Extends FileNotFoundError to provide Pipfile-specific context
198
when attempting to load Pipfiles that don't exist.
199
"""
200
201
def __init__(self, path, *args, **kwargs):
202
"""
203
Initialize with Pipfile path.
204
205
Parameters:
206
- path: Path to missing Pipfile
207
"""
208
```
209
210
## Usage Examples
211
212
### Basic Exception Handling
213
214
```python
215
from requirementslib import Requirement, Pipfile, Lockfile
216
from requirementslib.exceptions import (
217
RequirementError,
218
MissingParameter,
219
LockfileCorruptException,
220
PipfileCorruptException,
221
PipfileNotFound
222
)
223
224
# Handle requirement parsing errors
225
try:
226
req = Requirement.from_line("invalid requirement line")
227
except RequirementError as e:
228
print(f"Failed to parse requirement: {e}")
229
230
# Handle missing parameter errors
231
try:
232
# Some operation that might have missing parameters
233
pass
234
except MissingParameter as e:
235
print(f"Missing required parameter: {e}")
236
e.show(e.args[0]) # Show detailed error message
237
```
238
239
### File Operation Error Handling
240
241
```python
242
from requirementslib import Pipfile, Lockfile
243
from requirementslib.exceptions import (
244
PipfileNotFound,
245
PipfileCorruptException,
246
LockfileCorruptException
247
)
248
249
# Handle Pipfile loading errors
250
try:
251
pipfile = Pipfile.load("./Pipfile")
252
except PipfileNotFound as e:
253
print(f"Pipfile not found: {e}")
254
# Create new Pipfile or use defaults
255
pipfile = Pipfile.load("./Pipfile", create=True)
256
except PipfileCorruptException as e:
257
print(f"Pipfile is corrupt: {e}")
258
e.show(e.args[0]) # Show detailed error message
259
260
# Handle lockfile loading errors
261
try:
262
lockfile = Lockfile.load("./Pipfile.lock")
263
except LockfileCorruptException as e:
264
print(f"Lockfile is corrupt: {e}")
265
e.show(e.args[0], e.args[1] if len(e.args) > 1 else None)
266
# Regenerate lockfile from Pipfile
267
lockfile = Lockfile.lockfile_from_pipfile("./Pipfile")
268
```
269
270
### Comprehensive Error Handling
271
272
```python
273
from requirementslib import Requirement, Pipfile, Lockfile
274
from requirementslib.exceptions import *
275
import sys
276
277
def safe_parse_requirement(line):
278
"""Safely parse a requirement line with error handling."""
279
try:
280
return Requirement.from_line(line)
281
except RequirementError as e:
282
print(f"Error parsing requirement '{line}': {e}", file=sys.stderr)
283
return None
284
except MissingParameter as e:
285
print(f"Missing parameter while parsing '{line}':", file=sys.stderr)
286
e.show(e.args[0])
287
return None
288
289
def safe_load_pipfile(path):
290
"""Safely load a Pipfile with comprehensive error handling."""
291
try:
292
return Pipfile.load(path)
293
except PipfileNotFound:
294
print(f"Pipfile not found at {path}, creating new one")
295
return Pipfile.load(path, create=True)
296
except PipfileCorruptException as e:
297
print(f"Pipfile at {path} is corrupt:")
298
e.show(path)
299
return None
300
except Exception as e:
301
print(f"Unexpected error loading Pipfile: {e}", file=sys.stderr)
302
return None
303
304
def safe_load_lockfile(path, pipfile_path=None):
305
"""Safely load a lockfile with fallback to regeneration."""
306
try:
307
return Lockfile.load(path)
308
except LockfileCorruptException as e:
309
print(f"Lockfile at {path} is corrupt:")
310
e.show(path)
311
if pipfile_path:
312
print("Attempting to regenerate from Pipfile...")
313
try:
314
return Lockfile.lockfile_from_pipfile(pipfile_path)
315
except Exception as regen_error:
316
print(f"Failed to regenerate lockfile: {regen_error}")
317
return None
318
except Exception as e:
319
print(f"Unexpected error loading lockfile: {e}", file=sys.stderr)
320
return None
321
322
# Example usage
323
requirements_lines = [
324
"requests>=2.25.0",
325
"invalid_requirement_line",
326
"django[redis]==3.2.0"
327
]
328
329
for line in requirements_lines:
330
req = safe_parse_requirement(line)
331
if req:
332
print(f"Successfully parsed: {req.name} {req.specifiers}")
333
334
pipfile = safe_load_pipfile("./Pipfile")
335
if pipfile:
336
lockfile = safe_load_lockfile("./Pipfile.lock", "./Pipfile")
337
```
338
339
### Custom Exception Handling
340
341
```python
342
from requirementslib.exceptions import RequirementError
343
import logging
344
345
# Set up logging for better error tracking
346
logging.basicConfig(level=logging.INFO)
347
logger = logging.getLogger(__name__)
348
349
def process_requirements_with_logging(requirements_lines):
350
"""Process requirements with detailed logging."""
351
successful = []
352
failed = []
353
354
for line in requirements_lines:
355
try:
356
req = Requirement.from_line(line)
357
successful.append(req)
358
logger.info(f"Successfully parsed: {req.name}")
359
except RequirementError as e:
360
failed.append((line, str(e)))
361
logger.error(f"Failed to parse '{line}': {e}")
362
except Exception as e:
363
failed.append((line, f"Unexpected error: {str(e)}"))
364
logger.error(f"Unexpected error parsing '{line}': {e}")
365
366
logger.info(f"Processed {len(successful)} requirements successfully")
367
logger.info(f"Failed to process {len(failed)} requirements")
368
369
return successful, failed
370
```