Skip to content
Merged
10 changes: 9 additions & 1 deletion Doc/library/pathlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -576,6 +576,14 @@ Pure paths provide the following methods and properties:
>>> PureWindowsPath('b.py').match('*.PY')
True

By default, or when the *case_sensitive* keyword-only argument is set to
Comment thread
thirumurugan-git marked this conversation as resolved.
Outdated
``None``, this method matches paths using platform-specific casing rules:
typically, case-sensitive on POSIX, and case-insensitive on Windows.
Set *case_sensitive* to ``True`` or ``False`` to override this behaviour.
Comment thread
thirumurugan-git marked this conversation as resolved.
Outdated

.. versionadded:: 3.12
The *case_sensitive* argument.


.. method:: PurePath.relative_to(other, walk_up=False)

Expand Down
18 changes: 14 additions & 4 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, typed=True)
Comment thread
thirumurugan-git marked this conversation as resolved.
Outdated
def _compile_pattern(pat, flags):
re_pat = fnmatch.translate(pat)
Comment thread
thirumurugan-git marked this conversation as resolved.
Outdated
return re.compile(re_pat, flags).match


class _Selector:
"""A selector matches a specific glob pattern part against the children
of a given path."""
Expand Down Expand Up @@ -680,22 +686,26 @@ def is_reserved(self):
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)
flags = re.NOFLAG if case_sensitive else re.IGNORECASE
Comment thread
thirumurugan-git marked this conversation as resolved.
Outdated
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, flags)
if not match(part):
return False
return True

Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ def test_match_common(self):
# 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))
Comment thread
thirumurugan-git marked this conversation as resolved.

def test_ordering_common(self):
# Ordering is tuple-alike.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added case_sensitive argument to pathlib.PurePath.match()
Comment thread
thirumurugan-git marked this conversation as resolved.
Outdated