Prospector is a tool to analyse Python code by aggregating the result of other tools.
—
Custom exception classes for error handling and diagnostics. Prospector defines several specific exceptions for different error conditions that can occur during analysis.
class FatalProspectorException(Exception):
def __init__(self, message: str) -> NoneException used to indicate an internal prospector problem or fatal error that prevents analysis from continuing.
Parameters:
message: str - Description of the fatal errorProperties:
message: str - The error messageThis exception is raised for critical errors such as:
--die-on-tool-error flagUsage: When this exception is raised, Prospector will typically exit with code 2 to indicate a fatal error rather than normal analysis completion.
class CouldNotHandleEncoding(Exception):
def __init__(self, path: Path) -> NoneException raised when Prospector cannot determine or handle the encoding of a source file.
Parameters:
path: Path - Path to the file with encoding issuesProperties:
path: Path - The problematic file pathThis exception occurs when:
class PermissionMissing(Exception):
def __init__(self, path: Path) -> NoneException raised when Prospector lacks permissions to read a file or directory.
Parameters:
path: Path - Path to the inaccessible file or directoryThe exception message includes:
This exception provides helpful guidance for resolving permission issues by either:
--ignore-paths command line optionignore-paths in a prospector profileclass ProfileNotFound(Exception):
def __init__(self, name: str, profile_path: list[Path]) -> NoneException raised when a requested configuration profile cannot be found.
Parameters:
name: str - Name of the profile that wasn't foundprofile_path: list[Path] - List of paths that were searchedProperties:
name: str - The profile name that was requestedprofile_path: list[Path] - The search paths that were checkedThis exception occurs when:
--profile doesn't existinherits cannot be foundclass CannotParseProfile(Exception):
def __init__(self, filepath: Path, parse_error: Any) -> NoneException raised when a profile file contains invalid YAML or configuration.
Parameters:
filepath: Path - Path to the problematic profile fileparse_error: Any - The underlying parsing error from the YAML parserProperties:
filepath: Path - The profile file that failed to parseparse_error: Any - The original parsing errordef get_parse_message(self) -> strReturns a human-readable error message describing the parse failure.
Returns:
str - Formatted error message with details about the parsing problemfrom prospector.config import ProspectorConfig
from prospector.run import Prospector
from prospector.exceptions import (
FatalProspectorException,
CouldNotHandleEncoding,
PermissionMissing
)
def run_analysis_safely():
try:
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
messages = prospector.get_messages()
print(f"Analysis completed: {len(messages)} issues found")
except FatalProspectorException as e:
print(f"Fatal error: {e.message}")
return 2 # Fatal error exit code
except CouldNotHandleEncoding as e:
print(f"Encoding error in file {e.path}")
print("Try specifying file encoding or excluding the file")
return 1
except PermissionMissing as e:
print(f"Permission denied: {e}")
return 1
except Exception as e:
print(f"Unexpected error: {e}")
return 1
return 0
exit_code = run_analysis_safely()from prospector.profiles.profile import ProspectorProfile, ProfileNotFound, CannotParseProfile
from pathlib import Path
def load_profile_with_fallback(profile_name: str, search_paths: list[Path]) -> ProspectorProfile:
try:
profile = ProspectorProfile.load(profile_name, search_paths)
print(f"Loaded profile: {profile_name}")
return profile
except ProfileNotFound as e:
print(f"Profile '{e.name}' not found in any of these locations:")
for path in e.profile_path:
print(f" {path}")
# Fall back to default profile
print("Falling back to default profile")
return ProspectorProfile.load("default", search_paths)
except CannotParseProfile as e:
print(f"Failed to parse profile file: {e.filepath}")
print("Parse error details:")
print(e.get_parse_message())
# Could fall back to default or re-raise
raise
# Usage
search_paths = [Path(".prospector"), Path("/etc/prospector/profiles")]
profile = load_profile_with_fallback("myproject", search_paths)from prospector.finder import FileFinder
from prospector.exceptions import CouldNotHandleEncoding, PermissionMissing
from pathlib import Path
def process_files_safely(paths: list[Path]):
try:
finder = FileFinder(*paths)
modules = list(finder.iter_all_modules())
processed_count = 0
error_count = 0
for module_path in modules:
try:
# Simulate file processing that might fail
with open(module_path, 'r', encoding='utf-8') as f:
content = f.read()
processed_count += 1
except UnicodeDecodeError:
print(f"Encoding error in {module_path}")
error_count += 1
except PermissionError:
print(f"Permission denied: {module_path}")
error_count += 1
print(f"Processed {processed_count} files, {error_count} errors")
except FileNotFoundError as e:
print(f"Path not found: {e}")
except Exception as e:
print(f"Unexpected error during file processing: {e}")
# Usage
process_files_safely([Path("src"), Path("tests")])from prospector.config import ProspectorConfig
from prospector.run import Prospector
from prospector.exceptions import FatalProspectorException
def run_with_error_tolerance():
# Configure to continue on tool errors (default behavior)
config = ProspectorConfig()
# If you want to fail fast on any tool error, set die_on_tool_error
# This would be done via command line: --die-on-tool-error
prospector = Prospector(config)
try:
prospector.execute()
messages = prospector.get_messages()
summary = prospector.get_summary()
# Check if any tools failed
if summary and "external_config" in summary:
print(f"External config used: {summary['external_config']}")
# Look for tool failure messages
tool_failures = [msg for msg in messages if msg.code == "failure"]
if tool_failures:
print(f"Warning: {len(tool_failures)} tools failed to run")
for failure in tool_failures:
print(f" {failure.source}: {failure.message}")
return messages
except FatalProspectorException as e:
print(f"Tool error caused fatal failure: {e.message}")
raise
messages = run_with_error_tolerance()from prospector.exceptions import FatalProspectorException
import logging
class ProspectorRunner:
def __init__(self):
self.logger = logging.getLogger(__name__)
def run_analysis(self, config_overrides=None):
try:
from prospector.config import ProspectorConfig
from prospector.run import Prospector
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
return {
'success': True,
'messages': prospector.get_messages(),
'summary': prospector.get_summary()
}
except FatalProspectorException as e:
self.logger.error(f"Fatal prospector error: {e.message}")
return {
'success': False,
'error': 'fatal',
'message': e.message
}
except Exception as e:
self.logger.exception("Unexpected error during analysis")
return {
'success': False,
'error': 'unexpected',
'message': str(e)
}
def handle_result(self, result):
if result['success']:
print(f"Analysis successful: {len(result['messages'])} issues")
return 0
else:
print(f"Analysis failed ({result['error']}): {result['message']}")
return 2 if result['error'] == 'fatal' else 1
# Usage
runner = ProspectorRunner()
result = runner.run_analysis()
exit_code = runner.handle_result(result)from prospector.config import ProspectorConfig
from prospector.run import Prospector
from prospector.exceptions import FatalProspectorException
import traceback
def debug_prospector_error():
try:
config = ProspectorConfig()
prospector = Prospector(config)
prospector.execute()
except FatalProspectorException as e:
print("=== FATAL PROSPECTOR ERROR ===")
print(f"Error message: {e.message}")
print(f"Error type: {type(e).__name__}")
# Print full traceback for debugging
print("\nFull traceback:")
traceback.print_exc()
# Additional debug information
print(f"\nConfiguration summary:")
print(f" Tools to run: {config.tools_to_run}")
print(f" Paths: {config.paths}")
print(f" Working directory: {config.workdir}")
except Exception as e:
print("=== UNEXPECTED ERROR ===")
print(f"Error: {e}")
print(f"Type: {type(e).__name__}")
traceback.print_exc()
debug_prospector_error()Install with Tessl CLI
npx tessl i tessl/pypi-prospector