Skip to content

Commit 2db28d9

Browse files
committed
Revert "Deprecate follow_symlinks=None"
This reverts commit 8704d33.
1 parent ce7973f commit 2db28d9

File tree

3 files changed

+73
-102
lines changed

3 files changed

+73
-102
lines changed

Doc/library/pathlib.rst

+6-14
Original file line numberDiff line numberDiff line change
@@ -876,9 +876,9 @@ call fails (for example because the path doesn't exist).
876876
PosixPath('setup.py'),
877877
PosixPath('test_pathlib.py')]
878878

879-
By default, :meth:`Path.glob` emits a deprecation warning and follows
880-
symlinks except when expanding "``**``" wildcards. Set *follow_symlinks*
881-
to true to always follow symlinks, or false to treat all symlinks as files.
879+
By default, :meth:`Path.glob` follows symlinks except when expanding
880+
"``**``" wildcards. Set *follow_symlinks* to true to always follow
881+
symlinks, or false to treat all symlinks as files.
882882

883883
.. note::
884884
Using the "``**``" pattern in large directory trees may consume
@@ -893,10 +893,6 @@ call fails (for example because the path doesn't exist).
893893
.. versionchanged:: 3.12
894894
The *follow_symlinks* parameter was added.
895895

896-
.. deprecated-removed:: 3.12 3.14
897-
898-
Setting *follow_symlinks* to ``None`` (e.g. by omitting it) is deprecated.
899-
900896
.. method:: Path.group()
901897

902898
Return the name of the group owning the file. :exc:`KeyError` is raised
@@ -1295,9 +1291,9 @@ call fails (for example because the path doesn't exist).
12951291
PosixPath('setup.py'),
12961292
PosixPath('test_pathlib.py')]
12971293

1298-
By default, :meth:`Path.rglob` emits a deprecation warning and follows
1299-
symlinks except when expanding "``**``" wildcards. Set *follow_symlinks*
1300-
to true to always follow symlinks, or false to treat all symlinks as files.
1294+
By default, :meth:`Path.rglob` follows symlinks except when expanding
1295+
"``**``" wildcards. Set *follow_symlinks* to true to always follow
1296+
symlinks, or false to treat all symlinks as files.
13011297

13021298
.. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob
13031299

@@ -1308,10 +1304,6 @@ call fails (for example because the path doesn't exist).
13081304
.. versionchanged:: 3.12
13091305
The *follow_symlinks* parameter was added.
13101306

1311-
.. deprecated-removed:: 3.12 3.14
1312-
1313-
Setting *follow_symlinks* to ``None`` (e.g. by omitting it) is deprecated.
1314-
13151307
.. method:: Path.rmdir()
13161308

13171309
Remove this directory. The directory must be empty.

Lib/pathlib.py

-14
Original file line numberDiff line numberDiff line change
@@ -826,13 +826,6 @@ def glob(self, pattern, *, follow_symlinks=None):
826826
kind, including directories) matching the given relative pattern.
827827
"""
828828
sys.audit("pathlib.Path.glob", self, pattern)
829-
if follow_symlinks is None:
830-
msg = ("pathlib.Path.glob(pattern, follow_symlinks=None) is "
831-
"deprecated and scheduled for removal in Python {remove}. "
832-
"The follow_symlinks keyword-only argument should be set "
833-
"to either True or False.")
834-
warnings._deprecated("pathlib.Path.glob(pattern, follow_symlinks=None)",
835-
msg, remove=(3, 14))
836829
if not pattern:
837830
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
838831
drv, root, pattern_parts = self._parse_path(pattern)
@@ -850,13 +843,6 @@ def rglob(self, pattern, *, follow_symlinks=None):
850843
this subtree.
851844
"""
852845
sys.audit("pathlib.Path.rglob", self, pattern)
853-
if follow_symlinks is None:
854-
msg = ("pathlib.Path.rglob(pattern, follow_symlinks=None) is "
855-
"deprecated and scheduled for removal in Python {remove}. "
856-
"The follow_symlinks keyword-only argument should be set "
857-
"to either True or False.")
858-
warnings._deprecated("pathlib.Path.rglob(pattern, follow_symlinks=None)", msg,
859-
remove=(3, 14))
860846
drv, root, pattern_parts = self._parse_path(pattern)
861847
if drv or root:
862848
raise NotImplementedError("Non-relative patterns are unsupported")

Lib/test/test_pathlib.py

+67-74
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import tempfile
1212
import unittest
1313
from unittest import mock
14-
import warnings
1514

1615
from test.support import import_helper
1716
from test.support import set_recursion_limit
@@ -1787,44 +1786,41 @@ def test_iterdir_nodir(self):
17871786
errno.ENOENT, errno.EINVAL))
17881787

17891788
def test_glob_common(self):
1790-
def _check(path, glob, expected):
1791-
with self.assertWarns(DeprecationWarning):
1792-
actual = {q for q in path.glob(glob)}
1793-
self.assertEqual(actual, { P(BASE, q) for q in expected })
1789+
def _check(glob, expected):
1790+
self.assertEqual(set(glob), { P(BASE, q) for q in expected })
17941791
P = self.cls
17951792
p = P(BASE)
1796-
with self.assertWarns(DeprecationWarning):
1797-
it = p.glob("fileA")
1798-
self.assertIsInstance(it, collections.abc.Iterator)
1799-
self.assertEqual(set(it), { P(BASE, "fileA") })
1800-
_check(p, "fileB", [])
1801-
_check(p, "dir*/file*", ["dirB/fileB", "dirC/fileC"])
1793+
it = p.glob("fileA")
1794+
self.assertIsInstance(it, collections.abc.Iterator)
1795+
_check(it, ["fileA"])
1796+
_check(p.glob("fileB"), [])
1797+
_check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
18021798
if not os_helper.can_symlink():
1803-
_check(p, "*A", ['dirA', 'fileA'])
1799+
_check(p.glob("*A"), ['dirA', 'fileA'])
18041800
else:
1805-
_check(p, "*A", ['dirA', 'fileA', 'linkA'])
1801+
_check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
18061802
if not os_helper.can_symlink():
1807-
_check(p, "*B/*", ['dirB/fileB'])
1803+
_check(p.glob("*B/*"), ['dirB/fileB'])
18081804
else:
1809-
_check(p, "*B/*", ['dirB/fileB', 'dirB/linkD',
1805+
_check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
18101806
'linkB/fileB', 'linkB/linkD'])
18111807
if not os_helper.can_symlink():
1812-
_check(p, "*/fileB", ['dirB/fileB'])
1808+
_check(p.glob("*/fileB"), ['dirB/fileB'])
18131809
else:
1814-
_check(p, "*/fileB", ['dirB/fileB', 'linkB/fileB'])
1810+
_check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
18151811
if os_helper.can_symlink():
1816-
_check(p, "brokenLink", ['brokenLink'])
1812+
_check(p.glob("brokenLink"), ['brokenLink'])
18171813

18181814
if not os_helper.can_symlink():
1819-
_check(p, "*/", ["dirA", "dirB", "dirC", "dirE"])
1815+
_check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"])
18201816
else:
1821-
_check(p, "*/", ["dirA", "dirB", "dirC", "dirE", "linkB"])
1817+
_check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"])
18221818

18231819
@os_helper.skip_unless_symlink
18241820
def test_glob_follow_symlinks_common(self):
18251821
def _check(path, glob, expected):
1826-
actual = {q for q in path.glob(glob, follow_symlinks=True)
1827-
if "linkD" not in q.parent.parts} # exclude symlink loop.
1822+
actual = {path for path in path.glob(glob, follow_symlinks=True)
1823+
if "linkD" not in path.parent.parts} # exclude symlink loop.
18281824
self.assertEqual(actual, { P(BASE, q) for q in expected })
18291825
P = self.cls
18301826
p = P(BASE)
@@ -1838,7 +1834,7 @@ def _check(path, glob, expected):
18381834
@os_helper.skip_unless_symlink
18391835
def test_glob_no_follow_symlinks_common(self):
18401836
def _check(path, glob, expected):
1841-
actual = {q for q in path.glob(glob, follow_symlinks=False)}
1837+
actual = {path for path in path.glob(glob, follow_symlinks=False)}
18421838
self.assertEqual(actual, { P(BASE, q) for q in expected })
18431839
P = self.cls
18441840
p = P(BASE)
@@ -1850,46 +1846,43 @@ def _check(path, glob, expected):
18501846
_check(p, "*/", ["dirA", "dirB", "dirC", "dirE"])
18511847

18521848
def test_rglob_common(self):
1853-
def _check(path, glob, expected):
1854-
with self.assertWarns(DeprecationWarning):
1855-
actual = {q for q in path.rglob(glob)}
1856-
self.assertEqual(actual, { P(BASE, q) for q in expected })
1849+
def _check(glob, expected):
1850+
self.assertEqual(set(glob), { P(BASE, q) for q in expected })
18571851
P = self.cls
18581852
p = P(BASE)
1859-
with self.assertWarns(DeprecationWarning):
1860-
it = p.rglob("fileA")
1861-
self.assertIsInstance(it, collections.abc.Iterator)
1862-
self.assertEqual(set(it), { P(BASE, "fileA") })
1863-
_check(p, "fileB", ["dirB/fileB"])
1864-
_check(p, "*/fileA", [])
1853+
it = p.rglob("fileA")
1854+
self.assertIsInstance(it, collections.abc.Iterator)
1855+
_check(it, ["fileA"])
1856+
_check(p.rglob("fileB"), ["dirB/fileB"])
1857+
_check(p.rglob("*/fileA"), [])
18651858
if not os_helper.can_symlink():
1866-
_check(p, "*/fileB", ["dirB/fileB"])
1859+
_check(p.rglob("*/fileB"), ["dirB/fileB"])
18671860
else:
1868-
_check(p, "*/fileB", ["dirB/fileB", "dirB/linkD/fileB",
1861+
_check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB",
18691862
"linkB/fileB", "dirA/linkC/fileB"])
1870-
_check(p, "file*", ["fileA", "dirB/fileB",
1863+
_check(p.rglob("file*"), ["fileA", "dirB/fileB",
18711864
"dirC/fileC", "dirC/dirD/fileD"])
18721865
if not os_helper.can_symlink():
1873-
_check(p, "*/", [
1866+
_check(p.rglob("*/"), [
18741867
"dirA", "dirB", "dirC", "dirC/dirD", "dirE",
18751868
])
18761869
else:
1877-
_check(p, "*/", [
1870+
_check(p.rglob("*/"), [
18781871
"dirA", "dirA/linkC", "dirB", "dirB/linkD", "dirC",
18791872
"dirC/dirD", "dirE", "linkB",
18801873
])
1881-
_check(p, "", ["", "dirA", "dirB", "dirC", "dirE", "dirC/dirD"])
1874+
_check(p.rglob(""), ["", "dirA", "dirB", "dirC", "dirE", "dirC/dirD"])
18821875

18831876
p = P(BASE, "dirC")
1884-
_check(p, "*", ["dirC/fileC", "dirC/novel.txt",
1877+
_check(p.rglob("*"), ["dirC/fileC", "dirC/novel.txt",
18851878
"dirC/dirD", "dirC/dirD/fileD"])
1886-
_check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"])
1887-
_check(p, "*/*", ["dirC/dirD/fileD"])
1888-
_check(p, "*/", ["dirC/dirD"])
1889-
_check(p, "", ["dirC", "dirC/dirD"])
1879+
_check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
1880+
_check(p.rglob("*/*"), ["dirC/dirD/fileD"])
1881+
_check(p.rglob("*/"), ["dirC/dirD"])
1882+
_check(p.rglob(""), ["dirC", "dirC/dirD"])
18901883
# gh-91616, a re module regression
1891-
_check(p, "*.txt", ["dirC/novel.txt"])
1892-
_check(p, "*.*", ["dirC/novel.txt"])
1884+
_check(p.rglob("*.txt"), ["dirC/novel.txt"])
1885+
_check(p.rglob("*.*"), ["dirC/novel.txt"])
18931886

18941887
@os_helper.skip_unless_symlink
18951888
def test_rglob_follow_symlinks_common(self):
@@ -1950,7 +1943,7 @@ def test_rglob_symlink_loop(self):
19501943
# Don't get fooled by symlink loops (Issue #26012).
19511944
P = self.cls
19521945
p = P(BASE)
1953-
given = set(p.rglob('*', follow_symlinks=False))
1946+
given = set(p.rglob('*'))
19541947
expect = {'brokenLink',
19551948
'dirA', 'dirA/linkC',
19561949
'dirB', 'dirB/fileB', 'dirB/linkD',
@@ -1971,10 +1964,10 @@ def test_glob_many_open_files(self):
19711964
p = P(base, *(['d']*depth))
19721965
p.mkdir(parents=True)
19731966
pattern = '/'.join(['*'] * depth)
1974-
iters = [base.glob(pattern, follow_symlinks=True) for j in range(100)]
1967+
iters = [base.glob(pattern) for j in range(100)]
19751968
for it in iters:
19761969
self.assertEqual(next(it), p)
1977-
iters = [base.rglob('d', follow_symlinks=True) for j in range(100)]
1970+
iters = [base.rglob('d') for j in range(100)]
19781971
p = base
19791972
for i in range(depth):
19801973
p = p / 'd'
@@ -1985,14 +1978,14 @@ def test_glob_dotdot(self):
19851978
# ".." is not special in globs.
19861979
P = self.cls
19871980
p = P(BASE)
1988-
self.assertEqual(set(p.glob("..", follow_symlinks=True)), { P(BASE, "..") })
1989-
self.assertEqual(set(p.glob("../..", follow_symlinks=True)), { P(BASE, "..", "..") })
1990-
self.assertEqual(set(p.glob("dirA/..", follow_symlinks=True)), { P(BASE, "dirA", "..") })
1991-
self.assertEqual(set(p.glob("dirA/../file*", follow_symlinks=True)), { P(BASE, "dirA/../fileA") })
1992-
self.assertEqual(set(p.glob("dirA/../file*/..", follow_symlinks=True)), set())
1993-
self.assertEqual(set(p.glob("../xyzzy", follow_symlinks=True)), set())
1994-
self.assertEqual(set(p.glob("xyzzy/..", follow_symlinks=True)), set())
1995-
self.assertEqual(set(p.glob("/".join([".."] * 50), follow_symlinks=True)), { P(BASE, *[".."] * 50)})
1981+
self.assertEqual(set(p.glob("..")), { P(BASE, "..") })
1982+
self.assertEqual(set(p.glob("../..")), { P(BASE, "..", "..") })
1983+
self.assertEqual(set(p.glob("dirA/..")), { P(BASE, "dirA", "..") })
1984+
self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
1985+
self.assertEqual(set(p.glob("dirA/../file*/..")), set())
1986+
self.assertEqual(set(p.glob("../xyzzy")), set())
1987+
self.assertEqual(set(p.glob("xyzzy/..")), set())
1988+
self.assertEqual(set(p.glob("/".join([".."] * 50))), { P(BASE, *[".."] * 50)})
19961989

19971990
@os_helper.skip_unless_symlink
19981991
def test_glob_permissions(self):
@@ -2022,11 +2015,11 @@ def my_scandir(path):
20222015
return contextlib.nullcontext(entries)
20232016

20242017
with mock.patch("os.scandir", my_scandir):
2025-
self.assertEqual(len(set(base.glob("*", follow_symlinks=True))), 3)
2018+
self.assertEqual(len(set(base.glob("*"))), 3)
20262019
subdir.mkdir()
2027-
self.assertEqual(len(set(base.glob("*", follow_symlinks=True))), 4)
2020+
self.assertEqual(len(set(base.glob("*"))), 4)
20282021
subdir.chmod(000)
2029-
self.assertEqual(len(set(base.glob("*", follow_symlinks=True))), 4)
2022+
self.assertEqual(len(set(base.glob("*"))), 4)
20302023

20312024
def _check_resolve(self, p, expected, strict=True):
20322025
q = p.resolve(strict)
@@ -2970,7 +2963,7 @@ def test_unsupported_flavour(self):
29702963
def test_glob_empty_pattern(self):
29712964
p = self.cls()
29722965
with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'):
2973-
list(p.glob('', follow_symlinks=True))
2966+
list(p.glob(''))
29742967

29752968

29762969
@only_posix
@@ -3063,18 +3056,18 @@ def test_resolve_loop(self):
30633056
def test_glob(self):
30643057
P = self.cls
30653058
p = P(BASE)
3066-
given = set(p.glob("FILEa", follow_symlinks=True))
3059+
given = set(p.glob("FILEa"))
30673060
expect = set() if not os_helper.fs_is_case_insensitive(BASE) else given
30683061
self.assertEqual(given, expect)
3069-
self.assertEqual(set(p.glob("FILEa*", follow_symlinks=True)), set())
3062+
self.assertEqual(set(p.glob("FILEa*")), set())
30703063

30713064
def test_rglob(self):
30723065
P = self.cls
30733066
p = P(BASE, "dirC")
3074-
given = set(p.rglob("FILEd", follow_symlinks=True))
3067+
given = set(p.rglob("FILEd"))
30753068
expect = set() if not os_helper.fs_is_case_insensitive(BASE) else given
30763069
self.assertEqual(given, expect)
3077-
self.assertEqual(set(p.rglob("FILEd*", follow_symlinks=True)), set())
3070+
self.assertEqual(set(p.rglob("FILEd*")), set())
30783071

30793072
@unittest.skipUnless(hasattr(pwd, 'getpwall'),
30803073
'pwd module does not expose getpwall()')
@@ -3137,7 +3130,7 @@ def test_expanduser(self):
31373130
"Bad file descriptor in /dev/fd affects only macOS")
31383131
def test_handling_bad_descriptor(self):
31393132
try:
3140-
file_descriptors = list(pathlib.Path('/dev/fd').rglob("*", follow_symlinks=True))[3:]
3133+
file_descriptors = list(pathlib.Path('/dev/fd').rglob("*"))[3:]
31413134
if not file_descriptors:
31423135
self.skipTest("no file descriptors - issue was not reproduced")
31433136
# Checking all file descriptors because there is no guarantee
@@ -3209,18 +3202,18 @@ def test_absolute(self):
32093202
def test_glob(self):
32103203
P = self.cls
32113204
p = P(BASE)
3212-
self.assertEqual(set(p.glob("FILEa", follow_symlinks=True)), { P(BASE, "fileA") })
3213-
self.assertEqual(set(p.glob("*a\\", follow_symlinks=True)), { P(BASE, "dirA") })
3214-
self.assertEqual(set(p.glob("F*a", follow_symlinks=True)), { P(BASE, "fileA") })
3215-
self.assertEqual(set(map(str, p.glob("FILEa", follow_symlinks=True))), {f"{p}\\fileA"})
3216-
self.assertEqual(set(map(str, p.glob("F*a", follow_symlinks=True))), {f"{p}\\fileA"})
3205+
self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
3206+
self.assertEqual(set(p.glob("*a\\")), { P(BASE, "dirA") })
3207+
self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") })
3208+
self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\fileA"})
3209+
self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"})
32173210

32183211
def test_rglob(self):
32193212
P = self.cls
32203213
p = P(BASE, "dirC")
3221-
self.assertEqual(set(p.rglob("FILEd", follow_symlinks=True)), { P(BASE, "dirC/dirD/fileD") })
3222-
self.assertEqual(set(p.rglob("*\\", follow_symlinks=True)), { P(BASE, "dirC/dirD") })
3223-
self.assertEqual(set(map(str, p.rglob("FILEd", follow_symlinks=True))), {f"{p}\\dirD\\fileD"})
3214+
self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
3215+
self.assertEqual(set(p.rglob("*\\")), { P(BASE, "dirC/dirD") })
3216+
self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\fileD"})
32243217

32253218
def test_expanduser(self):
32263219
P = self.cls

0 commit comments

Comments
 (0)