Skip to content

Commit 1dce007

Browse files
authored
pathlib ABCs: follow all symlinks in PathBase.glob() (#116293)
Switch the default value of *follow_symlinks* from `None` to `True` in `pathlib._abc.PathBase.glob()` and `rglob()`. This speeds up recursive globbing. No change to the public pathlib classes.
1 parent 3383d6a commit 1dce007

File tree

2 files changed

+34
-39
lines changed

2 files changed

+34
-39
lines changed

Lib/pathlib/_abc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ def _make_child_direntry(self, entry):
789789
def _make_child_relpath(self, name):
790790
return self.joinpath(name)
791791

792-
def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
792+
def glob(self, pattern, *, case_sensitive=None, follow_symlinks=True):
793793
"""Iterate over this subtree and yield all existing files (of any
794794
kind, including directories) matching the given relative pattern.
795795
"""
@@ -846,7 +846,7 @@ def glob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
846846
paths = _select_children(paths, bool(stack), follow_symlinks, match)
847847
return paths
848848

849-
def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=None):
849+
def rglob(self, pattern, *, case_sensitive=None, follow_symlinks=True):
850850
"""Recursively yield all existing files (of any kind, including
851851
directories) matching the given relative pattern, anywhere in
852852
this subtree.

Lib/test/test_pathlib/test_pathlib_abc.py

+32-37
Original file line numberDiff line numberDiff line change
@@ -1844,51 +1844,46 @@ def _check(path, glob, expected):
18441844
_check(p, "*/dirD/**", ["dirC/dirD/", "dirC/dirD/fileD"])
18451845
_check(p, "*/dirD/**/", ["dirC/dirD/"])
18461846

1847-
def test_rglob_common(self):
1848-
def _check(glob, expected):
1849-
self.assertEqual(set(glob), {P(self.base, q) for q in expected})
1847+
def test_rglob_follow_symlinks_none(self):
1848+
def _check(path, glob, expected):
1849+
actual = set(path.rglob(glob, follow_symlinks=None))
1850+
self.assertEqual(actual, { P(self.base, q) for q in expected })
18501851
P = self.cls
18511852
p = P(self.base)
18521853
it = p.rglob("fileA")
18531854
self.assertIsInstance(it, collections.abc.Iterator)
1854-
_check(it, ["fileA"])
1855-
_check(p.rglob("fileB"), ["dirB/fileB"])
1856-
_check(p.rglob("**/fileB"), ["dirB/fileB"])
1857-
_check(p.rglob("*/fileA"), [])
1858-
if not self.can_symlink:
1859-
_check(p.rglob("*/fileB"), ["dirB/fileB"])
1860-
else:
1861-
_check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB",
1862-
"linkB/fileB", "dirA/linkC/fileB"])
1863-
_check(p.rglob("file*"), ["fileA", "dirB/fileB",
1864-
"dirC/fileC", "dirC/dirD/fileD"])
1865-
if not self.can_symlink:
1866-
_check(p.rglob("*/"), [
1867-
"dirA/", "dirB/", "dirC/", "dirC/dirD/", "dirE/",
1868-
])
1869-
else:
1870-
_check(p.rglob("*/"), [
1855+
_check(p, "fileA", ["fileA"])
1856+
_check(p, "fileB", ["dirB/fileB"])
1857+
_check(p, "**/fileB", ["dirB/fileB"])
1858+
_check(p, "*/fileA", [])
1859+
1860+
if self.can_symlink:
1861+
_check(p, "*/fileB", ["dirB/fileB", "dirB/linkD/fileB",
1862+
"linkB/fileB", "dirA/linkC/fileB"])
1863+
_check(p, "*/", [
18711864
"dirA/", "dirA/linkC/", "dirB/", "dirB/linkD/", "dirC/",
1872-
"dirC/dirD/", "dirE/", "linkB/",
1873-
])
1874-
_check(p.rglob(""), ["", "dirA/", "dirB/", "dirC/", "dirE/", "dirC/dirD/"])
1865+
"dirC/dirD/", "dirE/", "linkB/"])
1866+
else:
1867+
_check(p, "*/fileB", ["dirB/fileB"])
1868+
_check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirC/dirD/", "dirE/"])
18751869

1870+
_check(p, "file*", ["fileA", "dirB/fileB", "dirC/fileC", "dirC/dirD/fileD"])
1871+
_check(p, "", ["", "dirA/", "dirB/", "dirC/", "dirE/", "dirC/dirD/"])
18761872
p = P(self.base, "dirC")
1877-
_check(p.rglob("*"), ["dirC/fileC", "dirC/novel.txt",
1873+
_check(p, "*", ["dirC/fileC", "dirC/novel.txt",
18781874
"dirC/dirD", "dirC/dirD/fileD"])
1879-
_check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1880-
_check(p.rglob("**/file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1881-
_check(p.rglob("dir*/**"), ["dirC/dirD/", "dirC/dirD/fileD"])
1882-
_check(p.rglob("dir*/**/"), ["dirC/dirD/"])
1883-
_check(p.rglob("*/*"), ["dirC/dirD/fileD"])
1884-
_check(p.rglob("*/"), ["dirC/dirD/"])
1885-
_check(p.rglob(""), ["dirC/", "dirC/dirD/"])
1886-
_check(p.rglob("**"), [
1887-
"dirC/", "dirC/fileC", "dirC/dirD", "dirC/dirD/fileD", "dirC/novel.txt"])
1888-
_check(p.rglob("**/"), ["dirC/", "dirC/dirD/"])
1875+
_check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"])
1876+
_check(p, "**/file*", ["dirC/fileC", "dirC/dirD/fileD"])
1877+
_check(p, "dir*/**", ["dirC/dirD/", "dirC/dirD/fileD"])
1878+
_check(p, "dir*/**/", ["dirC/dirD/"])
1879+
_check(p, "*/*", ["dirC/dirD/fileD"])
1880+
_check(p, "*/", ["dirC/dirD/"])
1881+
_check(p, "", ["dirC/", "dirC/dirD/"])
1882+
_check(p, "**", ["dirC/", "dirC/fileC", "dirC/dirD", "dirC/dirD/fileD", "dirC/novel.txt"])
1883+
_check(p, "**/", ["dirC/", "dirC/dirD/"])
18891884
# gh-91616, a re module regression
1890-
_check(p.rglob("*.txt"), ["dirC/novel.txt"])
1891-
_check(p.rglob("*.*"), ["dirC/novel.txt"])
1885+
_check(p, "*.txt", ["dirC/novel.txt"])
1886+
_check(p, "*.*", ["dirC/novel.txt"])
18921887

18931888
@needs_posix
18941889
def test_rglob_posix(self):
@@ -1969,7 +1964,7 @@ def test_rglob_symlink_loop(self):
19691964
# Don't get fooled by symlink loops (Issue #26012).
19701965
P = self.cls
19711966
p = P(self.base)
1972-
given = set(p.rglob('*'))
1967+
given = set(p.rglob('*', follow_symlinks=None))
19731968
expect = {'brokenLink',
19741969
'dirA', 'dirA/linkC',
19751970
'dirB', 'dirB/fileB', 'dirB/linkD',

0 commit comments

Comments
 (0)