Wcmatch - Wildcard/Glob File Name Matcher

raw JSON →
10.1 verified Tue May 12 auth: no python install: verified

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.

pip install wcmatch
error TypeError: glob.glob() got an unexpected keyword argument 'flags'
cause The user imported Python's standard `glob` module but attempted to use `wcmatch`-specific arguments like `flags` which are only available in `wcmatch.glob`.
fix
Import wcmatch.glob instead of the standard glob module: from wcmatch import glob then glob.glob('**/*.txt', flags=glob.GLOBSTAR).
error AttributeError: module 'wcmatch.path' has no attribute 'walk'
cause In recent versions of `wcmatch` (v8.0+), path-related functions like `walk` are methods of the `wcmatch.path.Path` class, not direct functions of the module itself.
fix
Instantiate the Path class and call the method on the instance: from wcmatch.path import Path then Path('.').walk().
error ModuleNotFoundError: No module named 'wcmatch'
cause The `wcmatch` library has not been installed in the active Python environment, or the environment where it's installed is not the one being used.
fix
Install the library using pip: pip install wcmatch.
error ERROR: No matching distribution found for wcmatch
cause The Python version being used is no longer supported by the latest `wcmatch` releases, preventing `pip` from finding a compatible package.
fix
Upgrade Python to a supported version (e.g., Python 3.9 or newer for recent wcmatch versions) or explicitly install an older wcmatch version compatible with your current Python (e.g., pip install wcmatch==7.0.2 for Python 3.7).
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.
fix Upgrade your Python environment to 3.9 or newer.
breaking The `glob.raw_escape` function was removed in version 9.0.
fix Review your code for usage of `glob.raw_escape` and remove it, as its functionality is no longer available.
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.
fix Choose either the `exclude` parameter or the `NEGATE` flag with `!` prefix for exclusion patterns, but not both in the same call. The `exclude` parameter offers a cleaner separation.
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).
fix Add `flags=glob.GLOBSTAR | glob.FOLLOW` or `flags=glob.GLOBSTARLONG` to your `glob.glob` calls if symlink traversal is desired.
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.
fix Add `flags=glob.DOTGLOB` (or `glob.GLOBSTAR | glob.DOTGLOB` for recursive hidden files) to your `glob.glob` or `pathlib` calls.
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).
fix Be mindful of complex brace expansions. Consider using extended glob patterns like `@(a|b|c)` or adjusting the `limit` parameter in `compile` or `glob` functions (set to `0` for no limit) if necessary.
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.
fix Use raw strings for patterns with backslashes (e.g., `r'C:\Users\**'`) or use forward slashes for cross-platform compatibility.
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - 0.03s 18.1M
3.10 alpine (musl) - - 0.04s 18.1M
3.10 slim (glibc) wheel 1.5s 0.02s 19M
3.10 slim (glibc) - - 0.03s 19M
3.11 alpine (musl) wheel - 0.09s 20.1M
3.11 alpine (musl) - - 0.10s 20.1M
3.11 slim (glibc) wheel 1.6s 0.07s 21M
3.11 slim (glibc) - - 0.07s 21M
3.12 alpine (musl) wheel - 0.06s 11.9M
3.12 alpine (musl) - - 0.07s 11.9M
3.12 slim (glibc) wheel 1.4s 0.06s 12M
3.12 slim (glibc) - - 0.07s 12M
3.13 alpine (musl) wheel - 0.05s 11.7M
3.13 alpine (musl) - - 0.06s 11.6M
3.13 slim (glibc) wheel 1.5s 0.05s 12M
3.13 slim (glibc) - - 0.06s 12M
3.9 alpine (musl) wheel - 0.03s 17.6M
3.9 alpine (musl) - - 0.04s 17.6M
3.9 slim (glibc) wheel 1.7s 0.03s 18M
3.9 slim (glibc) - - 0.03s 18M

Demonstrates basic recursive globbing, including how to match hidden files, and a simple string match using `fnmatch`. This creates a temporary directory structure for the example.

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')