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

git-operations.mddocs/

Git Operations

Comprehensive git integration for working with staged files, status checking, and repository operations within hooks. This API provides all necessary functionality for plugins to interact with git repositories and manage file staging.

Capabilities

Git Status Operations

Retrieve and analyze git status information for files in the repository with support for filtering and status type checking.

def get_status(files: Optional[Iterable[PathLike]] = None) -> List[StatusEntry]:
    """
    Get information about the current git status.
    
    Args:
        files: (optional) specify an iterable of PathLike and exclude all other paths
        
    Returns:
        A list of StatusEntry instances that contain the status of the specific files
    """

def get_staged_status(files: Optional[Iterable[PathLike]] = None) -> List[StatusEntry]:
    """
    Get a list of StatusEntry instances containing only staged files.
    
    Args:
        files: (optional) specify an iterable of files and exclude all other paths
        
    Returns:
        A list of StatusEntry instances with files that are staged
    """

def is_staged_status(status: StatusEntry) -> bool:
    """
    Returns true, if the status of the given StatusEntry is staged.
    
    Args:
        status: A StatusEntry object that contains the filename, path and git status
        
    Returns:
        True if file is staged, False else
    """

def is_partially_staged_status(status: StatusEntry) -> bool:
    """
    Returns true, if the status of the given StatusEntry is partially staged.
    
    Args:
        status: A StatusEntry object that contains the filename, path and git status
        
    Returns:
        True if file is partially staged, False else
    """

Usage Examples:

from autohooks.api.git import get_status, get_staged_status, is_staged_status

def precommit(config, report_progress, **kwargs):
    # Get all file status
    all_status = get_status()
    
    # Get only staged files
    staged_files = get_staged_status()
    
    # Filter for specific file types
    python_files = []
    for status_entry in staged_files:
        if status_entry.path.suffix == '.py':
            python_files.append(status_entry)
    
    # Check if specific files are staged
    for status_entry in all_status:
        if is_staged_status(status_entry):
            print(f"Staged: {status_entry.path}")

File Staging Operations

Add files to the git staging index with support for different input types and batch operations.

def stage_files(files: Iterable[PathLike]) -> None:
    """
    Add the passed PathLike to git staging index.
    
    Args:
        files: An iterable of PathLike to add to the index
    """

def stage_files_from_status_list(status_list: Iterable[StatusEntry]) -> None:
    """
    Add the passed files from the status list to git staging index.
    
    Deprecated. Please use stage_files instead.
    
    Args:
        status_list: A List of StatusEntry instances that should be added
    """

Usage Examples:

from autohooks.api.git import get_staged_status, stage_files
from pathlib import Path

def precommit(config, report_progress, **kwargs):
    # Get staged files
    staged_files = get_staged_status()
    
    # Process and potentially modify files
    modified_files = []
    for status_entry in staged_files:
        if process_file(status_entry.absolute_path()):
            modified_files.append(status_entry.path)
    
    # Re-stage modified files
    if modified_files:
        stage_files(modified_files)

Git Command Execution

Execute git commands directly with error handling and output capture.

def exec_git(*args: str, ignore_errors: bool = False) -> str:
    """
    Execute git command.
    
    Args:
        *args: Variable length argument list passed to git
        ignore_errors: Ignore errors if git command fails. Default: False
        
    Returns:
        Command output as string
        
    Raises:
        GitError: A GitError is raised if the git commit fails and ignore_errors is False
    """

def get_diff(files: Optional[Iterable[StatusEntry]] = None) -> str:
    """
    Get the diff of the passed files.
    
    Args:
        files: A List of StatusEntry instances that should be diffed
        
    Returns:
        String containing the diff of the given files
    """

class GitError(subprocess.CalledProcessError):
    """
    Error raised if a git command fails.
    """

Usage Examples:

from autohooks.api.git import exec_git, get_diff, GitError

def precommit(config, report_progress, **kwargs):
    try:
        # Get current branch
        branch = exec_git("rev-parse", "--abbrev-ref", "HEAD").strip()
        
        # Get diff for staged files
        diff_output = get_diff()
        
        if "TODO" in diff_output:
            warning("Found TODO comments in staged changes")
            
    except GitError as e:
        error(f"Git command failed: {e}")
        return 1

Unstaged Changes Management

Context manager for temporarily stashing unstaged changes during plugin execution to avoid conflicts.

class stash_unstaged_changes:
    """
    A context manager that stashes changes that:
    - are not staged, and  
    - affect files that are partially staged.
    
    Changes that are made before the context manager exits, are added to the index.
    The stashed changes are restored when the context manager exits.
    """
    
    def __init__(self, files: Optional[Iterable[PathLike]] = None) -> None:
        """
        Args:
            files: Optional iterable of path like objects to consider for being staged.
                  By default all files in the git status are considered.
        """

Usage Examples:

from autohooks.api.git import stash_unstaged_changes, get_staged_status

def precommit(config, report_progress, **kwargs):
    staged_files = get_staged_status()
    
    # Stash unstaged changes while processing
    with stash_unstaged_changes():
        # Format staged files - unstaged changes are temporarily stashed
        for status_entry in staged_files:
            format_file(status_entry.absolute_path())
        
        # Stage the formatted changes
        stage_files([entry.path for entry in staged_files])
    
    # Unstaged changes are restored here
    return 0

Status Entry Information

Detailed information about file status in git with path resolution and status checking.

class StatusEntry:
    """
    Status of a file in the git index and working tree.
    Implements the os.PathLike protocol.
    
    Attributes:
        index: Status in the index
        working_tree: Status in the working tree  
        path: Path to the file
        root_path: An optional path to a root directory
        old_path: Set for renamed files
    """
    
    def __init__(self, status_string: str, root_path: Optional[Path] = None) -> None:
        """
        Create StatusEntry from git status string.
        
        Args:
            status_string: Git status format string
            root_path: Optional root path for resolution
        """
    
    def absolute_path(self) -> Path:
        """
        Returns the absolute path of the file of this StatusEntry.
        """
    
    def __str__(self) -> str:
        """String representation showing status and path."""
    
    def __fspath__(self):
        """PathLike protocol implementation."""

class Status(Enum):
    """
    Status of a file in git.
    """
    UNMODIFIED = " "
    MODIFIED = "M"  
    ADDED = "A"
    DELETED = "D"
    RENAMED = "R"
    COPIED = "C"
    UPDATED = "U"
    UNTRACKED = "?"
    IGNORED = "!"

Usage Examples:

from autohooks.api.git import get_staged_status, Status

def precommit(config, report_progress, **kwargs):
    staged_files = get_staged_status()
    
    for status_entry in staged_files:
        print(f"File: {status_entry.path}")
        print(f"Absolute path: {status_entry.absolute_path()}")
        print(f"Index status: {status_entry.index}")
        print(f"Working tree status: {status_entry.working_tree}")
        
        # Check for specific status
        if status_entry.index == Status.MODIFIED:
            print("File is modified in index")
        elif status_entry.index == Status.ADDED:
            print("File is newly added")
        
        # Handle renamed files
        if hasattr(status_entry, 'old_path'):
            print(f"Renamed from: {status_entry.old_path}")

Types

from pathlib import Path
from typing import Iterable, List, Optional
from os import PathLike
from enum import Enum
import subprocess

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