CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-prospector

Prospector is a tool to analyse Python code by aggregating the result of other tools.

Pending
Overview
Eval results
Files

file-finding.mddocs/

File Finding

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.

Capabilities

FileFinder Class

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) -> None

Creates 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 exclude

Built-in Exclusions: The FileFinder automatically excludes:

  • Directories: .git, .tox, .mypy_cache, .pytest_cache, .venv, __pycache__, node_modules
  • Virtual environments (detected using heuristics)

File Discovery Properties and Methods

@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 files

This 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 directories
def is_excluded(self, path: Path) -> bool

Checks if a path would be excluded by the configured filters.

Parameters:

  • path: Path - The path to check

Returns:

  • bool - True if the path should be excluded

Python Path Management

def 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 resolution

This method analyzes the provided paths and determines the appropriate parent directories that should be in sys.path to ensure proper module imports during analysis.

Usage Examples

Basic File Discovery

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}")

Multiple Path Discovery

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}")

Custom Exclusion Filters

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)")

Working with Configuration

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}")

Specific File Analysis

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}")

Error Handling

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")

Integration with Tools

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

docs

analysis-runner.md

configuration.md

exceptions.md

file-finding.md

formatters.md

index.md

messages.md

profiles.md

tools.md

tile.json