pathspec review
pathspec 1.1.1 turns ordered gitignore-style lines into matchers for individual relative paths, path iterables, or directory trees. `PathSpec` implements the documented ignore pattern rules; `GitIgnoreSpec` covers places where Git's behavior differs, especially later rules that re-include paths. Version 1 added selectable regex backends and made `gitignore` the preferred pattern name. The 1.1.1 patch concentrates on type checking, including covariant PathSpec typing, pattern-factory hints, and addition operators.
pathspec 1.1.1 installed in 0.2 seconds as 1 package using 1 MB, with typed metadata and 0 audit findings in our sandbox; use GitIgnoreSpec when a Python tool claims Git-like exclusions. Skip it for plain wildcards, and test ordered negations before any 0.x migration.
We installed it
| Install | ✓ · 0.2s | 1 package on disk · 1 MB |
| Import | ✓ | import pathspec in 0.21s · pure Python · py.typed · requires Python >=3.9 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does pathspec install cleanly?
Yes. In a fresh container with an empty cache, pip install pathspec finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does pathspec need to run?
Python >=3.9, and nothing compiled: it is pure Python. In our run import pathspec succeeded in 0.21s, and the package ships py.typed for type checkers.
pathspec or gitignore-parser: which should you use?
gitignore-parser: Choose its small file-oriented helper when one .gitignore file and a boolean matcher are enough. pathspec 1.1.1 installed in 0.2 seconds as 1 package using 1 MB, with typed metadata and 0 audit findings in our sandbox; use GitIgnoreSpec when a Python tool claims Git-like exclusions.
When should you not use pathspec?
The job is one or two shell wildcards; Python's fnmatch already handles that without another package.
Discussed on
Use it if
- A formatter, backup tool, packager, or scanner promises to honor familiar .gitignore-style rules.
- Users need ordered negation rules rather than a fixed set of fnmatch wildcards.
- One compiled specification will test many normalized paths or walk a directory tree.
- Diagnostics need to identify the particular rule and position that produced a match decision.
- The job is one or two shell wildcards; Python's fnmatch already handles that without another package.
- The pattern language needs extglob, brace expansion, or broader globstar controls; wcmatch is built for those forms.
- Callers cannot make paths relative to the rule file's directory. Anchored and nested ignore rules become misleading against absolute paths.
- An upgrade from 0.x cannot be checked against real exclude and re-include fixtures. Version 1 distinguishes documented rules from GitIgnoreSpec's closer Git behavior.
- Modified dependency code cannot be published under MPL 2.0 terms. The project says larger closed-source works are allowed, but changes to pathspec itself must be released.
Setup reality
We installed pathspec 1.1.1 in a fresh Python 3.12 Bookworm sandbox in 0.2 seconds. The install added 1 package and occupied 1 MB; pip-audit found 0 known vulnerabilities. import pathspec completed in 0.21 seconds. The distribution is pure Python, needs Python 3.9 or newer, reports 3 direct dependencies in our measurement, ships py.typed, and uses the Mozilla Public License 2.0.
Choose semantics before compiling rules. GitIgnoreSpec is the safer promise when output should match Git's observed edge cases. PathSpec.from_lines('gitignore', ...) follows the documented pattern implementation and supports the generic pattern abstraction. The older gitwildmatch style name is deprecated in version 1. Tests should cover leading slashes, directory suffixes, comments, escaped markers, and negations.
Rules operate on ordered, relative path text. Convert platform separators to forward slashes and make each path relative to the directory that owns the ignore file. Passing an absolute path often produces a believable but wrong miss. A trailing slash carries directory intent; standalone string matching does not inspect the filesystem, while tree methods can distinguish files during traversal.
Later lines can overturn earlier lines, so never sort or deduplicate a pattern file. check_file() can expose the deciding pattern for an explanation. The default best backend may select optional re2 or Hyperscan support when installed; the simple Python regex backend can be faster for only 1 or 2 patterns. Benchmark the real rule count before accepting native backend packaging and platform costs.
Patterns
Compile ordered ignore lines compile-rules
from pathspec import PathSpec
spec = PathSpec.from_lines('gitignore', [
'*.pyc',
'build/',
'!build/keep.txt',
])
print(spec.match_file('module.pyc'))Pattern order is observable. A later negation can reverse an earlier positive match.
Read rules with Git semantics load-gitignore
from pathspec import GitIgnoreSpec
with open('.gitignore', encoding='utf-8') as source:
spec = GitIgnoreSpec.from_lines(source)
ignored = spec.match_file('dist/app.js')Match paths relative to the directory containing this .gitignore file.
Match a portable relative path normalize-path
from pathlib import Path
root = Path('/srv/project')
candidate = Path('/srv/project/docs/guide.md')
relative = candidate.relative_to(root).as_posix()
ignored = spec.match_file(relative)Anchored rules and directory patterns assume slash-separated names relative to their rule root.
Split ignored and kept files filter-paths
paths = ['src/app.py', 'cache/a.bin', 'notes.tmp']
ignored = set(spec.match_files(paths))
kept = [path for path in paths if path not in ignored]match_files() yields paths that matched the specification; it does not return the kept side automatically.
Find matching files under a root walk-tree
for relative_path in spec.match_tree_files('/srv/project'):
print(relative_path)Tree methods return paths relative to the supplied root and still pay the cost of walking the filesystem.
Invert a tree selection select-kept-files
kept = set(
spec.match_tree_files('/srv/project', negate=True)
)`negate=True` reverses the final match decision, which is useful when assembling a package allowlist.
Append local overrides layer-rule-files
base = GitIgnoreSpec.from_lines(base_lines)
local = GitIgnoreSpec.from_lines(local_lines)
combined = base + localAddition preserves line ordering, so patterns from `local` can change decisions made by `base`.
Inspect the deciding rule explain-match
result = spec.check_file('build/keep.txt')
print(result.include, result.index, result.pattern)check_file() returns the last relevant pattern and its position, which is better for diagnostics than a bare boolean.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| gitignore-parser | PyPI | Choose its small file-oriented helper when one .gitignore file and a boolean matcher are enough. |
| wcmatch | PyPI | Choose it for shell-style matching with brace expansion, extglob, and configurable globstar behavior. |
| glob2 | PyPI | Choose it only for recursive include globs in older code that already depends on its pathlib-independent API. |
More utils guides
lru-cache · type-fest · ajv · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

