Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.gitignore style fnmatch()

What would be the simplest way to have .gitignore style fnmatch() with Python. Looks like that stdlib does not provide a match() function which would match a path spec against an UNIX style path regex.

  • fnmatch() matches only pure filenames, no paths http://docs.python.org/library/fnmatch.html?highlight=fnmatch#fnmatch

  • glob() will perform directory listing, and does not provide match() true/false style function http://docs.python.org/py3k/library/glob.html?highlight=glob#glob.glob

.gitignore have both paths and files with wildcards to be (black)listed

  • https://github.com/miohtama/Krusovice/blob/master/.gitignore

  • http://linux.die.net/man/5/gitignore

like image 823
Mikko Ohtamaa Avatar asked Apr 06 '12 20:04

Mikko Ohtamaa


2 Answers

There's a library called pathspec which implements the full .gitignore specification, including things like **/*.py; the documentation describes how to handle Git pattern matching (you can also see code).

>>> import pathspec
>>> spec_src = '**/*.pyc'
>>> spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, spec_src.splitlines())
>>> set(spec.match_files({"test.py", "test.pyc", "deeper/file.pyc", "even/deeper/file.pyc"}))
set(['test.pyc', 'even/deeper/file.pyc', 'deeper/file.pyc'])
>>> set(spec.match_tree("pathspec/"))
set(['__init__.pyc', 'gitignore.pyc', 'util.pyc', 'pattern.pyc', 'tests/__init__.pyc', 'tests/test_gitignore.pyc', 'compat.pyc', 'pathspec.pyc'])
like image 52
David Fraser Avatar answered Sep 21 '22 13:09

David Fraser


If you want to use mixed UNIX wildcard patterns as listed in your .gitignore example, why not just take each pattern and use fnmatch.translate with re.search?

import fnmatch
import re

s = '/path/eggs/foo/bar'
pattern = "eggs/*"

re.search(fnmatch.translate(pattern), s)
# <_sre.SRE_Match object at 0x10049e988>

translate turns the wildcard pattern into a re pattern

Hidden UNIX files:

s = '/path/to/hidden/.file'
isHiddenFile = re.search(fnmatch.translate('.*'), s)
if not isHiddenFile:
    # do something with it
like image 34
jdi Avatar answered Sep 21 '22 13:09

jdi