How to match python paths against recursive glob patterns

Viewed 214

I would like to filter a list of linux-style relative paths using glob expressions which may contain **.

For example:

+-- pattern.py
+-- dir_a
|   +-- pattern.py
|   +-- dir_b
|   |   +-- pattern.py

What I'm looking for:

glob_match('*.py', 'pattern.py')                         # -> True
glob_match('*.py', 'dir_a/pattern.py')                   # -> False
glob_match('dir_a/**/*.py', 'dir_a/pattern.py')          # -> True
glob_match('dir_a/*.py', 'dir_a/dir_b/pattern.py')       # -> False
glob_match('dir_a/**/*.py', 'dir_a/dir_b/pattern.py')    # -> True

If I'm not wrong, both pathlib.Path.match and fnmatch.fnmatch do not support **, but rather interpret a single * as any character, including slash, which makes the second and fourth example above give True.

I think I can see how to implement this, but I'd be looking for an existing implementation I can rely on :)

Thanks!

Edit To clarify, the glob_match I'm looking for is the bit of glob.glob(..., recursive=True) that does the matching, without the bit that does the filesystem scanning. In other words, the result of glob_match(pattern, rel_path) should not depend on rel_path pointing to an actual file, or even having access to the filesystem.

  • temporarily writing rel_path to the filesystem just to run glob_match would be a solution but I'd rather not
  • I thought about diggin up the implementation in glob.glob but since it is written as an iterator that doesn't seem much easier than writing a new glob_match from scratch...
1 Answers

After some more searching, I found that the glob.globmatch function in the wcmatch package does exactly what I was looking for (arguments are reversed compared to the code in my question:

print(glob.globmatch('pattern.py', '*.py', flags=glob.GLOBSTAR))
print(glob.globmatch('dir_a/pattern.py', '*.py', flags=glob.GLOBSTAR))
print(glob.globmatch('dir_a/pattern.py', 'dir_a/**/*.py', flags=glob.GLOBSTAR))
print(glob.globmatch('dir_a/dir_b/pattern.py', 'dir_a/*.py', flags=glob.GLOBSTAR))
print(glob.globmatch('dir_a/dir_b/pattern.py', 'dir_a/**/*.py', flags=glob.GLOBSTAR))

Leaving the question open in case someone has a solution based on Python's standard library.

Related