11
11
from test .support .os_helper import TESTFN
12
12
13
13
14
+ _tests_needing_posix = set ()
15
+ _tests_needing_windows = set ()
16
+ _tests_needing_symlinks = set ()
17
+
18
+
19
+ def needs_posix (fn ):
20
+ """Decorator that marks a test as requiring a POSIX-flavoured path class."""
21
+ _tests_needing_posix .add (fn .__name__ )
22
+ return fn
23
+
24
+ def needs_windows (fn ):
25
+ """Decorator that marks a test as requiring a Windows-flavoured path class."""
26
+ _tests_needing_windows .add (fn .__name__ )
27
+ return fn
28
+
29
+ def needs_symlinks (fn ):
30
+ """Decorator that marks a test as requiring a path class that supports symlinks."""
31
+ _tests_needing_symlinks .add (fn .__name__ )
32
+ return fn
33
+
34
+
14
35
class UnsupportedOperationTest (unittest .TestCase ):
15
36
def test_is_notimplemented (self ):
16
37
self .assertTrue (issubclass (UnsupportedOperation , NotImplementedError ))
@@ -115,6 +136,11 @@ class DummyPurePathTest(unittest.TestCase):
115
136
base = f'/this/path/kills/fascists/{ TESTFN } '
116
137
117
138
def setUp (self ):
139
+ name = self .id ().split ('.' )[- 1 ]
140
+ if name in _tests_needing_posix and self .cls .pathmod is not posixpath :
141
+ self .skipTest ('requires POSIX-flavoured path class' )
142
+ if name in _tests_needing_windows and self .cls .pathmod is posixpath :
143
+ self .skipTest ('requires Windows-flavoured path class' )
118
144
p = self .cls ('a' )
119
145
self .pathmod = p .pathmod
120
146
self .sep = self .pathmod .sep
@@ -888,6 +914,9 @@ class DummyPathTest(DummyPurePathTest):
888
914
889
915
def setUp (self ):
890
916
super ().setUp ()
917
+ name = self .id ().split ('.' )[- 1 ]
918
+ if name in _tests_needing_symlinks and not self .can_symlink :
919
+ self .skipTest ('requires symlinks' )
891
920
pathmod = self .cls .pathmod
892
921
p = self .cls (self .base )
893
922
p .mkdir (parents = True )
@@ -1045,9 +1074,8 @@ def test_iterdir(self):
1045
1074
expected += ['linkA' , 'linkB' , 'brokenLink' , 'brokenLinkLoop' ]
1046
1075
self .assertEqual (paths , { P (self .base , q ) for q in expected })
1047
1076
1077
+ @needs_symlinks
1048
1078
def test_iterdir_symlink (self ):
1049
- if not self .can_symlink :
1050
- self .skipTest ("symlinks required" )
1051
1079
# __iter__ on a symlink to a directory.
1052
1080
P = self .cls
1053
1081
p = P (self .base , 'linkB' )
@@ -1116,9 +1144,8 @@ def _check(path, pattern, case_sensitive, expected):
1116
1144
_check (path , "dirb/file*" , True , [])
1117
1145
_check (path , "dirb/file*" , False , ["dirB/fileB" ])
1118
1146
1147
+ @needs_symlinks
1119
1148
def test_glob_follow_symlinks_common (self ):
1120
- if not self .can_symlink :
1121
- self .skipTest ("symlinks required" )
1122
1149
def _check (path , glob , expected ):
1123
1150
actual = {path for path in path .glob (glob , follow_symlinks = True )
1124
1151
if path .parts .count ("linkD" ) <= 1 } # exclude symlink loop.
@@ -1144,9 +1171,8 @@ def _check(path, glob, expected):
1144
1171
_check (p , "dir*/*/../dirD/**/" , ["dirC/dirD/../dirD/" ])
1145
1172
_check (p , "*/dirD/**/" , ["dirC/dirD/" ])
1146
1173
1174
+ @needs_symlinks
1147
1175
def test_glob_no_follow_symlinks_common (self ):
1148
- if not self .can_symlink :
1149
- self .skipTest ("symlinks required" )
1150
1176
def _check (path , glob , expected ):
1151
1177
actual = {path for path in path .glob (glob , follow_symlinks = False )}
1152
1178
self .assertEqual (actual , { P (self .base , q ) for q in expected })
@@ -1210,9 +1236,8 @@ def _check(glob, expected):
1210
1236
_check (p .rglob ("*.txt" ), ["dirC/novel.txt" ])
1211
1237
_check (p .rglob ("*.*" ), ["dirC/novel.txt" ])
1212
1238
1239
+ @needs_symlinks
1213
1240
def test_rglob_follow_symlinks_common (self ):
1214
- if not self .can_symlink :
1215
- self .skipTest ("symlinks required" )
1216
1241
def _check (path , glob , expected ):
1217
1242
actual = {path for path in path .rglob (glob , follow_symlinks = True )
1218
1243
if path .parts .count ("linkD" ) <= 1 } # exclude symlink loop.
@@ -1243,9 +1268,8 @@ def _check(path, glob, expected):
1243
1268
_check (p , "*.txt" , ["dirC/novel.txt" ])
1244
1269
_check (p , "*.*" , ["dirC/novel.txt" ])
1245
1270
1271
+ @needs_symlinks
1246
1272
def test_rglob_no_follow_symlinks_common (self ):
1247
- if not self .can_symlink :
1248
- self .skipTest ("symlinks required" )
1249
1273
def _check (path , glob , expected ):
1250
1274
actual = {path for path in path .rglob (glob , follow_symlinks = False )}
1251
1275
self .assertEqual (actual , { P (self .base , q ) for q in expected })
@@ -1269,10 +1293,9 @@ def _check(path, glob, expected):
1269
1293
_check (p , "*.txt" , ["dirC/novel.txt" ])
1270
1294
_check (p , "*.*" , ["dirC/novel.txt" ])
1271
1295
1296
+ @needs_symlinks
1272
1297
def test_rglob_symlink_loop (self ):
1273
1298
# Don't get fooled by symlink loops (Issue #26012).
1274
- if not self .can_symlink :
1275
- self .skipTest ("symlinks required" )
1276
1299
P = self .cls
1277
1300
p = P (self .base )
1278
1301
given = set (p .rglob ('*' ))
@@ -1302,10 +1325,9 @@ def test_glob_dotdot(self):
1302
1325
self .assertEqual (set (p .glob ("xyzzy/.." )), set ())
1303
1326
self .assertEqual (set (p .glob ("/" .join ([".." ] * 50 ))), { P (self .base , * [".." ] * 50 )})
1304
1327
1328
+ @needs_symlinks
1305
1329
def test_glob_permissions (self ):
1306
1330
# See bpo-38894
1307
- if not self .can_symlink :
1308
- self .skipTest ("symlinks required" )
1309
1331
P = self .cls
1310
1332
base = P (self .base ) / 'permissions'
1311
1333
base .mkdir ()
@@ -1322,19 +1344,17 @@ def test_glob_permissions(self):
1322
1344
self .assertEqual (len (set (base .glob ("*/fileC" ))), 50 )
1323
1345
self .assertEqual (len (set (base .glob ("*/file*" ))), 50 )
1324
1346
1347
+ @needs_symlinks
1325
1348
def test_glob_long_symlink (self ):
1326
1349
# See gh-87695
1327
- if not self .can_symlink :
1328
- self .skipTest ("symlinks required" )
1329
1350
base = self .cls (self .base ) / 'long_symlink'
1330
1351
base .mkdir ()
1331
1352
bad_link = base / 'bad_link'
1332
1353
bad_link .symlink_to ("bad" * 200 )
1333
1354
self .assertEqual (sorted (base .glob ('**/*' )), [bad_link ])
1334
1355
1356
+ @needs_symlinks
1335
1357
def test_readlink (self ):
1336
- if not self .can_symlink :
1337
- self .skipTest ("symlinks required" )
1338
1358
P = self .cls (self .base )
1339
1359
self .assertEqual ((P / 'linkA' ).readlink (), self .cls ('fileA' ))
1340
1360
self .assertEqual ((P / 'brokenLink' ).readlink (),
@@ -1358,9 +1378,8 @@ def _check_resolve(self, p, expected, strict=True):
1358
1378
# This can be used to check both relative and absolute resolutions.
1359
1379
_check_resolve_relative = _check_resolve_absolute = _check_resolve
1360
1380
1381
+ @needs_symlinks
1361
1382
def test_resolve_common (self ):
1362
- if not self .can_symlink :
1363
- self .skipTest ("symlinks required" )
1364
1383
P = self .cls
1365
1384
p = P (self .base , 'foo' )
1366
1385
with self .assertRaises (OSError ) as cm :
@@ -1419,10 +1438,9 @@ def test_resolve_common(self):
1419
1438
# resolves to 'dirB/..' first before resolving to parent of dirB.
1420
1439
self ._check_resolve_relative (p , P (self .base , 'foo' , 'in' , 'spam' ), False )
1421
1440
1441
+ @needs_symlinks
1422
1442
def test_resolve_dot (self ):
1423
1443
# See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/
1424
- if not self .can_symlink :
1425
- self .skipTest ("symlinks required" )
1426
1444
pathmod = self .pathmod
1427
1445
p = self .cls (self .base )
1428
1446
p .joinpath ('0' ).symlink_to ('.' , target_is_directory = True )
@@ -1441,11 +1459,9 @@ def _check_symlink_loop(self, *args):
1441
1459
path .resolve (strict = True )
1442
1460
self .assertEqual (cm .exception .errno , errno .ELOOP )
1443
1461
1462
+ @needs_posix
1463
+ @needs_symlinks
1444
1464
def test_resolve_loop (self ):
1445
- if not self .can_symlink :
1446
- self .skipTest ("symlinks required" )
1447
- if self .cls .pathmod is not posixpath :
1448
- self .skipTest ("symlink loops work differently with concrete Windows paths" )
1449
1465
# Loops with relative symlinks.
1450
1466
self .cls (self .base , 'linkX' ).symlink_to ('linkX/inside' )
1451
1467
self ._check_symlink_loop (self .base , 'linkX' )
@@ -1487,9 +1503,8 @@ def test_stat(self):
1487
1503
self .assertEqual (statA .st_dev , statC .st_dev )
1488
1504
# other attributes not used by pathlib.
1489
1505
1506
+ @needs_symlinks
1490
1507
def test_stat_no_follow_symlinks (self ):
1491
- if not self .can_symlink :
1492
- self .skipTest ("symlinks required" )
1493
1508
p = self .cls (self .base ) / 'linkA'
1494
1509
st = p .stat ()
1495
1510
self .assertNotEqual (st , p .stat (follow_symlinks = False ))
@@ -1499,9 +1514,8 @@ def test_stat_no_follow_symlinks_nosymlink(self):
1499
1514
st = p .stat ()
1500
1515
self .assertEqual (st , p .stat (follow_symlinks = False ))
1501
1516
1517
+ @needs_symlinks
1502
1518
def test_lstat (self ):
1503
- if not self .can_symlink :
1504
- self .skipTest ("symlinks required" )
1505
1519
p = self .cls (self .base )/ 'linkA'
1506
1520
st = p .stat ()
1507
1521
self .assertNotEqual (st , p .lstat ())
@@ -1634,9 +1648,6 @@ def test_is_char_device_false(self):
1634
1648
self .assertIs ((P / 'fileA\x00 ' ).is_char_device (), False )
1635
1649
1636
1650
def _check_complex_symlinks (self , link0_target ):
1637
- if not self .can_symlink :
1638
- self .skipTest ("symlinks required" )
1639
-
1640
1651
# Test solving a non-looping chain of symlinks (issue #19887).
1641
1652
pathmod = self .pathmod
1642
1653
P = self .cls (self .base )
@@ -1682,12 +1693,15 @@ def _check_complex_symlinks(self, link0_target):
1682
1693
finally :
1683
1694
os .chdir (old_path )
1684
1695
1696
+ @needs_symlinks
1685
1697
def test_complex_symlinks_absolute (self ):
1686
1698
self ._check_complex_symlinks (self .base )
1687
1699
1700
+ @needs_symlinks
1688
1701
def test_complex_symlinks_relative (self ):
1689
1702
self ._check_complex_symlinks ('.' )
1690
1703
1704
+ @needs_symlinks
1691
1705
def test_complex_symlinks_relative_dot_dot (self ):
1692
1706
self ._check_complex_symlinks (self .pathmod .join ('dirA' , '..' ))
1693
1707
@@ -1803,9 +1817,8 @@ def test_walk_bottom_up(self):
1803
1817
raise AssertionError (f"Unexpected path: { path } " )
1804
1818
self .assertTrue (seen_testfn )
1805
1819
1820
+ @needs_symlinks
1806
1821
def test_walk_follow_symlinks (self ):
1807
- if not self .can_symlink :
1808
- self .skipTest ("symlinks required" )
1809
1822
self .setUpWalk ()
1810
1823
walk_it = self .walk_path .walk (follow_symlinks = True )
1811
1824
for root , dirs , files in walk_it :
@@ -1816,9 +1829,8 @@ def test_walk_follow_symlinks(self):
1816
1829
else :
1817
1830
self .fail ("Didn't follow symlink with follow_symlinks=True" )
1818
1831
1832
+ @needs_symlinks
1819
1833
def test_walk_symlink_location (self ):
1820
- if not self .can_symlink :
1821
- self .skipTest ("symlinks required" )
1822
1834
self .setUpWalk ()
1823
1835
# Tests whether symlinks end up in filenames or dirnames depending
1824
1836
# on the `follow_symlinks` argument.
0 commit comments