]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] GH-106330: Fix matching of empty path in `pathlib.PurePath.match()` (GH-106331...
authorBarney Gale <barney.gale@gmail.com>
Tue, 4 Jul 2023 20:51:36 +0000 (21:51 +0100)
committerGitHub <noreply@github.com>
Tue, 4 Jul 2023 20:51:36 +0000 (21:51 +0100)
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)

Lib/pathlib.py
Lib/test/test_pathlib.py
Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst [new file with mode: 0644]

index d279fd2958b17067e347c4c0810274fe4aefaf6a..b99bf6e7dd240882661adc5e01c01a1f82ff1e39 100644 (file)
@@ -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):
index f716f1075bcb3e6c378bf3a7d50de32739a22969..1d28a782f44ab3780ad2f0c74cbfa436d06cc321 100644 (file)
@@ -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.
diff --git a/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst b/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst
new file mode 100644 (file)
index 0000000..c1f55ab
--- /dev/null
@@ -0,0 +1,2 @@
+Fix incorrect matching of empty paths in :meth:`pathlib.PurePath.match`.
+This bug was introduced in Python 3.12.0 beta 1.