diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst index ce07d326b395d8..6eabc414805bd8 100644 --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -72,12 +72,17 @@ patterns. :const:`False`; the comparison is case-sensitive and does not apply :func:`os.path.normcase`. + .. versionchanged:: 3.8 + Accepts a :term:`path-like object` as *filename*. .. function:: filter(names, pattern) Return the subset of the list of *names* that match *pattern*. It is the same as ``[n for n in names if fnmatch(n, pattern)]``, but implemented more efficiently. + .. versionchanged:: 3.8 + Accepts :term:`path-like objects ` as items of the iterable + *names*. .. function:: translate(pattern) diff --git a/Lib/fnmatch.py b/Lib/fnmatch.py index b98e6413295e1c..63cb765753d232 100644 --- a/Lib/fnmatch.py +++ b/Lib/fnmatch.py @@ -53,7 +53,7 @@ def filter(names, pat): if os.path is posixpath: # normcase on posix is NOP. Optimize it away from the loop. for name in names: - if match(name): + if match(os.fspath(name)): result.append(name) else: for name in names: @@ -68,7 +68,7 @@ def fnmatchcase(name, pat): its arguments. """ match = _compile_pattern(pat) - return match(name) is not None + return match(os.fspath(name)) is not None def translate(pat): diff --git a/Lib/test/test_fnmatch.py b/Lib/test/test_fnmatch.py index 55f9f0d3a5425a..38721a2c3ccfd4 100644 --- a/Lib/test/test_fnmatch.py +++ b/Lib/test/test_fnmatch.py @@ -6,6 +6,13 @@ from fnmatch import fnmatch, fnmatchcase, translate, filter +class Path: + def __init__(self, path): + self.path = path + + def __fspath__(self): + return self.path + class FnmatchTestCase(unittest.TestCase): def check_match(self, filename, pattern, should_match=True, fn=fnmatch): @@ -95,6 +102,11 @@ def test_warnings(self): check(',', '[a-z+--A-Z]') check('.', '[a-z--/A-Z]') + def test_fspath(self): + check = self.check_match + check(Path('foo.txt'), '*.txt', fn=fnmatch) + check(Path('foo.txt'), '*.txt', fn=fnmatchcase) + class TranslateTestCase(unittest.TestCase): @@ -135,6 +147,12 @@ def test_sep(self): self.assertEqual(filter(['usr/bin', 'usr', 'usr\\lib'], 'usr\\*'), ['usr/bin', 'usr\\lib'] if normsep else ['usr\\lib']) + def test_fspath(self): + path = Path('foo.txt') + + self.assertEqual(filter([path], '*.txt*'), [path]) + self.assertEqual(filter([path, 'bar.txt'], '*.txt'), [path, 'bar.txt']) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2018-12-04-07-02-57.bpo-35396.eXdRba.rst b/Misc/NEWS.d/next/Library/2018-12-04-07-02-57.bpo-35396.eXdRba.rst new file mode 100644 index 00000000000000..c6d1e7967539a3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-12-04-07-02-57.bpo-35396.eXdRba.rst @@ -0,0 +1,3 @@ +Added support for :term:`path-like objects ` to +:func:`fnmatch.fnmatchcase` and :func:`fnmatch.filter`. Patch by +Andrés Delfino.