Skip to content

Commit 35e7b04

Browse files
committed
GH-89812: Make symlink support configurable in pathlib tests.
Adjust the pathlib tests to add a new `PathTest.can_symlink` class attribute, which allows us to enable or disable symlink support in tests. A (near-)future commit will add an `AbstractPath` class; its tests will hard-code the value to `True` or `False` depending on a stub subclass's capabilities.
1 parent 4a6c84f commit 35e7b04

File tree

1 file changed

+50
-34
lines changed

1 file changed

+50
-34
lines changed

Lib/test/test_pathlib.py

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,7 @@ class PathTest(unittest.TestCase):
15731573
"""Tests for the FS-accessing functionalities of the Path classes."""
15741574

15751575
cls = pathlib.Path
1576+
can_symlink = os_helper.can_symlink()
15761577

15771578
# (BASE)
15781579
# |
@@ -1616,7 +1617,7 @@ def cleanup():
16161617
with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
16171618
f.write(b"this is file D\n")
16181619
os.chmod(join('dirE'), 0)
1619-
if os_helper.can_symlink():
1620+
if self.can_symlink:
16201621
# Relative symlinks.
16211622
os.symlink('fileA', join('linkA'))
16221623
os.symlink('non-existing', join('brokenLink'))
@@ -1680,7 +1681,7 @@ def test_exists(self):
16801681
self.assertIs(True, (p / 'dirA').exists())
16811682
self.assertIs(True, (p / 'fileA').exists())
16821683
self.assertIs(False, (p / 'fileA' / 'bah').exists())
1683-
if os_helper.can_symlink():
1684+
if self.can_symlink:
16841685
self.assertIs(True, (p / 'linkA').exists())
16851686
self.assertIs(True, (p / 'linkB').exists())
16861687
self.assertIs(True, (p / 'linkB' / 'fileB').exists())
@@ -1747,12 +1748,13 @@ def test_iterdir(self):
17471748
it = p.iterdir()
17481749
paths = set(it)
17491750
expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
1750-
if os_helper.can_symlink():
1751+
if self.can_symlink:
17511752
expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop']
17521753
self.assertEqual(paths, { P(BASE, q) for q in expected })
17531754

1754-
@os_helper.skip_unless_symlink
17551755
def test_iterdir_symlink(self):
1756+
if not self.can_symlink:
1757+
self.skipTest("symlinks required")
17561758
# __iter__ on a symlink to a directory.
17571759
P = self.cls
17581760
p = P(BASE, 'linkB')
@@ -1780,23 +1782,23 @@ def _check(glob, expected):
17801782
_check(it, ["fileA"])
17811783
_check(p.glob("fileB"), [])
17821784
_check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
1783-
if not os_helper.can_symlink():
1785+
if not self.can_symlink:
17841786
_check(p.glob("*A"), ['dirA', 'fileA'])
17851787
else:
17861788
_check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
1787-
if not os_helper.can_symlink():
1789+
if not self.can_symlink:
17881790
_check(p.glob("*B/*"), ['dirB/fileB'])
17891791
else:
17901792
_check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
17911793
'linkB/fileB', 'linkB/linkD'])
1792-
if not os_helper.can_symlink():
1794+
if not self.can_symlink:
17931795
_check(p.glob("*/fileB"), ['dirB/fileB'])
17941796
else:
17951797
_check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
1796-
if os_helper.can_symlink():
1798+
if self.can_symlink:
17971799
_check(p.glob("brokenLink"), ['brokenLink'])
17981800

1799-
if not os_helper.can_symlink():
1801+
if not self.can_symlink:
18001802
_check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"])
18011803
else:
18021804
_check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"])
@@ -1818,8 +1820,9 @@ def _check(path, pattern, case_sensitive, expected):
18181820
_check(path, "dirb/file*", True, [])
18191821
_check(path, "dirb/file*", False, ["dirB/fileB"])
18201822

1821-
@os_helper.skip_unless_symlink
18221823
def test_glob_follow_symlinks_common(self):
1824+
if not self.can_symlink:
1825+
self.skipTest("symlinks required")
18231826
def _check(path, glob, expected):
18241827
actual = {path for path in path.glob(glob, follow_symlinks=True)
18251828
if "linkD" not in path.parent.parts} # exclude symlink loop.
@@ -1843,8 +1846,9 @@ def _check(path, glob, expected):
18431846
_check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD"])
18441847
_check(p, "*/dirD/**/", ["dirC/dirD"])
18451848

1846-
@os_helper.skip_unless_symlink
18471849
def test_glob_no_follow_symlinks_common(self):
1850+
if not self.can_symlink:
1851+
self.skipTest("symlinks required")
18481852
def _check(path, glob, expected):
18491853
actual = {path for path in path.glob(glob, follow_symlinks=False)}
18501854
self.assertEqual(actual, { P(BASE, q) for q in expected })
@@ -1876,14 +1880,14 @@ def _check(glob, expected):
18761880
_check(p.rglob("fileB"), ["dirB/fileB"])
18771881
_check(p.rglob("**/fileB"), ["dirB/fileB"])
18781882
_check(p.rglob("*/fileA"), [])
1879-
if not os_helper.can_symlink():
1883+
if not self.can_symlink:
18801884
_check(p.rglob("*/fileB"), ["dirB/fileB"])
18811885
else:
18821886
_check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB",
18831887
"linkB/fileB", "dirA/linkC/fileB"])
18841888
_check(p.rglob("file*"), ["fileA", "dirB/fileB",
18851889
"dirC/fileC", "dirC/dirD/fileD"])
1886-
if not os_helper.can_symlink():
1890+
if not self.can_symlink:
18871891
_check(p.rglob("*/"), [
18881892
"dirA", "dirB", "dirC", "dirC/dirD", "dirE",
18891893
])
@@ -1908,8 +1912,9 @@ def _check(glob, expected):
19081912
_check(p.rglob("*.txt"), ["dirC/novel.txt"])
19091913
_check(p.rglob("*.*"), ["dirC/novel.txt"])
19101914

1911-
@os_helper.skip_unless_symlink
19121915
def test_rglob_follow_symlinks_common(self):
1916+
if not self.can_symlink:
1917+
self.skipTest("symlinks required")
19131918
def _check(path, glob, expected):
19141919
actual = {path for path in path.rglob(glob, follow_symlinks=True)
19151920
if 'linkD' not in path.parent.parts} # exclude symlink loop.
@@ -1937,8 +1942,9 @@ def _check(path, glob, expected):
19371942
_check(p, "*.txt", ["dirC/novel.txt"])
19381943
_check(p, "*.*", ["dirC/novel.txt"])
19391944

1940-
@os_helper.skip_unless_symlink
19411945
def test_rglob_no_follow_symlinks_common(self):
1946+
if not self.can_symlink:
1947+
self.skipTest("symlinks required")
19421948
def _check(path, glob, expected):
19431949
actual = {path for path in path.rglob(glob, follow_symlinks=False)}
19441950
self.assertEqual(actual, { P(BASE, q) for q in expected })
@@ -1962,9 +1968,10 @@ def _check(path, glob, expected):
19621968
_check(p, "*.txt", ["dirC/novel.txt"])
19631969
_check(p, "*.*", ["dirC/novel.txt"])
19641970

1965-
@os_helper.skip_unless_symlink
19661971
def test_rglob_symlink_loop(self):
19671972
# Don't get fooled by symlink loops (Issue #26012).
1973+
if not self.can_symlink:
1974+
self.skipTest("symlinks required")
19681975
P = self.cls
19691976
p = P(BASE)
19701977
given = set(p.rglob('*'))
@@ -2011,9 +2018,10 @@ def test_glob_dotdot(self):
20112018
self.assertEqual(set(p.glob("xyzzy/..")), set())
20122019
self.assertEqual(set(p.glob("/".join([".."] * 50))), { P(BASE, *[".."] * 50)})
20132020

2014-
@os_helper.skip_unless_symlink
20152021
def test_glob_permissions(self):
20162022
# See bpo-38894
2023+
if not self.can_symlink:
2024+
self.skipTest("symlinks required")
20172025
P = self.cls
20182026
base = P(BASE) / 'permissions'
20192027
base.mkdir()
@@ -2031,9 +2039,10 @@ def test_glob_permissions(self):
20312039
self.assertEqual(len(set(base.glob("*/fileC"))), 50)
20322040
self.assertEqual(len(set(base.glob("*/file*"))), 50)
20332041

2034-
@os_helper.skip_unless_symlink
20352042
def test_glob_long_symlink(self):
20362043
# See gh-87695
2044+
if not self.can_symlink:
2045+
self.skipTest("symlinks required")
20372046
base = self.cls(BASE) / 'long_symlink'
20382047
base.mkdir()
20392048
bad_link = base / 'bad_link'
@@ -2051,8 +2060,9 @@ def test_glob_above_recursion_limit(self):
20512060
with set_recursion_limit(recursion_limit):
20522061
list(base.glob('**'))
20532062

2054-
@os_helper.skip_unless_symlink
20552063
def test_readlink(self):
2064+
if not self.can_symlink:
2065+
self.skipTest("symlinks required")
20562066
P = self.cls(BASE)
20572067
self.assertEqual((P / 'linkA').readlink(), self.cls('fileA'))
20582068
self.assertEqual((P / 'brokenLink').readlink(),
@@ -2075,8 +2085,9 @@ def _check_resolve(self, p, expected, strict=True):
20752085
# This can be used to check both relative and absolute resolutions.
20762086
_check_resolve_relative = _check_resolve_absolute = _check_resolve
20772087

2078-
@os_helper.skip_unless_symlink
20792088
def test_resolve_common(self):
2089+
if not self.can_symlink:
2090+
self.skipTest("symlinks required")
20802091
P = self.cls
20812092
p = P(BASE, 'foo')
20822093
with self.assertRaises(OSError) as cm:
@@ -2136,9 +2147,10 @@ def test_resolve_common(self):
21362147
# resolves to 'dirB/..' first before resolving to parent of dirB.
21372148
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
21382149

2139-
@os_helper.skip_unless_symlink
21402150
def test_resolve_dot(self):
21412151
# See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/
2152+
if not self.can_symlink:
2153+
self.skipTest("symlinks required")
21422154
p = self.cls(BASE)
21432155
self.dirlink('.', join('0'))
21442156
self.dirlink(os.path.join('0', '0'), join('1'))
@@ -2160,8 +2172,9 @@ def test_stat(self):
21602172
self.addCleanup(p.chmod, st.st_mode)
21612173
self.assertNotEqual(p.stat(), st)
21622174

2163-
@os_helper.skip_unless_symlink
21642175
def test_stat_no_follow_symlinks(self):
2176+
if not self.can_symlink:
2177+
self.skipTest("symlinks required")
21652178
p = self.cls(BASE) / 'linkA'
21662179
st = p.stat()
21672180
self.assertNotEqual(st, p.stat(follow_symlinks=False))
@@ -2171,8 +2184,9 @@ def test_stat_no_follow_symlinks_nosymlink(self):
21712184
st = p.stat()
21722185
self.assertEqual(st, p.stat(follow_symlinks=False))
21732186

2174-
@os_helper.skip_unless_symlink
21752187
def test_lstat(self):
2188+
if not self.can_symlink:
2189+
self.skipTest("symlinks required")
21762190
p = self.cls(BASE)/ 'linkA'
21772191
st = p.stat()
21782192
self.assertNotEqual(st, p.lstat())
@@ -2188,7 +2202,7 @@ def test_is_dir(self):
21882202
self.assertFalse((P / 'fileA').is_dir())
21892203
self.assertFalse((P / 'non-existing').is_dir())
21902204
self.assertFalse((P / 'fileA' / 'bah').is_dir())
2191-
if os_helper.can_symlink():
2205+
if self.can_symlink:
21922206
self.assertFalse((P / 'linkA').is_dir())
21932207
self.assertTrue((P / 'linkB').is_dir())
21942208
self.assertFalse((P/ 'brokenLink').is_dir(), False)
@@ -2201,7 +2215,7 @@ def test_is_file(self):
22012215
self.assertFalse((P / 'dirA').is_file())
22022216
self.assertFalse((P / 'non-existing').is_file())
22032217
self.assertFalse((P / 'fileA' / 'bah').is_file())
2204-
if os_helper.can_symlink():
2218+
if self.can_symlink:
22052219
self.assertTrue((P / 'linkA').is_file())
22062220
self.assertFalse((P / 'linkB').is_file())
22072221
self.assertFalse((P/ 'brokenLink').is_file())
@@ -2219,7 +2233,7 @@ def test_is_mount(self):
22192233
self.assertFalse((P / 'non-existing').is_mount())
22202234
self.assertFalse((P / 'fileA' / 'bah').is_mount())
22212235
self.assertTrue(R.is_mount())
2222-
if os_helper.can_symlink():
2236+
if self.can_symlink:
22232237
self.assertFalse((P / 'linkA').is_mount())
22242238
self.assertIs((R / '\udfff').is_mount(), False)
22252239

@@ -2229,13 +2243,13 @@ def test_is_symlink(self):
22292243
self.assertFalse((P / 'dirA').is_symlink())
22302244
self.assertFalse((P / 'non-existing').is_symlink())
22312245
self.assertFalse((P / 'fileA' / 'bah').is_symlink())
2232-
if os_helper.can_symlink():
2246+
if self.can_symlink:
22332247
self.assertTrue((P / 'linkA').is_symlink())
22342248
self.assertTrue((P / 'linkB').is_symlink())
22352249
self.assertTrue((P/ 'brokenLink').is_symlink())
22362250
self.assertIs((P / 'fileA\udfff').is_file(), False)
22372251
self.assertIs((P / 'fileA\x00').is_file(), False)
2238-
if os_helper.can_symlink():
2252+
if self.can_symlink:
22392253
self.assertIs((P / 'linkA\udfff').is_file(), False)
22402254
self.assertIs((P / 'linkA\x00').is_file(), False)
22412255

@@ -2292,6 +2306,9 @@ def test_parts_interning(self):
22922306
self.assertIs(p.parts[2], q.parts[3])
22932307

22942308
def _check_complex_symlinks(self, link0_target):
2309+
if not self.can_symlink:
2310+
self.skipTest("symlinks required")
2311+
22952312
# Test solving a non-looping chain of symlinks (issue #19887).
22962313
P = self.cls(BASE)
22972314
self.dirlink(os.path.join('link0', 'link0'), join('link1'))
@@ -2332,15 +2349,12 @@ def _check_complex_symlinks(self, link0_target):
23322349
finally:
23332350
os.chdir(old_path)
23342351

2335-
@os_helper.skip_unless_symlink
23362352
def test_complex_symlinks_absolute(self):
23372353
self._check_complex_symlinks(BASE)
23382354

2339-
@os_helper.skip_unless_symlink
23402355
def test_complex_symlinks_relative(self):
23412356
self._check_complex_symlinks('.')
23422357

2343-
@os_helper.skip_unless_symlink
23442358
def test_complex_symlinks_relative_dot_dot(self):
23452359
self._check_complex_symlinks(os.path.join('dirA', '..'))
23462360

@@ -2444,7 +2458,7 @@ def with_segments(self, *pathsegments):
24442458
self.assertEqual(42, p.with_segments('~').expanduser().session_id)
24452459
self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id)
24462460
self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id)
2447-
if os_helper.can_symlink():
2461+
if self.can_symlink:
24482462
self.assertEqual(42, (p / 'linkA').readlink().session_id)
24492463
for path in p.iterdir():
24502464
self.assertEqual(42, path.session_id)
@@ -2765,8 +2779,9 @@ def my_mkdir(path, mode=0o777):
27652779
self.assertNotIn(str(p12), concurrently_created)
27662780
self.assertTrue(p.exists())
27672781

2768-
@os_helper.skip_unless_symlink
27692782
def test_symlink_to(self):
2783+
if not self.can_symlink:
2784+
self.skipTest("symlinks required")
27702785
P = self.cls(BASE)
27712786
target = P / 'fileA'
27722787
# Symlinking a path target.
@@ -3149,8 +3164,9 @@ def test_touch_mode(self):
31493164
st = os.stat(join('masked_new_file'))
31503165
self.assertEqual(stat.S_IMODE(st.st_mode), 0o750)
31513166

3152-
@os_helper.skip_unless_symlink
31533167
def test_resolve_loop(self):
3168+
if not self.can_symlink:
3169+
self.skipTest("symlinks required")
31543170
# Loops with relative symlinks.
31553171
os.symlink('linkX/inside', join('linkX'))
31563172
self._check_symlink_loop(BASE, 'linkX')

0 commit comments

Comments
 (0)