summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2023-07-04 20:51:36 (GMT)
committerGitHub <noreply@github.com>2023-07-04 20:51:36 (GMT)
commitd5ed72b696f2d26d85f3599abf0693545a1ac4e2 (patch)
tree05fc68ffaa0f6672a77c2fdecb785820de756a64 /Lib
parent930df7b07e774636ad200a62a7b4b56564f502b0 (diff)
downloadcpython-d5ed72b696f2d26d85f3599abf0693545a1ac4e2.zip
cpython-d5ed72b696f2d26d85f3599abf0693545a1ac4e2.tar.gz
cpython-d5ed72b696f2d26d85f3599abf0693545a1ac4e2.tar.bz2
[3.12] GH-106330: Fix matching of empty path in `pathlib.PurePath.match()` (GH-106331) (GH-106372)
We match paths using the `_lines` attribute, which is derived from the path's string representation. The bug arises because an empty path's string representation is `'.'` (not `''`), which is matched by the `'*'` wildcard. (cherry picked from commit b4efdf8cda8fbbd0ca53b457d5f6e46a59348caf)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/pathlib.py27
-rw-r--r--Lib/test/test_pathlib.py4
2 files changed, 23 insertions, 8 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index d279fd2..b99bf6e 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -127,12 +127,19 @@ def _compile_pattern_lines(pattern_lines, case_sensitive):
# Match the start of the path, or just after a path separator
parts = ['^']
for part in pattern_lines.splitlines(keepends=True):
- # We slice off the common prefix and suffix added by translate() to
- # ensure that re.DOTALL is not set, and the end of the string not
- # matched, respectively. With DOTALL not set, '*' wildcards will not
- # match path separators, because the '.' characters in the pattern
- # will not match newlines.
- parts.append(fnmatch.translate(part)[_FNMATCH_SLICE])
+ if part == '*\n':
+ part = r'.+\n'
+ elif part == '*':
+ part = r'.+'
+ else:
+ # Any other component: pass to fnmatch.translate(). We slice off
+ # the common prefix and suffix added by translate() to ensure that
+ # re.DOTALL is not set, and the end of the string not matched,
+ # respectively. With DOTALL not set, '*' wildcards will not match
+ # path separators, because the '.' characters in the pattern will
+ # not match newlines.
+ part = fnmatch.translate(part)[_FNMATCH_SLICE]
+ parts.append(part)
# Match the end of the path, always.
parts.append(r'\Z')
flags = re.MULTILINE
@@ -501,8 +508,12 @@ class PurePath(object):
try:
return self._lines_cached
except AttributeError:
- trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep]
- self._lines_cached = str(self).translate(trans)
+ path_str = str(self)
+ if path_str == '.':
+ self._lines_cached = ''
+ else:
+ trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep]
+ self._lines_cached = path_str.translate(trans)
return self._lines_cached
def __eq__(self, other):
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index f716f10..1d28a78 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -317,6 +317,10 @@ class _BasePurePathTest(object):
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))
+ # Matching against empty path
+ self.assertFalse(P().match('*'))
+ self.assertTrue(P().match('**'))
+ self.assertFalse(P().match('**/*'))
def test_ordering_common(self):
# Ordering is tuple-alike.