Prospector is a tool to analyse Python code by aggregating the result of other tools.
—
Configuration profile system for managing tool settings, rules, and project-specific configurations. Profiles allow customization of Prospector's behavior for different projects and coding styles.
Main configuration profile class that manages tool settings and rules.
class ProspectorProfile:
passRepresents a configuration profile with tool settings, enabled/disabled rules, and other preferences.
@staticmethod
def load(name: Union[str, Path], profile_path: list[Path],
forced_inherits: Optional[list[str]] = None) -> ProspectorProfileLoads a profile from the filesystem or built-in profiles.
Parameters:
name: Union[str, Path] - Profile name or path to profile fileprofile_path: list[Path] - List of directories to search for profilesforced_inherits: Optional[list[str]] - Additional profiles to inherit fromReturns:
ProspectorProfile - Loaded and configured profileRaises:
ProfileNotFound - If the specified profile cannot be foundCannotParseProfile - If the profile file contains invalid YAMLProfile Search Order:
name is a Pathprofile_path listprospector_profile_{module_name}def is_tool_enabled(self, tool_name: str) -> Optional[bool]Checks if a specific tool is enabled in this profile.
Parameters:
tool_name: str - Name of the tool to checkReturns:
Optional[bool] - True if enabled, False if disabled, None if not specifieddef get_disabled_messages(self, tool_name: str) -> list[str]Gets list of message codes disabled for a specific tool.
Parameters:
tool_name: str - Name of the toolReturns:
list[str] - List of disabled message codesdef get_enabled_messages(self, tool_name: str) -> list[str]Gets list of message codes enabled for a specific tool.
Parameters:
tool_name: str - Name of the toolReturns:
list[str] - List of enabled message codesdef list_profiles(self) -> list[str]Lists all profiles that were loaded (including inherited profiles).
Returns:
list[str] - List of profile names in inheritance orderProfile objects have various properties for accessing configuration:
autodetect: bool - Whether to auto-detect libraries and frameworksuses: list[str] - Explicitly specified libraries/frameworks to useignore_patterns: list[str] - Regex patterns for files to ignoreignore_paths: list[str] - Specific paths to ignoreoutput_format: str - Default output formatoutput_target: list[str] - Default output target filesAUTO_LOADED_PROFILES: list[Path]List of profile filenames that Prospector automatically searches for in the working directory.
Auto-loaded Profile Files:
.landscape.yml / .landscape.yamllandscape.yml / landscape.yaml.prospector.yml / .prospector.yamlprospector.yml / prospector.yamlprospector/.prospector.yml / prospector/.prospector.yamlprospector/prospector.yml / prospector/prospector.yaml.prospector/.prospector.yml / .prospector/.prospector.yaml.prospector/prospector.yml / .prospector/prospector.yamlclass ProfileNotFound(Exception):
def __init__(self, name: str, profile_path: list[Path]) -> NoneRaised when a requested profile cannot be found.
Properties:
name: str - Name of the profile that wasn't foundprofile_path: list[Path] - Search paths that were checkedclass CannotParseProfile(Exception):
def __init__(self, filepath: Path, parse_error: Any) -> NoneRaised when a profile file contains invalid YAML or configuration.
Properties:
filepath: Path - Path to the problematic profile fileparse_error: Any - The underlying parsing errordef get_parse_message(self) -> strGets a human-readable error message describing the parse failure.
from prospector.profiles.profile import ProspectorProfile
from pathlib import Path
# Load default profile
try:
profile = ProspectorProfile.load("default", [Path("/usr/share/prospector/profiles")])
print(f"Loaded profile with {len(profile.list_profiles())} inherited profiles")
except Exception as e:
print(f"Failed to load profile: {e}")
# Load custom profile from specific location
profile_paths = [
Path(".prospector"),
Path("/etc/prospector/profiles"),
Path.home() / ".config/prospector/profiles"
]
try:
profile = ProspectorProfile.load("myproject", profile_paths)
print("Loaded custom profile")
except Exception as e:
print(f"Custom profile not found: {e}")from prospector.profiles.profile import ProspectorProfile
from pathlib import Path
profile = ProspectorProfile.load("default", [Path("/usr/share/prospector/profiles")])
# Check which tools are enabled
tools_to_check = ["pylint", "pyflakes", "mypy", "bandit"]
for tool in tools_to_check:
enabled = profile.is_tool_enabled(tool)
if enabled is True:
print(f"{tool}: enabled")
elif enabled is False:
print(f"{tool}: disabled")
else:
print(f"{tool}: not specified (use default)")
# Check disabled messages for pylint
disabled = profile.get_disabled_messages("pylint")
if disabled:
print(f"Pylint disabled messages: {disabled}")
# Check enabled messages for pydocstyle
enabled = profile.get_enabled_messages("pydocstyle")
if enabled:
print(f"Pydocstyle enabled messages: {enabled}")# Example .prospector.yaml file
strictness: medium
test-warnings: false
doc-warnings: true
autodetect: true
uses:
- django
- celery
ignore-patterns:
- '(^|/)migrations(/|$)'
- '\.pb2\.py$'
ignore-paths:
- docs
- build
- venv
output-format: grouped
pylint:
disable:
- missing-docstring
- invalid-name
options:
max-line-length: 120
pycodestyle:
disable:
- E501 # line too long
options:
max-line-length: 120
mypy:
run: true
options:
ignore-missing-imports: truefrom prospector.profiles.profile import ProspectorProfile
from pathlib import Path
# Load profile with forced inheritance
profile = ProspectorProfile.load(
"myproject",
[Path(".prospector")],
forced_inherits=["strictness_high", "django"]
)
# See what profiles were loaded
profiles = profile.list_profiles()
print(f"Profile inheritance chain: {' -> '.join(profiles)}")
# Check if specific settings come from inheritance
if profile.autodetect:
print("Auto-detection is enabled")
libraries = profile.uses
if libraries:
print(f"Configured for libraries: {libraries}")from prospector.profiles.profile import ProspectorProfile, ProfileNotFound, CannotParseProfile
from pathlib import Path
def load_profile_safely(name: str, search_paths: list[Path]) -> ProspectorProfile:
try:
return ProspectorProfile.load(name, search_paths)
except ProfileNotFound as e:
print(f"Profile '{e.name}' not found in paths: {e.profile_path}")
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(e.get_parse_message())
raise
# Usage
search_paths = [Path("."), Path("/etc/prospector")]
profile = load_profile_safely("myproject", search_paths)from prospector.profiles import AUTO_LOADED_PROFILES
from pathlib import Path
import os
def find_auto_profile(working_dir: Path) -> Optional[Path]:
"""Find automatically loaded profile in working directory"""
for profile_path in AUTO_LOADED_PROFILES:
full_path = working_dir / profile_path
if full_path.exists() and full_path.is_file():
return full_path
return None
# Check current directory
current_dir = Path.cwd()
auto_profile = find_auto_profile(current_dir)
if auto_profile:
print(f"Found auto-loaded profile: {auto_profile}")
# This profile would be automatically loaded by ProspectorConfig
else:
print("No auto-loaded profile found")
print("Checked for these files:")
for profile_path in AUTO_LOADED_PROFILES:
print(f" {profile_path}")from prospector.profiles.profile import ProspectorProfile
from prospector.config import ProspectorConfig
from pathlib import Path
def configure_for_project(project_type: str) -> ProspectorConfig:
"""Configure Prospector based on project type"""
# Determine appropriate profiles
if project_type == "django":
forced_inherits = ["django", "strictness_medium"]
elif project_type == "flask":
forced_inherits = ["flask", "strictness_medium"]
elif project_type == "library":
forced_inherits = ["strictness_high", "doc_warnings"]
else:
forced_inherits = ["strictness_medium"]
# Create config with custom profile loading
config = ProspectorConfig()
# Override profile with project-specific settings
profile_paths = [
Path(".prospector"),
Path("/etc/prospector/profiles")
]
try:
profile = ProspectorProfile.load(
"default",
profile_paths,
forced_inherits=forced_inherits
)
config.profile = profile
print(f"Configured for {project_type} project")
except Exception as e:
print(f"Failed to configure for {project_type}: {e}")
return config
# Usage
django_config = configure_for_project("django")
library_config = configure_for_project("library")from prospector.profiles.profile import ProspectorProfile
from pathlib import Path
import yaml
def validate_profile_file(profile_path: Path) -> bool:
"""Validate a profile file before loading"""
try:
# Check if file exists and is readable
if not profile_path.exists():
print(f"Profile file does not exist: {profile_path}")
return False
# Try to parse as YAML
with open(profile_path, 'r') as f:
yaml.safe_load(f)
# Try to load as Prospector profile
ProspectorProfile.load(str(profile_path), [profile_path.parent])
print(f"Profile file is valid: {profile_path}")
return True
except yaml.YAMLError as e:
print(f"YAML syntax error in {profile_path}: {e}")
return False
except Exception as e:
print(f"Profile validation failed for {profile_path}: {e}")
return False
# Validate profile files
profile_files = [
Path(".prospector.yaml"),
Path("profiles/myproject.yaml"),
Path("profiles/strict.yaml")
]
for profile_file in profile_files:
validate_profile_file(profile_file)Install with Tessl CLI
npx tessl i tessl/pypi-prospector