Prospector is a tool to analyse Python code by aggregating the result of other tools.
—
File and module discovery system that identifies Python code to be analyzed. The FileFinder class handles discovery of Python files, modules, and packages while respecting exclusion filters.
Discovers files and modules to be analyzed by static analysis tools.
class FileFinder:
def __init__(self, *provided_paths: Path,
exclusion_filters: Optional[Iterable[Callable[[Path], bool]]] = None) -> NoneCreates a new FileFinder for discovering Python code.
Parameters:
*provided_paths: Path - One or more paths to search (files or directories)exclusion_filters: Optional[Iterable[Callable[[Path], bool]]] - List of filter functions that return True for paths to excludeBuilt-in Exclusions: The FileFinder automatically excludes:
.git, .tox, .mypy_cache, .pytest_cache, .venv, __pycache__, node_modules@property
def files(self) -> set[Path]Lists every individual file found from the provided paths.
Returns:
set[Path] - Set of Path objects for all discovered filesThis property recursively discovers all files in the provided directories, applying exclusion filters.
@property
def python_modules(self) -> list[Path]Lists every Python module file found in the provided paths.
Returns:
list[Path] - List of Path objects for Python module files (.py files)Returns individual Python files that pass the is_python_module test.
@property
def python_packages(self) -> list[Path]Lists every directory that is a Python package (contains __init__.py).
Returns:
list[Path] - List of Path objects for package directories@property
def directories(self) -> set[Path]Lists every directory found from the provided paths.
Returns:
set[Path] - Set of Path objects for all discovered directoriesdef is_excluded(self, path: Path) -> boolChecks if a path would be excluded by the configured filters.
Parameters:
path: Path - The path to checkReturns:
bool - True if the path should be excludeddef make_syspath(self) -> list[Path]Creates a list of paths suitable for adding to Python's sys.path.
Returns:
list[Path] - List of directory paths that should be added to sys.path for proper module resolutionThis method analyzes the provided paths and determines the appropriate parent directories that should be in sys.path to ensure proper module imports during analysis.
from pathlib import Path
from prospector.finder import FileFinder
# Discover files in current directory
finder = FileFinder(Path("."))
# Get all Python modules
modules = finder.python_modules
print(f"Found {len(modules)} Python modules:")
for module in modules:
print(f" {module}")
# Get all packages
packages = finder.python_packages
print(f"Found {len(packages)} packages:")
for package in packages:
print(f" {package}")from pathlib import Path
from prospector.finder import FileFinder
# Analyze multiple paths
paths = [Path("src"), Path("tests"), Path("scripts")]
finder = FileFinder(*paths)
# Iterate over all modules
for module_path in finder.python_modules:
print(f"Module: {module_path}")
# Get syspath entries
syspath_entries = finder.make_syspath()
print(f"Sys.path entries needed: {syspath_entries}")from pathlib import Path
from prospector.finder import FileFinder
import re
# Create custom exclusion filters
def exclude_test_files(path: Path) -> bool:
"""Exclude test files"""
return path.name.startswith("test_") or path.name.endswith("_test.py")
def exclude_migration_files(path: Path) -> bool:
"""Exclude Django migration files"""
return "migrations" in path.parts and path.suffix == ".py"
# Create finder with custom filters
finder = FileFinder(
Path("src"),
exclusion_filters=[exclude_test_files, exclude_migration_files]
)
# Only non-test, non-migration files will be found
modules = finder.python_modules
print(f"Found {len(modules)} modules (excluding tests and migrations)")from pathlib import Path
from prospector.finder import FileFinder
from prospector.config import ProspectorConfig
# Use with ProspectorConfig exclusion filter
config = ProspectorConfig()
paths = [Path(".")]
# Create finder with config's exclusion filters
finder = FileFinder(*paths, exclusion_filters=[config.make_exclusion_filter()])
# Get modules that pass all filters
modules = finder.python_modules
# Check what would be included vs excluded
print("Included modules:")
for module in finder.python_modules:
print(f" {module}")
print("\nAll files (use files property for complete file list):")
for file_path in finder.files:
print(f" {file_path}")from pathlib import Path
from prospector.finder import FileFinder
# Analyze specific files
specific_files = [
Path("src/main.py"),
Path("src/utils.py"),
Path("tests/test_main.py")
]
finder = FileFinder(*specific_files)
# When providing specific files, they are all considered modules
modules = finder.python_modules
print(f"Analyzing {len(modules)} specific files:")
for module in modules:
print(f" {module}")
# Syspath still works with specific files
syspath = finder.make_syspath()
print(f"Syspath entries: {syspath}")from pathlib import Path
from prospector.finder import FileFinder
try:
# This will raise FileNotFoundError if path doesn't exist
finder = FileFinder(Path("nonexistent/path"))
except FileNotFoundError as e:
print(f"Path not found: {e}")
# Safer approach - check existence first
paths_to_check = [Path("src"), Path("lib"), Path("scripts")]
valid_paths = [p for p in paths_to_check if p.exists()]
if valid_paths:
finder = FileFinder(*valid_paths)
modules = finder.python_modules
print(f"Found {len(modules)} modules in {len(valid_paths)} valid paths")
else:
print("No valid paths found")from pathlib import Path
from prospector.finder import FileFinder
from prospector.config import ProspectorConfig
# This is how FileFinder is typically used within Prospector
config = ProspectorConfig()
# Create finder with config's paths and exclusion filters
paths = [Path(p) for p in config.paths]
finder = FileFinder(*paths, exclusion_filters=[config.make_exclusion_filter()])
# Tools use the finder to discover files to analyze
tools = config.get_tools(finder)
# Each tool gets the same FileFinder instance
for tool in tools:
print(f"Running {tool.__class__.__name__}")
messages = tool.run(finder)
print(f" Found {len(messages)} issues")
# Tools can access different file views:
print(f"Python modules: {len(finder.python_modules)}")
print(f"Python packages: {len(finder.python_packages)}")
print(f"All files: {len(finder.files)}")
print(f"Directories: {len(finder.directories)}")Install with Tessl CLI
npx tessl i tessl/pypi-prospector