0
# Exceptions
1
2
Custom exception classes for error handling and diagnostics. Prospector defines several specific exceptions for different error conditions that can occur during analysis.
3
4
## Capabilities
5
6
### Core Exceptions
7
8
```python { .api }
9
class FatalProspectorException(Exception):
10
def __init__(self, message: str) -> None
11
```
12
13
Exception used to indicate an internal prospector problem or fatal error that prevents analysis from continuing.
14
15
**Parameters:**
16
- `message`: str - Description of the fatal error
17
18
**Properties:**
19
- `message`: str - The error message
20
21
This exception is raised for critical errors such as:
22
- Tool configuration failures that prevent execution
23
- Internal prospector errors that cannot be recovered
24
- Missing required dependencies for essential functionality
25
- Fatal errors triggered by the `--die-on-tool-error` flag
26
27
**Usage:** When this exception is raised, Prospector will typically exit with code 2 to indicate a fatal error rather than normal analysis completion.
28
29
```python { .api }
30
class CouldNotHandleEncoding(Exception):
31
def __init__(self, path: Path) -> None
32
```
33
34
Exception raised when Prospector cannot determine or handle the encoding of a source file.
35
36
**Parameters:**
37
- `path`: Path - Path to the file with encoding issues
38
39
**Properties:**
40
- `path`: Path - The problematic file path
41
42
This exception occurs when:
43
- A file contains invalid byte sequences for its declared encoding
44
- The file encoding cannot be detected automatically
45
- Character encoding conversion fails
46
47
```python { .api }
48
class PermissionMissing(Exception):
49
def __init__(self, path: Path) -> None
50
```
51
52
Exception raised when Prospector lacks permissions to read a file or directory.
53
54
**Parameters:**
55
- `path`: Path - Path to the inaccessible file or directory
56
57
The exception message includes:
58
- Information about the current user and the inaccessible path
59
- Suggestions for fixing permissions or using ignore patterns
60
- Link to documentation about ignoring paths
61
62
This exception provides helpful guidance for resolving permission issues by either:
63
- Fixing file/directory permissions
64
- Adding the path to `--ignore-paths` command line option
65
- Adding the path to `ignore-paths` in a prospector profile
66
67
### Profile-Related Exceptions
68
69
```python { .api }
70
class ProfileNotFound(Exception):
71
def __init__(self, name: str, profile_path: list[Path]) -> None
72
```
73
74
Exception raised when a requested configuration profile cannot be found.
75
76
**Parameters:**
77
- `name`: str - Name of the profile that wasn't found
78
- `profile_path`: list[Path] - List of paths that were searched
79
80
**Properties:**
81
- `name`: str - The profile name that was requested
82
- `profile_path`: list[Path] - The search paths that were checked
83
84
This exception occurs when:
85
- A profile specified with `--profile` doesn't exist
86
- A profile referenced in `inherits` cannot be found
87
- Profile search paths don't contain the requested profile
88
89
```python { .api }
90
class CannotParseProfile(Exception):
91
def __init__(self, filepath: Path, parse_error: Any) -> None
92
```
93
94
Exception raised when a profile file contains invalid YAML or configuration.
95
96
**Parameters:**
97
- `filepath`: Path - Path to the problematic profile file
98
- `parse_error`: Any - The underlying parsing error from the YAML parser
99
100
**Properties:**
101
- `filepath`: Path - The profile file that failed to parse
102
- `parse_error`: Any - The original parsing error
103
104
```python { .api }
105
def get_parse_message(self) -> str
106
```
107
108
Returns a human-readable error message describing the parse failure.
109
110
**Returns:**
111
- `str` - Formatted error message with details about the parsing problem
112
113
## Usage Examples
114
115
### Basic Exception Handling
116
117
```python
118
from prospector.config import ProspectorConfig
119
from prospector.run import Prospector
120
from prospector.exceptions import (
121
FatalProspectorException,
122
CouldNotHandleEncoding,
123
PermissionMissing
124
)
125
126
def run_analysis_safely():
127
try:
128
config = ProspectorConfig()
129
prospector = Prospector(config)
130
prospector.execute()
131
132
messages = prospector.get_messages()
133
print(f"Analysis completed: {len(messages)} issues found")
134
135
except FatalProspectorException as e:
136
print(f"Fatal error: {e.message}")
137
return 2 # Fatal error exit code
138
139
except CouldNotHandleEncoding as e:
140
print(f"Encoding error in file {e.path}")
141
print("Try specifying file encoding or excluding the file")
142
return 1
143
144
except PermissionMissing as e:
145
print(f"Permission denied: {e}")
146
return 1
147
148
except Exception as e:
149
print(f"Unexpected error: {e}")
150
return 1
151
152
return 0
153
154
exit_code = run_analysis_safely()
155
```
156
157
### Profile Exception Handling
158
159
```python
160
from prospector.profiles.profile import ProspectorProfile, ProfileNotFound, CannotParseProfile
161
from pathlib import Path
162
163
def load_profile_with_fallback(profile_name: str, search_paths: list[Path]) -> ProspectorProfile:
164
try:
165
profile = ProspectorProfile.load(profile_name, search_paths)
166
print(f"Loaded profile: {profile_name}")
167
return profile
168
169
except ProfileNotFound as e:
170
print(f"Profile '{e.name}' not found in any of these locations:")
171
for path in e.profile_path:
172
print(f" {path}")
173
174
# Fall back to default profile
175
print("Falling back to default profile")
176
return ProspectorProfile.load("default", search_paths)
177
178
except CannotParseProfile as e:
179
print(f"Failed to parse profile file: {e.filepath}")
180
print("Parse error details:")
181
print(e.get_parse_message())
182
183
# Could fall back to default or re-raise
184
raise
185
186
# Usage
187
search_paths = [Path(".prospector"), Path("/etc/prospector/profiles")]
188
profile = load_profile_with_fallback("myproject", search_paths)
189
```
190
191
### File Processing Error Handling
192
193
```python
194
from prospector.finder import FileFinder
195
from prospector.exceptions import CouldNotHandleEncoding, PermissionMissing
196
from pathlib import Path
197
198
def process_files_safely(paths: list[Path]):
199
try:
200
finder = FileFinder(*paths)
201
modules = list(finder.iter_all_modules())
202
203
processed_count = 0
204
error_count = 0
205
206
for module_path in modules:
207
try:
208
# Simulate file processing that might fail
209
with open(module_path, 'r', encoding='utf-8') as f:
210
content = f.read()
211
processed_count += 1
212
213
except UnicodeDecodeError:
214
print(f"Encoding error in {module_path}")
215
error_count += 1
216
217
except PermissionError:
218
print(f"Permission denied: {module_path}")
219
error_count += 1
220
221
print(f"Processed {processed_count} files, {error_count} errors")
222
223
except FileNotFoundError as e:
224
print(f"Path not found: {e}")
225
except Exception as e:
226
print(f"Unexpected error during file processing: {e}")
227
228
# Usage
229
process_files_safely([Path("src"), Path("tests")])
230
```
231
232
### Tool Error Handling
233
234
```python
235
from prospector.config import ProspectorConfig
236
from prospector.run import Prospector
237
from prospector.exceptions import FatalProspectorException
238
239
def run_with_error_tolerance():
240
# Configure to continue on tool errors (default behavior)
241
config = ProspectorConfig()
242
243
# If you want to fail fast on any tool error, set die_on_tool_error
244
# This would be done via command line: --die-on-tool-error
245
246
prospector = Prospector(config)
247
248
try:
249
prospector.execute()
250
251
messages = prospector.get_messages()
252
summary = prospector.get_summary()
253
254
# Check if any tools failed
255
if summary and "external_config" in summary:
256
print(f"External config used: {summary['external_config']}")
257
258
# Look for tool failure messages
259
tool_failures = [msg for msg in messages if msg.code == "failure"]
260
if tool_failures:
261
print(f"Warning: {len(tool_failures)} tools failed to run")
262
for failure in tool_failures:
263
print(f" {failure.source}: {failure.message}")
264
265
return messages
266
267
except FatalProspectorException as e:
268
print(f"Tool error caused fatal failure: {e.message}")
269
raise
270
271
messages = run_with_error_tolerance()
272
```
273
274
### Custom Exception Handling
275
276
```python
277
from prospector.exceptions import FatalProspectorException
278
import logging
279
280
class ProspectorRunner:
281
def __init__(self):
282
self.logger = logging.getLogger(__name__)
283
284
def run_analysis(self, config_overrides=None):
285
try:
286
from prospector.config import ProspectorConfig
287
from prospector.run import Prospector
288
289
config = ProspectorConfig()
290
prospector = Prospector(config)
291
prospector.execute()
292
293
return {
294
'success': True,
295
'messages': prospector.get_messages(),
296
'summary': prospector.get_summary()
297
}
298
299
except FatalProspectorException as e:
300
self.logger.error(f"Fatal prospector error: {e.message}")
301
return {
302
'success': False,
303
'error': 'fatal',
304
'message': e.message
305
}
306
307
except Exception as e:
308
self.logger.exception("Unexpected error during analysis")
309
return {
310
'success': False,
311
'error': 'unexpected',
312
'message': str(e)
313
}
314
315
def handle_result(self, result):
316
if result['success']:
317
print(f"Analysis successful: {len(result['messages'])} issues")
318
return 0
319
else:
320
print(f"Analysis failed ({result['error']}): {result['message']}")
321
return 2 if result['error'] == 'fatal' else 1
322
323
# Usage
324
runner = ProspectorRunner()
325
result = runner.run_analysis()
326
exit_code = runner.handle_result(result)
327
```
328
329
### Exception Context and Debugging
330
331
```python
332
from prospector.config import ProspectorConfig
333
from prospector.run import Prospector
334
from prospector.exceptions import FatalProspectorException
335
import traceback
336
337
def debug_prospector_error():
338
try:
339
config = ProspectorConfig()
340
prospector = Prospector(config)
341
prospector.execute()
342
343
except FatalProspectorException as e:
344
print("=== FATAL PROSPECTOR ERROR ===")
345
print(f"Error message: {e.message}")
346
print(f"Error type: {type(e).__name__}")
347
348
# Print full traceback for debugging
349
print("\nFull traceback:")
350
traceback.print_exc()
351
352
# Additional debug information
353
print(f"\nConfiguration summary:")
354
print(f" Tools to run: {config.tools_to_run}")
355
print(f" Paths: {config.paths}")
356
print(f" Working directory: {config.workdir}")
357
358
except Exception as e:
359
print("=== UNEXPECTED ERROR ===")
360
print(f"Error: {e}")
361
print(f"Type: {type(e).__name__}")
362
traceback.print_exc()
363
364
debug_prospector_error()
365
```