CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-autohooks

Library for managing git hooks using pyproject.toml configuration with an extensible plugin system

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

path-utilities.mddocs/

Path Utilities

Path matching and validation utilities for file processing in plugins. This API provides convenient functions for filtering and validating file paths based on patterns and file types.

Capabilities

Python Path Validation

Check if paths represent Python source files with proper extension matching.

def is_python_path(path: Optional[Path]) -> bool:
    """
    Function to check if path is a Python file.
    
    Args:
        path: A path to a file
        
    Returns:
        True if path is a Python file (ends with .py), False otherwise
    """

Usage Examples:

from autohooks.api.path import is_python_path
from autohooks.api.git import get_staged_status
from pathlib import Path

def precommit(config, report_progress, **kwargs):
    # Get staged files
    staged_files = get_staged_status()
    
    # Filter for Python files using utility
    python_files = []
    for status_entry in staged_files:
        if is_python_path(status_entry.path):
            python_files.append(status_entry)
    
    # Process Python files
    for status_entry in python_files:
        process_python_file(status_entry.absolute_path())
    
    return 0

# Direct path checking
test_paths = [
    Path("script.py"),      # True
    Path("module.py"),      # True  
    Path("README.md"),      # False
    Path("config.toml"),    # False
    None                    # False
]

for path in test_paths:
    result = is_python_path(path)
    print(f"{path}: {result}")

Pattern Matching

Match file paths against multiple patterns using fnmatch-style glob patterns with support for complex filtering rules.

def match(path: PathLike, pattern_list: Iterable[str]) -> bool:
    """
    Check if a path like object matches to one of the patterns.
    
    Internally fnmatch is used.
    See https://docs.python.org/3/library/fnmatch.html for details.
    
    Args:
        path: PathLike to check if it matches to one of the patterns
        pattern_list: Iterable (e.g tuple or list) of patterns to match against the path
        
    Returns:
        True if path matches a pattern of the list, False otherwise
    """

Usage Examples:

from autohooks.api.path import match
from autohooks.api.git import get_staged_status
from pathlib import Path

def precommit(config, report_progress, **kwargs):
    # Get staged files
    staged_files = get_staged_status()
    
    # Define patterns for different file types
    python_patterns = ["*.py", "*.pyi"]
    config_patterns = ["*.toml", "*.yaml", "*.yml", "*.json"]
    documentation_patterns = ["*.md", "*.rst", "*.txt"]
    
    python_files = []
    config_files = []
    doc_files = []
    
    for status_entry in staged_files:
        path = status_entry.path
        
        if match(path, python_patterns):
            python_files.append(status_entry)
        elif match(path, config_patterns):
            config_files.append(status_entry)
        elif match(path, documentation_patterns):
            doc_files.append(status_entry)
    
    # Process different file types
    if python_files:
        info(f"Processing {len(python_files)} Python files")
        
    if config_files:
        info(f"Processing {len(config_files)} config files")
    
    return 0

# Pattern matching examples
test_files = [
    "src/main.py",
    "tests/test_module.py", 
    "docs/README.md",
    "pyproject.toml",
    "requirements.txt"
]

# Match Python files
python_patterns = ["*.py", "**/*.py"]
for filepath in test_files:
    if match(Path(filepath), python_patterns):
        print(f"Python file: {filepath}")

# Match configuration files
config_patterns = ["*.toml", "*.yaml", "*.yml", "*.json", "*.ini"]
for filepath in test_files:
    if match(Path(filepath), config_patterns):
        print(f"Config file: {filepath}")

# Match by directory patterns
test_patterns = ["tests/**", "test_*"]
for filepath in test_files:
    if match(Path(filepath), test_patterns):
        print(f"Test file: {filepath}")

Advanced Pattern Usage

Complex pattern matching scenarios for sophisticated file filtering.

Usage Examples:

from autohooks.api.path import match, is_python_path
from autohooks.api.git import get_staged_status

def precommit(config, report_progress, **kwargs):
    staged_files = get_staged_status()
    
    # Plugin configuration patterns
    plugin_config = config.get("tool", "my-plugin")
    include_patterns = plugin_config.get_value("include", ["*.py"])
    exclude_patterns = plugin_config.get_value("exclude", [])
    
    # Filter files based on patterns
    target_files = []
    for status_entry in staged_files:
        path = status_entry.path
        
        # Check include patterns
        if match(path, include_patterns):
            # Check exclude patterns
            if exclude_patterns and match(path, exclude_patterns):
                continue  # Skip excluded files
            target_files.append(status_entry)
    
    # Advanced filtering combining utilities
    python_files = [
        entry for entry in target_files 
        if is_python_path(entry.path)
    ]
    
    # Pattern-based exclusions
    test_patterns = ["test_*.py", "*_test.py", "tests/**/*.py"]
    non_test_files = [
        entry for entry in python_files
        if not match(entry.path, test_patterns)
    ]
    
    return 0

# Complex pattern examples
complex_patterns = [
    "src/**/*.py",          # Python files in src directory tree
    "!src/**/test_*.py",    # Exclude test files (Note: fnmatch doesn't support !)
    "*.{py,pyi}",          # Python implementation and interface files  
    "[Mm]akefile*",        # Makefiles with different cases
    "config.{yml,yaml,json}" # Multiple config file extensions
]

# Note: For exclusion patterns, you need to handle them separately
include_patterns = ["src/**/*.py", "*.py"]
exclude_patterns = ["test_*.py", "*_test.py", "tests/**"]

def should_process_file(path: Path) -> bool:
    """Check if file should be processed based on include/exclude patterns."""
    # Must match include patterns
    if not match(path, include_patterns):
        return False
    
    # Must not match exclude patterns  
    if match(path, exclude_patterns):
        return False
        
    return True

Integration with Git Operations

Combining path utilities with git operations for comprehensive file filtering.

Usage Examples:

from autohooks.api.path import is_python_path, match
from autohooks.api.git import get_staged_status, is_staged_status

def precommit(config, report_progress, **kwargs):
    # Get all status entries
    all_status = get_staged_status()
    
    # Multi-stage filtering
    processable_files = []
    
    for status_entry in all_status:
        # Only staged files
        if not is_staged_status(status_entry):
            continue
            
        # Only Python files
        if not is_python_path(status_entry.path):
            continue
            
        # Apply custom patterns
        source_patterns = ["src/**/*.py", "lib/**/*.py"]
        if not match(status_entry.path, source_patterns):
            continue
            
        # Exclude patterns
        exclude_patterns = ["**/migrations/*.py", "**/__pycache__/**"]
        if match(status_entry.path, exclude_patterns):
            continue
            
        processable_files.append(status_entry)
    
    if not processable_files:
        info("No Python source files to process")
        return 0
    
    report_progress.init(len(processable_files))
    
    for status_entry in processable_files:
        process_python_file(status_entry.absolute_path())
        report_progress.update()
    
    return 0

Pattern Syntax

The match function uses Python's fnmatch module, which supports Unix shell-style wildcards:

  • * - matches everything
  • ? - matches any single character
  • [seq] - matches any character in seq
  • [!seq] - matches any character not in seq
  • ** - matches directories recursively (when using pathlib)

Pattern Examples:

patterns = [
    "*.py",              # All Python files
    "test_*.py",         # Test files starting with test_
    "*_test.py",         # Test files ending with _test
    "src/**/*.py",       # Python files in src directory tree
    "*.{py,pyi}",        # Multiple extensions (not standard fnmatch)
    "[Tt]est*.py",       # Files starting with Test or test
    "config.?ml",        # config.yml, config.xml, etc.
]

Types

from pathlib import Path
from typing import Iterable, Optional
from os import PathLike

Install with Tessl CLI

npx tessl i tessl/pypi-autohooks

docs

cli.md

configuration.md

git-operations.md

hook-management.md

index.md

path-utilities.md

plugin-api.md

tile.json