Utility library for gitignore style pattern matching of file paths.
—
Core pattern matching functionality for testing files against gitignore-style patterns. This module provides the main interfaces for pattern matching operations, supporting both simple boolean tests and detailed result analysis.
from pathspec import PathSpec, GitIgnoreSpec
from pathspec.util import CheckResult, TreeEntry
from typing import AnyStr, Callable, Collection, Iterable, Iterator, Optional, Tuple, Union
import osThe main class for pattern matching operations. Wraps a list of compiled Pattern instances and provides methods for matching files and directory trees.
class PathSpec:
def __init__(self, patterns: Iterable[Pattern]) -> None:
"""
Initialize PathSpec with compiled patterns.
Parameters:
- patterns: Iterable of compiled Pattern instances
"""
def __len__(self) -> int:
"""Returns the number of compiled patterns."""
def __eq__(self, other: object) -> bool:
"""Tests equality by comparing patterns."""
def __add__(self, other: "PathSpec") -> PathSpec:
"""Combines patterns from two PathSpec instances."""
def __iadd__(self, other: "PathSpec") -> PathSpec:
"""Adds patterns from another PathSpec to this instance."""
@classmethod
def from_lines(
cls,
pattern_factory: Union[str, Callable[[AnyStr], Pattern]],
lines: Iterable[AnyStr]
) -> PathSpec:
"""
Create PathSpec from lines of text patterns.
Parameters:
- pattern_factory: Pattern factory name or callable
- lines: Iterable of pattern strings
Returns:
PathSpec instance with compiled patterns
"""Methods for testing individual files and collections of files against patterns.
def match_file(
self,
file: Union[str, os.PathLike],
separators: Optional[Collection[str]] = None
) -> bool:
"""
Test if a single file matches any pattern.
Parameters:
- file: File path to test
- separators: Path separators to normalize (defaults to os.sep)
Returns:
True if file matches any include pattern and no exclude patterns
"""
def match_files(
self,
files: Iterable[Union[str, os.PathLike]],
separators: Optional[Collection[str]] = None,
*,
negate: Optional[bool] = None
) -> Iterator[Union[str, os.PathLike]]:
"""
Match multiple files against patterns.
Parameters:
- files: Iterable of file paths to test
- separators: Path separators to normalize
- negate: If True, return non-matching files instead
Yields:
File paths that match the patterns
"""
def check_file(
self,
file: Union[str, os.PathLike],
separators: Optional[Collection[str]] = None
) -> CheckResult[Union[str, os.PathLike]]:
"""
Check a single file with detailed result information.
Parameters:
- file: File path to test
- separators: Path separators to normalize
Returns:
CheckResult with file path, match status, and pattern index
"""
def check_files(
self,
files: Iterable[Union[str, os.PathLike]],
separators: Optional[Collection[str]] = None
) -> Iterator[CheckResult[Union[str, os.PathLike]]]:
"""
Check multiple files with detailed results.
Parameters:
- files: Iterable of file paths to test
- separators: Path separators to normalize
Yields:
CheckResult for each file
"""Methods for traversing directory trees and matching files within them.
def match_tree_files(
self,
root: Union[str, os.PathLike],
on_error: Optional[Callable[[OSError], None]] = None,
follow_links: Optional[bool] = None,
*,
negate: Optional[bool] = None
) -> Iterator[str]:
"""
Walk directory tree and match files against patterns.
Parameters:
- root: Root directory path to traverse
- on_error: Optional error handler for OS errors during traversal
- follow_links: Whether to follow symbolic links (defaults to False)
- negate: If True, return non-matching files instead
Yields:
File paths that match the patterns
"""
def match_tree_entries(
self,
root: Union[str, os.PathLike],
on_error: Optional[Callable[[OSError], None]] = None,
follow_links: Optional[bool] = None,
*,
negate: Optional[bool] = None
) -> Iterator[TreeEntry]:
"""
Walk directory tree and match TreeEntry objects.
Parameters:
- root: Root directory path to traverse
- on_error: Optional error handler for OS errors
- follow_links: Whether to follow symbolic links
- negate: If True, return non-matching entries instead
Yields:
TreeEntry objects for matching file system entries
"""
def check_tree_files(
self,
root: Union[str, os.PathLike],
on_error: Optional[Callable[[OSError], None]] = None,
follow_links: Optional[bool] = None
) -> Iterator[CheckResult[str]]:
"""
Walk directory tree and check files with detailed results.
Parameters:
- root: Root directory path to traverse
- on_error: Optional error handler for OS errors
- follow_links: Whether to follow symbolic links
Yields:
CheckResult for each file in the tree
"""
def match_entries(
self,
entries: Iterable[TreeEntry],
separators: Optional[Collection[str]] = None,
*,
negate: Optional[bool] = None
) -> Iterator[TreeEntry]:
"""
Match TreeEntry objects against patterns.
Parameters:
- entries: Iterable of TreeEntry objects to test
- separators: Path separators to normalize
- negate: If True, return non-matching entries instead
Yields:
TreeEntry objects that match the patterns
"""
def match_tree(
self,
root: str,
on_error: Optional[Callable[[OSError], None]] = None,
follow_links: Optional[bool] = None,
*,
negate: Optional[bool] = None
) -> Iterator[str]:
"""
DEPRECATED: Alias for match_tree_files.
Walk directory tree and match files against patterns.
Parameters:
- root: Root directory path to traverse
- on_error: Optional error handler for OS errors
- follow_links: Whether to follow symbolic links
- negate: If True, return non-matching files instead
Yields:
File paths that match the patterns
"""Specialized PathSpec implementation that closely replicates .gitignore behavior with Git-specific edge case handling.
class GitIgnoreSpec(PathSpec):
def __eq__(self, other: object) -> bool:
"""
Test equality. Only compares equal to other GitIgnoreSpec instances.
"""
@classmethod
def from_lines(
cls,
lines: Iterable[AnyStr],
pattern_factory: Optional[Union[str, Callable[[AnyStr], Pattern]]] = None
) -> GitIgnoreSpec:
"""
Create GitIgnoreSpec from pattern lines. Supports reversed parameter order for compatibility.
Parameters:
- lines: Iterable of gitignore-style pattern strings (or pattern_factory if using reversed order)
- pattern_factory: Optional pattern factory (defaults to GitWildMatchPattern, or lines if using reversed order)
Returns:
GitIgnoreSpec instance with compiled patterns
Note: This method supports both parameter orders:
- from_lines(lines, pattern_factory) - standard order
- from_lines(pattern_factory, lines) - reversed order for PathSpec compatibility
"""
@staticmethod
def _match_file(
patterns: Iterable[Tuple[int, GitWildMatchPattern]],
file: str
) -> Tuple[Optional[bool], Optional[int]]:
"""
Internal method for gitignore-specific matching logic.
Parameters:
- patterns: Indexed patterns to test against
- file: File path to test
Returns:
Tuple of (match_result, pattern_index)
"""import pathspec
# Create PathSpec from patterns
patterns = ["*.py", "!test_*.py", "src/"]
spec = pathspec.PathSpec.from_lines('gitwildmatch', patterns)
# Test individual files
print(spec.match_file("main.py")) # True
print(spec.match_file("test_main.py")) # False
print(spec.match_file("src/utils.py")) # True
# Get matching files from a list
files = ["main.py", "test_main.py", "src/utils.py", "README.md"]
matches = list(spec.match_files(files))
print(matches) # ["main.py", "src/utils.py"]import pathspec
# Create spec for Python project files
spec = pathspec.PathSpec.from_lines('gitwildmatch', [
"*.py",
"*.md",
"!__pycache__/",
"!*.pyc",
"!.git/"
])
# Get all matching files in project directory
project_files = list(spec.match_tree_files("/path/to/project"))
# Handle errors during traversal
def handle_error(error):
print(f"Warning: {error}")
safe_files = list(spec.match_tree_files(
"/path/to/project",
on_error=handle_error
))import pathspec
spec = pathspec.PathSpec.from_lines('gitwildmatch', [
"*.py", # Pattern 0
"!test_*.py" # Pattern 1
])
# Get detailed information about matches
result = spec.check_file("main.py")
print(f"File: {result.file}")
print(f"Included: {result.include}")
print(f"Matched by pattern: {result.index}")
# Check multiple files with details
files = ["main.py", "test_main.py", "utils.py"]
for result in spec.check_files(files):
status = "included" if result.include else "excluded"
print(f"{result.file}: {status} (pattern {result.index})")import pathspec
# GitIgnoreSpec handles gitignore edge cases
gitignore_content = """
# Comments are ignored
*.log
temp/
!important.log
# Negation patterns work correctly
build/
!build/assets/
"""
spec = pathspec.GitIgnoreSpec.from_lines(gitignore_content.splitlines())
# Use exactly like PathSpec
matches = list(spec.match_tree_files("/project"))import pathspec
# Create separate specs for different pattern sets
code_spec = pathspec.PathSpec.from_lines('gitwildmatch', [
"*.py", "*.js", "*.ts"
])
doc_spec = pathspec.PathSpec.from_lines('gitwildmatch', [
"*.md", "*.rst", "*.txt"
])
# Combine them
combined_spec = code_spec + doc_spec
# Or add in place
code_spec += doc_specInstall with Tessl CLI
npx tessl i tessl/pypi-pathspec