0
# Path Matching
1
2
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.
3
4
## Imports
5
6
```python
7
from pathspec import PathSpec, GitIgnoreSpec
8
from pathspec.util import CheckResult, TreeEntry
9
from typing import AnyStr, Callable, Collection, Iterable, Iterator, Optional, Tuple, Union
10
import os
11
```
12
13
## Capabilities
14
15
### PathSpec Class
16
17
The main class for pattern matching operations. Wraps a list of compiled Pattern instances and provides methods for matching files and directory trees.
18
19
```python { .api }
20
class PathSpec:
21
def __init__(self, patterns: Iterable[Pattern]) -> None:
22
"""
23
Initialize PathSpec with compiled patterns.
24
25
Parameters:
26
- patterns: Iterable of compiled Pattern instances
27
"""
28
29
def __len__(self) -> int:
30
"""Returns the number of compiled patterns."""
31
32
def __eq__(self, other: object) -> bool:
33
"""Tests equality by comparing patterns."""
34
35
def __add__(self, other: "PathSpec") -> PathSpec:
36
"""Combines patterns from two PathSpec instances."""
37
38
def __iadd__(self, other: "PathSpec") -> PathSpec:
39
"""Adds patterns from another PathSpec to this instance."""
40
41
@classmethod
42
def from_lines(
43
cls,
44
pattern_factory: Union[str, Callable[[AnyStr], Pattern]],
45
lines: Iterable[AnyStr]
46
) -> PathSpec:
47
"""
48
Create PathSpec from lines of text patterns.
49
50
Parameters:
51
- pattern_factory: Pattern factory name or callable
52
- lines: Iterable of pattern strings
53
54
Returns:
55
PathSpec instance with compiled patterns
56
"""
57
```
58
59
### File Matching Methods
60
61
Methods for testing individual files and collections of files against patterns.
62
63
```python { .api }
64
def match_file(
65
self,
66
file: Union[str, os.PathLike],
67
separators: Optional[Collection[str]] = None
68
) -> bool:
69
"""
70
Test if a single file matches any pattern.
71
72
Parameters:
73
- file: File path to test
74
- separators: Path separators to normalize (defaults to os.sep)
75
76
Returns:
77
True if file matches any include pattern and no exclude patterns
78
"""
79
80
def match_files(
81
self,
82
files: Iterable[Union[str, os.PathLike]],
83
separators: Optional[Collection[str]] = None,
84
*,
85
negate: Optional[bool] = None
86
) -> Iterator[Union[str, os.PathLike]]:
87
"""
88
Match multiple files against patterns.
89
90
Parameters:
91
- files: Iterable of file paths to test
92
- separators: Path separators to normalize
93
- negate: If True, return non-matching files instead
94
95
Yields:
96
File paths that match the patterns
97
"""
98
99
def check_file(
100
self,
101
file: Union[str, os.PathLike],
102
separators: Optional[Collection[str]] = None
103
) -> CheckResult[Union[str, os.PathLike]]:
104
"""
105
Check a single file with detailed result information.
106
107
Parameters:
108
- file: File path to test
109
- separators: Path separators to normalize
110
111
Returns:
112
CheckResult with file path, match status, and pattern index
113
"""
114
115
def check_files(
116
self,
117
files: Iterable[Union[str, os.PathLike]],
118
separators: Optional[Collection[str]] = None
119
) -> Iterator[CheckResult[Union[str, os.PathLike]]]:
120
"""
121
Check multiple files with detailed results.
122
123
Parameters:
124
- files: Iterable of file paths to test
125
- separators: Path separators to normalize
126
127
Yields:
128
CheckResult for each file
129
"""
130
```
131
132
### Directory Tree Methods
133
134
Methods for traversing directory trees and matching files within them.
135
136
```python { .api }
137
def match_tree_files(
138
self,
139
root: Union[str, os.PathLike],
140
on_error: Optional[Callable[[OSError], None]] = None,
141
follow_links: Optional[bool] = None,
142
*,
143
negate: Optional[bool] = None
144
) -> Iterator[str]:
145
"""
146
Walk directory tree and match files against patterns.
147
148
Parameters:
149
- root: Root directory path to traverse
150
- on_error: Optional error handler for OS errors during traversal
151
- follow_links: Whether to follow symbolic links (defaults to False)
152
- negate: If True, return non-matching files instead
153
154
Yields:
155
File paths that match the patterns
156
"""
157
158
def match_tree_entries(
159
self,
160
root: Union[str, os.PathLike],
161
on_error: Optional[Callable[[OSError], None]] = None,
162
follow_links: Optional[bool] = None,
163
*,
164
negate: Optional[bool] = None
165
) -> Iterator[TreeEntry]:
166
"""
167
Walk directory tree and match TreeEntry objects.
168
169
Parameters:
170
- root: Root directory path to traverse
171
- on_error: Optional error handler for OS errors
172
- follow_links: Whether to follow symbolic links
173
- negate: If True, return non-matching entries instead
174
175
Yields:
176
TreeEntry objects for matching file system entries
177
"""
178
179
def check_tree_files(
180
self,
181
root: Union[str, os.PathLike],
182
on_error: Optional[Callable[[OSError], None]] = None,
183
follow_links: Optional[bool] = None
184
) -> Iterator[CheckResult[str]]:
185
"""
186
Walk directory tree and check files with detailed results.
187
188
Parameters:
189
- root: Root directory path to traverse
190
- on_error: Optional error handler for OS errors
191
- follow_links: Whether to follow symbolic links
192
193
Yields:
194
CheckResult for each file in the tree
195
"""
196
197
def match_entries(
198
self,
199
entries: Iterable[TreeEntry],
200
separators: Optional[Collection[str]] = None,
201
*,
202
negate: Optional[bool] = None
203
) -> Iterator[TreeEntry]:
204
"""
205
Match TreeEntry objects against patterns.
206
207
Parameters:
208
- entries: Iterable of TreeEntry objects to test
209
- separators: Path separators to normalize
210
- negate: If True, return non-matching entries instead
211
212
Yields:
213
TreeEntry objects that match the patterns
214
"""
215
216
def match_tree(
217
self,
218
root: str,
219
on_error: Optional[Callable[[OSError], None]] = None,
220
follow_links: Optional[bool] = None,
221
*,
222
negate: Optional[bool] = None
223
) -> Iterator[str]:
224
"""
225
DEPRECATED: Alias for match_tree_files.
226
227
Walk directory tree and match files against patterns.
228
229
Parameters:
230
- root: Root directory path to traverse
231
- on_error: Optional error handler for OS errors
232
- follow_links: Whether to follow symbolic links
233
- negate: If True, return non-matching files instead
234
235
Yields:
236
File paths that match the patterns
237
"""
238
```
239
240
### GitIgnoreSpec Class
241
242
Specialized PathSpec implementation that closely replicates .gitignore behavior with Git-specific edge case handling.
243
244
```python { .api }
245
class GitIgnoreSpec(PathSpec):
246
def __eq__(self, other: object) -> bool:
247
"""
248
Test equality. Only compares equal to other GitIgnoreSpec instances.
249
"""
250
251
@classmethod
252
def from_lines(
253
cls,
254
lines: Iterable[AnyStr],
255
pattern_factory: Optional[Union[str, Callable[[AnyStr], Pattern]]] = None
256
) -> GitIgnoreSpec:
257
"""
258
Create GitIgnoreSpec from pattern lines. Supports reversed parameter order for compatibility.
259
260
Parameters:
261
- lines: Iterable of gitignore-style pattern strings (or pattern_factory if using reversed order)
262
- pattern_factory: Optional pattern factory (defaults to GitWildMatchPattern, or lines if using reversed order)
263
264
Returns:
265
GitIgnoreSpec instance with compiled patterns
266
267
Note: This method supports both parameter orders:
268
- from_lines(lines, pattern_factory) - standard order
269
- from_lines(pattern_factory, lines) - reversed order for PathSpec compatibility
270
"""
271
272
@staticmethod
273
def _match_file(
274
patterns: Iterable[Tuple[int, GitWildMatchPattern]],
275
file: str
276
) -> Tuple[Optional[bool], Optional[int]]:
277
"""
278
Internal method for gitignore-specific matching logic.
279
280
Parameters:
281
- patterns: Indexed patterns to test against
282
- file: File path to test
283
284
Returns:
285
Tuple of (match_result, pattern_index)
286
"""
287
```
288
289
## Usage Examples
290
291
### Basic File Matching
292
293
```python
294
import pathspec
295
296
# Create PathSpec from patterns
297
patterns = ["*.py", "!test_*.py", "src/"]
298
spec = pathspec.PathSpec.from_lines('gitwildmatch', patterns)
299
300
# Test individual files
301
print(spec.match_file("main.py")) # True
302
print(spec.match_file("test_main.py")) # False
303
print(spec.match_file("src/utils.py")) # True
304
305
# Get matching files from a list
306
files = ["main.py", "test_main.py", "src/utils.py", "README.md"]
307
matches = list(spec.match_files(files))
308
print(matches) # ["main.py", "src/utils.py"]
309
```
310
311
### Directory Tree Traversal
312
313
```python
314
import pathspec
315
316
# Create spec for Python project files
317
spec = pathspec.PathSpec.from_lines('gitwildmatch', [
318
"*.py",
319
"*.md",
320
"!__pycache__/",
321
"!*.pyc",
322
"!.git/"
323
])
324
325
# Get all matching files in project directory
326
project_files = list(spec.match_tree_files("/path/to/project"))
327
328
# Handle errors during traversal
329
def handle_error(error):
330
print(f"Warning: {error}")
331
332
safe_files = list(spec.match_tree_files(
333
"/path/to/project",
334
on_error=handle_error
335
))
336
```
337
338
### Detailed Match Information
339
340
```python
341
import pathspec
342
343
spec = pathspec.PathSpec.from_lines('gitwildmatch', [
344
"*.py", # Pattern 0
345
"!test_*.py" # Pattern 1
346
])
347
348
# Get detailed information about matches
349
result = spec.check_file("main.py")
350
print(f"File: {result.file}")
351
print(f"Included: {result.include}")
352
print(f"Matched by pattern: {result.index}")
353
354
# Check multiple files with details
355
files = ["main.py", "test_main.py", "utils.py"]
356
for result in spec.check_files(files):
357
status = "included" if result.include else "excluded"
358
print(f"{result.file}: {status} (pattern {result.index})")
359
```
360
361
### GitIgnore-Specific Behavior
362
363
```python
364
import pathspec
365
366
# GitIgnoreSpec handles gitignore edge cases
367
gitignore_content = """
368
# Comments are ignored
369
*.log
370
temp/
371
!important.log
372
373
# Negation patterns work correctly
374
build/
375
!build/assets/
376
"""
377
378
spec = pathspec.GitIgnoreSpec.from_lines(gitignore_content.splitlines())
379
380
# Use exactly like PathSpec
381
matches = list(spec.match_tree_files("/project"))
382
```
383
384
### Combining PathSpecs
385
386
```python
387
import pathspec
388
389
# Create separate specs for different pattern sets
390
code_spec = pathspec.PathSpec.from_lines('gitwildmatch', [
391
"*.py", "*.js", "*.ts"
392
])
393
394
doc_spec = pathspec.PathSpec.from_lines('gitwildmatch', [
395
"*.md", "*.rst", "*.txt"
396
])
397
398
# Combine them
399
combined_spec = code_spec + doc_spec
400
401
# Or add in place
402
code_spec += doc_spec
403
```