CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-darker

Apply Black formatting only in regions changed since last commit

Pending
Overview
Eval results
Files

git-integration.mddocs/

Git Integration

Git repository interaction, revision comparison, and modified file discovery for determining which files and regions need formatting.

Capabilities

Repository Detection

Functions for detecting and validating Git repositories.

def git_is_repository(path: Path) -> bool:
    """
    Check if the given path is inside a Git working tree.
    
    Parameters:
    - path: Path to check for Git repository
    
    Returns:
    True if path is within a Git repository, False otherwise
    """

def get_path_in_repo(path: Path) -> str:
    """
    Get relative path within repository, handling VSCode temp files.
    
    Converts absolute paths to repository-relative paths and handles
    special cases like VSCode temporary files.
    
    Parameters:
    - path: Absolute path to convert
    
    Returns:
    Repository-relative path as string
    """

Modified File Discovery

Functions for finding modified Python files using Git.

def git_get_modified_python_files(
    paths: Collection[str],
    revrange: RevisionRange,
    cwd: Path,
) -> Set[str]:
    """
    Ask Git for modified *.py files in the given revision range.
    
    Parameters:
    - paths: Collection of file/directory paths to check
    - revrange: Git revision range for comparison
    - cwd: Current working directory for Git operations
    
    Returns:
    Set of repository-relative paths to modified Python files
    """

def should_reformat_file(path: Path) -> bool:
    """
    Check if the given path is an existing *.py file that should be reformatted.
    
    Parameters:
    - path: File path to check
    
    Returns:
    True if file exists and is a Python file, False otherwise
    """

def get_missing_at_revision(paths: Set[str], revrange: RevisionRange, cwd: Path) -> Set[str]:
    """
    Return paths that are missing (don't exist) in the given revision.
    
    Parameters:
    - paths: Set of paths to check
    - revrange: Git revision range
    - cwd: Current working directory
    
    Returns:
    Set of paths that don't exist in the specified revision
    """

Line-Level Change Detection

Class for detecting changed lines between Git revisions.

class EditedLinenumsDiffer:
    """
    Find changed lines between Git revisions for selective formatting.
    
    This class compares file content between revisions to identify
    exactly which lines have been modified, enabling precise formatting
    of only the changed regions.
    """
    
    def __init__(self, root: Path, revrange: RevisionRange):
        """
        Initialize the differ with root path and revision range.
        
        Parameters:
        - root: Common root directory for relative paths
        - revrange: Git revision range for comparison
        """
    
    def revision_vs_lines(
        self, 
        path_in_repo: Path, 
        content: TextDocument,
        context_lines: int
    ) -> List[int]:
        """
        Return changed line numbers between revision and current content.
        
        Parameters:
        - path_in_repo: Repository-relative path to the file
        - content: Current content of the file
        - context_lines: Number of context lines to include around changes
        
        Returns:
        List of line numbers that have changed in the current content
        """

Usage Examples

Basic Repository Operations

from darker.git import git_is_repository, get_path_in_repo
from pathlib import Path

# Check if current directory is a Git repository
if git_is_repository(Path.cwd()):
    print("Current directory is in a Git repository")
    
    # Get repository-relative path
    abs_path = Path.cwd() / "src" / "module.py"
    repo_path = get_path_in_repo(abs_path)
    print(f"Repository path: {repo_path}")
else:
    print("Not in a Git repository")

Finding Modified Files

from darker.git import git_get_modified_python_files, should_reformat_file
from darkgraylib.git import RevisionRange
from pathlib import Path

# Set up revision range
revrange = RevisionRange.parse_with_common_ancestor("HEAD~1", ":WORKTREE:")
cwd = Path.cwd()

# Find modified Python files
modified_files = git_get_modified_python_files(
    paths=["src/", "tests/"],
    revrange=revrange,
    cwd=cwd
)

print("Modified Python files:")
for file_path in modified_files:
    full_path = cwd / file_path
    if should_reformat_file(full_path):
        print(f"  {file_path}")

Line-Level Change Detection

from darker.git import EditedLinenumsDiffer
from darkgraylib.git import RevisionRange
from darkgraylib.utils import TextDocument
from pathlib import Path

# Set up differ
revrange = RevisionRange.parse_with_common_ancestor("HEAD", ":WORKTREE:")
differ = EditedLinenumsDiffer(Path.cwd(), revrange)

# Read current file content
file_path = "src/module.py"
with open(file_path) as f:
    current_content = TextDocument.from_str(f.read())

# Find changed lines
changed_lines = differ.revision_vs_lines(
    Path(file_path), 
    current_content,
    context_lines=3
)

print(f"Changed lines in {file_path}: {changed_lines}")

# Use line information for selective formatting
if changed_lines:
    print("File has changes and needs formatting")
else:
    print("No changes detected, skipping formatting")

Integration with Main Workflow

from darker.git import EditedLinenumsDiffer, git_get_modified_python_files
from darker.chooser import choose_lines
from darkgraylib.git import RevisionRange
from darkgraylib.utils import TextDocument
from pathlib import Path

def format_only_changed_lines(file_path: str, formatter_func):
    """Example of using Git integration for selective formatting."""
    
    # Set up Git integration
    revrange = RevisionRange.parse_with_common_ancestor("HEAD", ":WORKTREE:")
    differ = EditedLinenumsDiffer(revrange, Path.cwd())
    
    # Read current content
    with open(file_path) as f:
        current_content = TextDocument.from_str(f.read())
    
    # Find changed lines
    baseline_lines, edited_lines = differ.revision_vs_lines(
        file_path,
        current_content
    )
    
    if not edited_lines:
        print(f"No changes in {file_path}, skipping")
        return current_content
    
    # Apply formatter to entire content
    formatted_content = formatter_func(current_content)
    
    # Select only changed regions from formatted version
    result = choose_lines(
        edited_lines,
        current_content,
        formatted_content
    )
    
    return result

# Usage
formatted = format_only_changed_lines(
    "src/module.py",
    lambda content: run_black_formatter(content)
)

Working with Missing Files

from darker.git import get_missing_at_revision
from darkgraylib.git import RevisionRange
from pathlib import Path

# Check for files that exist now but not in the baseline
revrange = RevisionRange.parse_with_common_ancestor("HEAD~5", ":WORKTREE:")
current_files = {"src/new_module.py", "src/existing.py", "tests/test_new.py"}

missing_in_baseline = get_missing_at_revision(
    current_files,
    revrange,
    Path.cwd()
)

print("New files (missing in baseline):")
for new_file in missing_in_baseline:
    print(f"  {new_file}")

# These files should be fully formatted since they're entirely new
existing_files = current_files - missing_in_baseline
print("Existing files (partial formatting):")
for existing_file in existing_files:
    print(f"  {existing_file}")

Custom Revision Ranges

from darker.git import git_get_modified_python_files
from darkgraylib.git import RevisionRange
from pathlib import Path

# Different revision range patterns
examples = [
    "HEAD~1",           # Compare with previous commit
    "main",             # Compare with main branch
    "origin/main...",   # Compare with remote main branch
    ":PRE-COMMIT:",     # Pre-commit hook mode
    ":STDIN:",          # Standard input mode
]

for rev_str in examples:
    try:
        revrange = RevisionRange.parse_with_common_ancestor(rev_str, ":WORKTREE:")
        modified = git_get_modified_python_files(
            paths=["src/"],
            revrange=revrange,
            cwd=Path.cwd()
        )
        print(f"{rev_str}: {len(modified)} modified files")
    except Exception as e:
        print(f"{rev_str}: Error - {e}")

Install with Tessl CLI

npx tessl i tessl/pypi-darker

docs

chooser.md

command-line.md

configuration.md

diff-utilities.md

file-utilities.md

formatters.md

git-integration.md

index.md

main-functions.md

preprocessors.md

verification.md

tile.json