From 57bda18c98d101a818f554bf556eb3f992083d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:35:58 +0200 Subject: [PATCH 1/7] support path-like objects in `fnmatch.fnmatchcase` --- Lib/fnmatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fnmatch.py b/Lib/fnmatch.py index 73acb1fe8d4106..16dfb265ab58f7 100644 --- a/Lib/fnmatch.py +++ b/Lib/fnmatch.py @@ -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): From 870dab6535ab0f67613e22575b86e793c11af81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:36:01 +0200 Subject: [PATCH 2/7] add tests --- Lib/test/test_fnmatch.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_fnmatch.py b/Lib/test/test_fnmatch.py index 10ed496d4e2f37..5d336f026d1d72 100644 --- a/Lib/test/test_fnmatch.py +++ b/Lib/test/test_fnmatch.py @@ -4,6 +4,8 @@ import os import string import warnings +from pathlib import Path +from test.support.os_helper import FakePath from fnmatch import fnmatch, fnmatchcase, translate, filter @@ -61,15 +63,17 @@ def test_mix_bytes_str(self): def test_fnmatchcase(self): check = self.check_match - check('abc', 'abc', True, fnmatchcase) - check('AbC', 'abc', False, fnmatchcase) - check('abc', 'AbC', False, fnmatchcase) - check('AbC', 'AbC', True, fnmatchcase) - - check('usr/bin', 'usr/bin', True, fnmatchcase) - check('usr\\bin', 'usr/bin', False, fnmatchcase) - check('usr/bin', 'usr\\bin', False, fnmatchcase) - check('usr\\bin', 'usr\\bin', True, fnmatchcase) + for cls in (str, Path, FakePath): + with self.subTest(cls=cls): + check(cls('abc'), 'abc', True, fnmatchcase) + check(cls('AbC'), 'abc', False, fnmatchcase) + check(cls('abc'), 'AbC', False, fnmatchcase) + check(cls('AbC'), 'AbC', True, fnmatchcase) + + check(cls('usr/bin'), 'usr/bin', True, fnmatchcase) + check(cls('usr\\bin'), 'usr/bin', False, fnmatchcase) + check(cls('usr/bin'), 'usr\\bin', False, fnmatchcase) + check(cls('usr\\bin'), 'usr\\bin', True, fnmatchcase) def test_bytes(self): self.check_match(b'test', b'te*') From 04ed91d3e4d89f14ccd68ffba8065edbda0646aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:36:17 +0200 Subject: [PATCH 3/7] blurb --- .../next/Library/2024-08-22-09-33-17.gh-issue-123215.MpDzeC.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-08-22-09-33-17.gh-issue-123215.MpDzeC.rst diff --git a/Misc/NEWS.d/next/Library/2024-08-22-09-33-17.gh-issue-123215.MpDzeC.rst b/Misc/NEWS.d/next/Library/2024-08-22-09-33-17.gh-issue-123215.MpDzeC.rst new file mode 100644 index 00000000000000..bd5a211c614c09 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-22-09-33-17.gh-issue-123215.MpDzeC.rst @@ -0,0 +1,2 @@ +Added support for :term:`path-like objects ` for the +*name* parameter of :func:`fnmatch.fnmatchcase`. Patch by Bénédikt Tran. From dcbd139cc7dd15119814461edc0b6570e08bac7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:36:24 +0200 Subject: [PATCH 4/7] add What's New entry --- Doc/whatsnew/3.14.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index a34dc639ad2a94..705b388d6bfd3a 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -126,6 +126,14 @@ dis (Contributed by Bénédikt Tran in :gh:`123165`.) +fnmatch +------- + +* Added support for :term:`path-like objects ` for + the *name* parameter of :func:`fnmatch.fnmatchcase`. + + (Contributed by Bénédikt Tran in :gh:`123215`.) + fractions --------- From e369ab7673b0f455e64571a72acf055b46cdf534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:36:27 +0200 Subject: [PATCH 5/7] add docs --- Doc/library/fnmatch.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst index fda44923f204fc..6de1ea98dfe71f 100644 --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -52,7 +52,7 @@ cache the compiled regex patterns in the following functions: :func:`fnmatch`, .. function:: fnmatch(name, pat) - Test whether the filename string *name* matches the pattern string *pat*, + Test whether the filename *name* matches the pattern string *pat*, returning ``True`` or ``False``. Both parameters are case-normalized using :func:`os.path.normcase`. :func:`fnmatchcase` can be used to perform a case-sensitive comparison, regardless of whether that's standard for the @@ -71,10 +71,14 @@ cache the compiled regex patterns in the following functions: :func:`fnmatch`, .. function:: fnmatchcase(name, pat) - Test whether the filename string *name* matches the pattern string *pat*, + Test whether the filename *name* matches the pattern string *pat*, returning ``True`` or ``False``; the comparison is case-sensitive and does not apply :func:`os.path.normcase`. + .. versionchanged:: 3.14 + Added support for :term:`path-like objects ` for + the *name* parameter. + .. function:: filter(names, pat) From fa3b2c62e25b9026df364e39b3b3b4e9410f031e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:08:25 +0200 Subject: [PATCH 6/7] investigations --- Lib/test/test_fnmatch.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_fnmatch.py b/Lib/test/test_fnmatch.py index 5d336f026d1d72..3714aaeef4cf19 100644 --- a/Lib/test/test_fnmatch.py +++ b/Lib/test/test_fnmatch.py @@ -14,12 +14,12 @@ class FnmatchTestCase(unittest.TestCase): def check_match(self, filename, pattern, should_match=True, fn=fnmatch): if should_match: self.assertTrue(fn(filename, pattern), - "expected %r to match pattern %r" - % (filename, pattern)) + "expected %r (%r) to match pattern %r" + % (filename, os.fspath(filename), pattern)) else: self.assertFalse(fn(filename, pattern), - "expected %r not to match pattern %r" - % (filename, pattern)) + "expected %r (%r) not to match pattern %r" + % (filename, os.fspath(filename), pattern)) def test_fnmatch(self): check = self.check_match From b14aef594ad6c88c6f207516403bf3d9400309dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:31:05 +0200 Subject: [PATCH 7/7] investigations --- Lib/test/test_fnmatch.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_fnmatch.py b/Lib/test/test_fnmatch.py index 3714aaeef4cf19..819a0ba42e5fbb 100644 --- a/Lib/test/test_fnmatch.py +++ b/Lib/test/test_fnmatch.py @@ -70,10 +70,10 @@ def test_fnmatchcase(self): check(cls('abc'), 'AbC', False, fnmatchcase) check(cls('AbC'), 'AbC', True, fnmatchcase) - check(cls('usr/bin'), 'usr/bin', True, fnmatchcase) - check(cls('usr\\bin'), 'usr/bin', False, fnmatchcase) - check(cls('usr/bin'), 'usr\\bin', False, fnmatchcase) - check(cls('usr\\bin'), 'usr\\bin', True, fnmatchcase) + check(cls('usr/bin'), 'usr/bin', os.fspath(cls('/')) == '/', fnmatchcase) + check(cls('usr\\bin'), 'usr/bin', os.fspath(cls('\\')) == '/', fnmatchcase) + check(cls('usr/bin'), 'usr\\bin', os.fspath(cls('/')) == '\\', fnmatchcase) + check(cls('usr\\bin'), 'usr\\bin', os.fspath(cls('\\')) == '\\', fnmatchcase) def test_bytes(self): self.check_match(b'test', b'te*')