diff options
author | Barney Gale <barney.gale@gmail.com> | 2023-07-04 20:51:36 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-04 20:51:36 (GMT) |
commit | d5ed72b696f2d26d85f3599abf0693545a1ac4e2 (patch) | |
tree | 05fc68ffaa0f6672a77c2fdecb785820de756a64 /Lib | |
parent | 930df7b07e774636ad200a62a7b4b56564f502b0 (diff) | |
download | cpython-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.py | 27 | ||||
-rw-r--r-- | Lib/test/test_pathlib.py | 4 |
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. |