{"id":280,"library":"pathspec","title":"pathspec","description":"pathspec is a utility library for gitignore-style pattern matching of file paths, implementing Git's wildmatch/gitignore specification. Current stable version is 1.0.4 (released 2025). The project is actively maintained by Caleb P. Burns and releases roughly a few times per year. It is a zero-dependency pure-Python library widely used by tools such as Black, pip, and Poetry for .gitignore-based file filtering.","status":"active","version":"1.0.4","language":"python","source_language":"en","source_url":"https://github.com/cpburnz/python-pathspec","tags":["filesystem","gitignore","pattern-matching","glob","files","ignore"],"install":[{"cmd":"pip install pathspec","lang":"bash","label":"Latest stable"},{"cmd":"pip install pathspec google-re2","lang":"bash","label":"With fast re2 backend"}],"dependencies":[{"reason":"Optional high-performance regex backend; significantly faster than the default 'simple' backend at high pattern counts","package":"google-re2","optional":true},{"reason":"Optional regex backend; 2x faster than 'simple' backend, best for 1-25 patterns","package":"hyperscan","optional":true}],"imports":[{"note":"Top-level re-export; do not import from pathspec.pathspec directly","symbol":"PathSpec","correct":"from pathspec import PathSpec"},{"note":"For true git-compatible behaviour (including edge cases like re-including files from excluded dirs) use GitIgnoreSpec.from_lines(), not PathSpec with 'gitwildmatch'","wrong":"from pathspec import PathSpec; spec = PathSpec.from_lines('gitwildmatch', lines)","symbol":"GitIgnoreSpec","correct":"from pathspec import GitIgnoreSpec"},{"note":"GitWildMatchPattern is deprecated since 1.0.0 and is now only an alias for GitIgnoreSpecPattern; update direct references","wrong":"from pathspec.patterns import GitWildMatchPattern","symbol":"GitWildMatchPattern","correct":"from pathspec.patterns.gitignore.spec import GitIgnoreSpecPattern"}],"quickstart":{"code":"from pathspec import PathSpec, GitIgnoreSpec\n\n# --- PathSpec: documented gitignore behaviour ---\npatterns = [\n    '*.pyc',\n    '__pycache__/',\n    'dist/',\n    '!dist/keep_this.txt',   # negation re-includes a file\n]\nspec = PathSpec.from_lines('gitignore', patterns)\n\n# Match a list of paths\nfiles = ['src/main.py', 'src/main.pyc', '__pycache__/x.pyc', 'dist/output.whl']\nmatched = list(spec.match_files(files))\nprint('Matched (excluded):', matched)\n# -> ['src/main.pyc', '__pycache__/x.pyc', 'dist/output.whl']\n\n# --- GitIgnoreSpec: replicates Git's actual edge-case behaviour ---\n# Use this when you need to mirror exactly what `git` itself would ignore.\ngit_spec = GitIgnoreSpec.from_lines(patterns)\n\n# Walk a real directory tree and get files to KEEP (negate=True flips results)\nimport os, tempfile, pathlib\nwith tempfile.TemporaryDirectory() as tmpdir:\n    # create sample files\n    for p in ['a.py', 'a.pyc', '__pycache__/x.pyc']:\n        full = pathlib.Path(tmpdir) / p\n        full.parent.mkdir(parents=True, exist_ok=True)\n        full.write_text('')\n    keep = set(git_spec.match_tree_files(tmpdir, negate=True))\n    ignore = set(git_spec.match_tree_files(tmpdir))\n    print('Keep:', keep)\n    print('Ignore:', ignore)\n","lang":"python","description":"Compile gitignore-style patterns with PathSpec (documented semantics) or GitIgnoreSpec (true Git edge-case semantics), match individual paths or walk a directory tree."},"warnings":[{"fix":"Use spec.match_tree_files('path/to/dir', negate=True) to obtain files to keep, mirroring .gitignore exclusion logic.","message":"GitIgnoreSpec and PathSpec both POSITIVELY match files by default — meaning match_tree_files() returns the files that ARE ignored, not the files to keep. Pass negate=True to get the files that should be kept.","severity":"gotcha","affected_versions":">=0.11.0"},{"fix":"Use GitIgnoreSpec.from_lines() whenever you need to replicate what 'git status' / 'git ls-files' would show.","message":"PathSpec and GitIgnoreSpec implement gitignore differently. PathSpec follows the documented spec strictly; GitIgnoreSpec replicates Git's actual behaviour, including allowing files to be re-included from an otherwise excluded directory. Using PathSpec for exact git parity will produce wrong results on such edge cases.","severity":"gotcha","affected_versions":">=0.11.0"},{"fix":"Replace PathSpec.from_lines('gitwildmatch', ...) with PathSpec.from_lines('gitignore', ...) and import from pathspec.patterns.gitignore.spec.GitIgnoreSpecPattern if you reference the class directly.","message":"The pattern name 'gitwildmatch' and the class pathspec.patterns.GitWildMatchPattern are deprecated since 1.0.0. 'gitwildmatch' is now an alias for 'gitignore', and GitWildMatchPattern is an alias for GitIgnoreSpecPattern.","severity":"deprecated","affected_versions":">=1.0.0"},{"fix":"Remove overrides of PathSpec._match_file(). Use the public match_file() / match_files() / match_tree_files() API or implement a custom backend instead.","message":"In v1.0.0 the protected method PathSpec._match_file() was removed and replaced by the backends system. Any custom PathSpec subclass overriding _match_file() will silently break.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Upgrade to >=0.10.1.","message":"v0.10.0 introduced a regression that broke a common wildcard matching pattern used by Black and other tools; v0.10.1 fixed it. Pinning to exactly 0.10.0 will cause subtle mis-matches.","severity":"breaking","affected_versions":"==0.10.0"},{"fix":"Always pass the root directory as the first argument and let the library normalise paths, or pre-normalise with os.path.relpath(). Do not feed absolute paths to match_file().","message":"match_tree_files() (and the deprecated match_tree()) require paths to be RELATIVE to the root directory. Passing absolute paths or paths with a leading slash will fail to match patterns correctly.","severity":"gotcha","affected_versions":"all"},{"fix":"Install 'pip install google-re2', not 'pip install re2'.","message":"The 're2' optional backend refers to google-re2 (PyPI package google-re2), NOT the unrelated abandoned 're2' package on PyPI. Installing the wrong package will silently fall back to 'simple'.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure a C++ compiler is installed in your environment before attempting to install `google-re2`. For Debian/Ubuntu-based systems, this typically means `apt-get install build-essential`. For RHEL/CentOS, `yum install gcc-c++` or `dnf install gcc-c++`.","message":"The `google-re2` package, an optional backend for `pathspec`, requires a C++ compiler (like g++) to be available in the environment to build its native extensions. In minimal environments (e.g., -slim Docker images), these build tools are often missing, leading to installation failure.","severity":"breaking","affected_versions":"all"},{"fix":"Install a C++ compiler and build essentials in your environment. For Alpine Linux, this typically means running `apk add build-base` or `apk add g++`.","message":"Building the 'google-re2' package, which provides the optional 're2' backend for pathspec, requires a C++ compiler (e.g., g++) and associated build tools. In minimal environments (like Alpine Linux), these tools might be missing, leading to compilation failure.","severity":"breaking","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-05-12T12:48:06.463Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Install the library using pip: `pip install pathspec`","cause":"The `pathspec` library is not installed in the Python environment where the code is being run.","error":"ModuleNotFoundError: No module named 'pathspec'"},{"fix":"Update your import statement to use `from pathspec.patterns.gitignore.spec import GitIgnorePatternError` and adjust your code accordingly. If you need the exact prior behavior, refer to `GitIgnoreSpecPattern`.","cause":"The `GitWildMatchPatternError` class (and the `pathspec.patterns.gitwildmatch` module) was deprecated and removed in `pathspec` version 1.0.0 and later, replaced by `GitIgnorePatternError` in `pathspec.patterns.gitignore.spec`.","error":"ImportError: cannot import name 'GitWildMatchPatternError' from 'pathspec.patterns.gitwildmatch'"},{"fix":"For Git's behavior, use `from pathspec import GitIgnoreSpec` and then `GitIgnoreSpec.from_lines(...)`. For behavior aligning with `.gitignore` documentation, use `PathSpec.from_lines('gitignore', ...)`. If you explicitly need the exact behavior of the old `GitWildMatchPattern`, use `PathSpec.from_lines(GitIgnoreSpecPattern, ...)`.","cause":"In `pathspec` version 1.0.0 and later, the 'gitwildmatch' backend's behavior was split and changed. Using `PathSpec.from_lines('gitwildmatch', ...)` now aliases to 'gitignore', which may not match the exact behavior of Git's `wildmatch` patterns as in previous versions or `git`. For more precise control, dedicated backends like `GitIgnoreSpec` were introduced.","error":"Using PathSpec.from_lines('gitwildmatch', ...) results in unexpected filtering behavior or deprecation warnings"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.4,"disk_size":"18.2M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.4,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2.6,"disk_size":"20M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":2.7,"disk_size":"20.1M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":2.7,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":2.9,"disk_size":"22M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":2.7,"disk_size":"12.0M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":2.7,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":2.8,"disk_size":"14M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":2.6,"disk_size":"11.6M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":2.5,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":2.6,"disk_size":"14M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.4,"disk_size":"17.7M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.4,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}