summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthirumurugan <67573527+thirumurugan-git@users.noreply.github.com>2023-05-18 17:59:31 (GMT)
committerGitHub <noreply@github.com>2023-05-18 17:59:31 (GMT)
commitdcdc90d384723920e8dea0ee04eae8c219333634 (patch)
tree86ca2a14764711a0b1586358d2d7236b6643eff0
parentcfa517d5a68bae24cbe8d9fe6b8e0d4935e507d2 (diff)
downloadcpython-dcdc90d384723920e8dea0ee04eae8c219333634.zip
cpython-dcdc90d384723920e8dea0ee04eae8c219333634.tar.gz
cpython-dcdc90d384723920e8dea0ee04eae8c219333634.tar.bz2
GH-104484: Add case_sensitive argument to `pathlib.PurePath.match()` (GH-104565)
Co-authored-by: Barney Gale <barney.gale@gmail.com>
-rw-r--r--Doc/library/pathlib.rst7
-rw-r--r--Doc/whatsnew/3.12.rst3
-rw-r--r--Lib/pathlib.py20
-rw-r--r--Lib/test/test_pathlib.py7
-rw-r--r--Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst1
5 files changed, 30 insertions, 8 deletions
diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index 93af07a..627f2df 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -546,7 +546,7 @@ Pure paths provide the following methods and properties:
PureWindowsPath('c:/Program Files')
-.. method:: PurePath.match(pattern)
+.. method:: PurePath.match(pattern, *, case_sensitive=None)
Match this path against the provided glob-style pattern. Return ``True``
if matching is successful, ``False`` otherwise.
@@ -576,6 +576,11 @@ Pure paths provide the following methods and properties:
>>> PureWindowsPath('b.py').match('*.PY')
True
+ Set *case_sensitive* to ``True`` or ``False`` to override this behaviour.
+
+ .. versionadded:: 3.12
+ The *case_sensitive* argument.
+
.. method:: PurePath.relative_to(other, walk_up=False)
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 3e55b3f..25f0a4c 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -395,6 +395,9 @@ pathlib
* Add :meth:`pathlib.Path.is_junction` as a proxy to :func:`os.path.isjunction`.
(Contributed by Charles Machalow in :gh:`99547`.)
+* Add *case_sensitive* optional parameter to :meth:`pathlib.Path.glob`,
+ :meth:`pathlib.Path.rglob` and :meth:`pathlib.PurePath.match` for matching
+ the path's case sensitivity, allowing for more precise control over the matching process.
dis
---
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index ef7c47c..3d68c16 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -86,6 +86,12 @@ def _make_selector(pattern_parts, flavour, case_sensitive):
return cls(pat, child_parts, flavour, case_sensitive)
+@functools.lru_cache(maxsize=256)
+def _compile_pattern(pat, case_sensitive):
+ flags = re.NOFLAG if case_sensitive else re.IGNORECASE
+ return re.compile(fnmatch.translate(pat), flags).match
+
+
class _Selector:
"""A selector matches a specific glob pattern part against the children
of a given path."""
@@ -133,8 +139,7 @@ class _WildcardSelector(_Selector):
if case_sensitive is None:
# TODO: evaluate case-sensitivity of each directory in _select_from()
case_sensitive = _is_case_sensitive(flavour)
- flags = re.NOFLAG if case_sensitive else re.IGNORECASE
- self.match = re.compile(fnmatch.translate(pat), flags=flags).fullmatch
+ self.match = _compile_pattern(pat, case_sensitive)
def _select_from(self, parent_path, scandir):
try:
@@ -680,22 +685,25 @@ class PurePath(object):
name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ')
return name.upper() in _WIN_RESERVED_NAMES
- def match(self, path_pattern):
+ def match(self, path_pattern, *, case_sensitive=None):
"""
Return True if this path matches the given pattern.
"""
+ if case_sensitive is None:
+ case_sensitive = _is_case_sensitive(self._flavour)
pat = self.with_segments(path_pattern)
if not pat.parts:
raise ValueError("empty pattern")
- pat_parts = pat._parts_normcase
- parts = self._parts_normcase
+ pat_parts = pat.parts
+ parts = self.parts
if pat.drive or pat.root:
if len(pat_parts) != len(parts):
return False
elif len(pat_parts) > len(parts):
return False
for part, pat in zip(reversed(parts), reversed(pat_parts)):
- if not fnmatch.fnmatchcase(part, pat):
+ match = _compile_pattern(pat, case_sensitive)
+ if not match(part):
return False
return True
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 46a5248..ab2c2b2 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -312,6 +312,11 @@ class _BasePurePathTest(object):
# Multi-part glob-style pattern.
self.assertFalse(P('/a/b/c.py').match('/**/*.py'))
self.assertTrue(P('/a/b/c.py').match('/a/**/*.py'))
+ # Case-sensitive flag
+ self.assertFalse(P('A.py').match('a.PY', case_sensitive=True))
+ self.assertTrue(P('A.py').match('a.PY', case_sensitive=False))
+ self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True))
+ self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False))
def test_ordering_common(self):
# Ordering is tuple-alike.
@@ -916,7 +921,7 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
self.assertEqual(P('//some/share/a/b%#c\xe9').as_uri(),
'file://some/share/a/b%25%23c%C3%A9')
- def test_match_common(self):
+ def test_match(self):
P = self.cls
# Absolute patterns.
self.assertTrue(P('c:/b.py').match('*:/*.py'))
diff --git a/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst b/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst
new file mode 100644
index 0000000..6d42078
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst
@@ -0,0 +1 @@
+Added *case_sensitive* argument to :meth:`pathlib.PurePath.match`