[Python-checkins] bpo-22276: Change pathlib.Path.glob not to ignore trailing path separator (GH-10349)

brettcannon webhook-mailer at python.org
Thu Apr 28 15:45:35 EDT 2022


https://github.com/python/cpython/commit/ea2f5bcda1a392804487e6883be89fbad38a01a5
commit: ea2f5bcda1a392804487e6883be89fbad38a01a5
branch: main
author: Eisuke Kawashima <e-kwsm at users.noreply.github.com>
committer: brettcannon <brett at python.org>
date: 2022-04-28T12:45:03-07:00
summary:

bpo-22276: Change pathlib.Path.glob not to ignore trailing path separator (GH-10349)

Now pathlib.Path.glob() **only** matches directories when the pattern ends in a path separator.

Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>

files:
A Misc/NEWS.d/next/Library/2018-11-11-04-41-11.bpo-22276.Tt19TW.rst
M Doc/library/pathlib.rst
M Doc/whatsnew/3.11.rst
M Lib/pathlib.py
M Lib/test/test_pathlib.py

diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index 01e9cfb93e391..ab26e2f1719fe 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -815,6 +815,9 @@ call fails (for example because the path doesn't exist).
 
    .. audit-event:: pathlib.Path.glob self,pattern pathlib.Path.glob
 
+   .. versionchanged:: 3.11
+      Return only directories if *pattern* ends with a pathname components
+      separator (:data:`~os.sep` or :data:`~os.altsep`).
 
 .. method:: Path.group()
 
@@ -1104,6 +1107,9 @@ call fails (for example because the path doesn't exist).
 
    .. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob
 
+   .. versionchanged:: 3.11
+      Return only directories if *pattern* ends with a pathname components
+      separator (:data:`~os.sep` or :data:`~os.altsep`).
 
 .. method:: Path.rmdir()
 
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index b2b98747d31a1..5f1f995a0fe2f 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -506,6 +506,15 @@ os
   instead of ``CryptGenRandom()`` which is deprecated.
   (Contributed by Dong-hee Na in :issue:`44611`.)
 
+
+pathlib
+-------
+
+* :meth:`~pathlib.Path.glob` and :meth:`~pathlib.Path.rglob` return only
+  directories if *pattern* ends with a pathname components separator:
+  :data:`~os.sep` or :data:`~os.altsep`.
+  (Contributed by Eisuke Kawasima in :issue:`22276` and :issue:`33392`.)
+
 re
 --
 
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 4763ab54f6ba8..1f098fe6bd5f3 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -281,6 +281,8 @@ def make_uri(self, path):
 def _make_selector(pattern_parts, flavour):
     pat = pattern_parts[0]
     child_parts = pattern_parts[1:]
+    if not pat:
+        return _TerminatingSelector()
     if pat == '**':
         cls = _RecursiveWildcardSelector
     elif '**' in pat:
@@ -943,6 +945,8 @@ def glob(self, pattern):
         drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
         if drv or root:
             raise NotImplementedError("Non-relative patterns are unsupported")
+        if pattern[-1] in (self._flavour.sep, self._flavour.altsep):
+            pattern_parts.append('')
         selector = _make_selector(tuple(pattern_parts), self._flavour)
         for p in selector.select_from(self):
             yield p
@@ -956,6 +960,8 @@ def rglob(self, pattern):
         drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
         if drv or root:
             raise NotImplementedError("Non-relative patterns are unsupported")
+        if pattern[-1] in (self._flavour.sep, self._flavour.altsep):
+            pattern_parts.append('')
         selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
         for p in selector.select_from(self):
             yield p
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index b8b08bf0ce1bb..6737068c0ff6d 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -1662,6 +1662,11 @@ def _check(glob, expected):
         else:
             _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
 
+        if not os_helper.can_symlink():
+            _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"])
+        else:
+            _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"])
+
     def test_rglob_common(self):
         def _check(glob, expected):
             self.assertEqual(set(glob), { P(BASE, q) for q in expected })
@@ -1679,6 +1684,16 @@ def _check(glob, expected):
                                         "linkB/fileB", "dirA/linkC/fileB"])
         _check(p.rglob("file*"), ["fileA", "dirB/fileB",
                                   "dirC/fileC", "dirC/dirD/fileD"])
+        if not os_helper.can_symlink():
+            _check(p.rglob("*/"), [
+                "dirA", "dirB", "dirC", "dirC/dirD", "dirE",
+            ])
+        else:
+            _check(p.rglob("*/"), [
+                "dirA", "dirA/linkC", "dirB", "dirB/linkD", "dirC",
+                "dirC/dirD", "dirE", "linkB",
+            ])
+
         p = P(BASE, "dirC")
         _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
         _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
@@ -2704,6 +2719,7 @@ def test_glob(self):
         P = self.cls
         p = P(BASE)
         self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
+        self.assertEqual(set(p.glob("*a\\")), { P(BASE, "dirA") })
         self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") })
         self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\FILEa"})
         self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"})
@@ -2712,6 +2728,7 @@ def test_rglob(self):
         P = self.cls
         p = P(BASE, "dirC")
         self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
+        self.assertEqual(set(p.rglob("*\\")), { P(BASE, "dirC/dirD") })
         self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\FILEd"})
 
     def test_expanduser(self):
diff --git a/Misc/NEWS.d/next/Library/2018-11-11-04-41-11.bpo-22276.Tt19TW.rst b/Misc/NEWS.d/next/Library/2018-11-11-04-41-11.bpo-22276.Tt19TW.rst
new file mode 100644
index 0000000000000..357c3f4ae0e6a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-11-11-04-41-11.bpo-22276.Tt19TW.rst
@@ -0,0 +1,4 @@
+:class:`~pathlib.Path` methods :meth:`~pathlib.Path.glob` and :meth:`~pathlib.Path.rglob` return only
+directories if *pattern* ends with a pathname components separator
+(``/`` or :data:`~os.sep`).
+Patch by Eisuke Kawashima.



More information about the Python-checkins mailing list