Wcmatch - Wildcard/Glob File Name Matcher
Wcmatch is a Python library that provides enhanced `fnmatch`, `glob`, and `pathlib` functionalities, closely following Bash-like wildcard and glob matching features. It includes support for recursive globs (`**`), Zsh-style symlink traversal (`***`), brace expansion, extended glob patterns, and more. The library is actively maintained with regular releases, often adding new features and dropping support for older Python versions.
Warnings
- breaking Wcmatch has progressively dropped support for older Python versions. Version 10.1 dropped Python 3.8, Version 8.5 dropped Python 3.7, and Version 8.4 dropped Python 3.6. Ensure your environment uses Python 3.9 or newer.
- breaking The `glob.raw_escape` function was removed in version 9.0.
- gotcha When using `glob` or `fnmatch` for exclusion, the `exclude` parameter (introduced in v8.4) is generally preferred over using the `NEGATE` flag with `!` prefixes in patterns. Do not use both simultaneously, as this can lead to unexpected behavior.
- gotcha By default, `GLOBSTAR` (`**`) in `wcmatch.glob` does not traverse symlinks. To include symlinks in recursive globbing, you must explicitly enable the `FOLLOW` or `GLOBSTARLONG` flag (the latter provides Zsh-style `***` behavior, introduced in 10.0).
- gotcha Wildcard characters like `*` do not match files or directories starting with a dot (`.`) by default. To include hidden files/directories in your glob results, enable the `DOTGLOB` flag.
- gotcha Large brace expansion patterns (e.g., `a{1..100000}`) can lead to a significant number of generated patterns, potentially impacting performance or exceeding the default pattern limit (1000).
- gotcha On Windows, backslashes in patterns must be escaped (e.g., `r'path\\to\file'`) to match literal backslashes, as `wcmatch` allows escaped characters. Forward slashes (`/`) are normalized and will match both forward and backslashes.
Install
-
pip install wcmatch
Imports
- glob
from wcmatch import glob
- fnmatch
from wcmatch import fnmatch
- pathlib
from wcmatch import pathlib
- WcMatch
from wcmatch import wcmatch
Quickstart
import os
import shutil
from wcmatch import glob, fnmatch
# Create some dummy files/directories for the example
os.makedirs('temp_dir/nested/.hidden', exist_ok=True)
with open('temp_dir/file.txt', 'w') as f: f.write('hi')
with open('temp_dir/nested/another.log', 'w') as f: f.write('hi')
with open('temp_dir/nested/.hidden/secret.dat', 'w') as f: f.write('hi')
print("Basic recursive glob (glob.GLOBSTAR):")
# By default, doesn't match hidden files or symlinks
# Output may vary based on OS and actual symlinks
results_globstar = glob.glob('temp_dir/**/*.txt', flags=glob.GLOBSTAR)
print(f"Found: {sorted(results_globstar)}")
# Expected: ['temp_dir/file.txt']
print("\nRecursive glob including hidden files (GLOBSTAR | DOTGLOB):")
results_hidden = glob.glob('temp_dir/**/*', flags=glob.GLOBSTAR | glob.DOTGLOB)
print(f"Found: {sorted(results_hidden)}")
# Expected: Should include 'temp_dir/.hidden/secret.dat', 'temp_dir/file.txt', 'temp_dir/nested/another.log', etc.
print("\nString matching with fnmatch:")
match_str = fnmatch.fnmatch('image.jpeg', '*.jp*g')
print(f"'image.jpeg' matches '*.jp*g': {match_str}")
# Expected: True
# Clean up
shutil.rmtree('temp_dir')