1import collections 2import io 3import os 4import errno 5import stat 6import unittest 7 8from pathlib._abc import UnsupportedOperation, ParserBase, PurePathBase, PathBase 9import posixpath 10 11from test.support import is_wasi 12from test.support.os_helper import TESTFN 13 14 15_tests_needing_posix = set() 16_tests_needing_windows = set() 17_tests_needing_symlinks = set() 18 19 20def needs_posix(fn): 21 """Decorator that marks a test as requiring a POSIX-flavoured path class.""" 22 _tests_needing_posix.add(fn.__name__) 23 return fn 24 25def needs_windows(fn): 26 """Decorator that marks a test as requiring a Windows-flavoured path class.""" 27 _tests_needing_windows.add(fn.__name__) 28 return fn 29 30def needs_symlinks(fn): 31 """Decorator that marks a test as requiring a path class that supports symlinks.""" 32 _tests_needing_symlinks.add(fn.__name__) 33 return fn 34 35 36class UnsupportedOperationTest(unittest.TestCase): 37 def test_is_notimplemented(self): 38 self.assertTrue(issubclass(UnsupportedOperation, NotImplementedError)) 39 self.assertTrue(isinstance(UnsupportedOperation(), NotImplementedError)) 40 41 42class ParserBaseTest(unittest.TestCase): 43 cls = ParserBase 44 45 def test_unsupported_operation(self): 46 m = self.cls() 47 e = UnsupportedOperation 48 with self.assertRaises(e): 49 m.sep 50 self.assertRaises(e, m.join, 'foo') 51 self.assertRaises(e, m.split, 'foo') 52 self.assertRaises(e, m.splitdrive, 'foo') 53 self.assertRaises(e, m.normcase, 'foo') 54 self.assertRaises(e, m.isabs, 'foo') 55 56# 57# Tests for the pure classes. 58# 59 60 61class PurePathBaseTest(unittest.TestCase): 62 cls = PurePathBase 63 64 def test_unsupported_operation_pure(self): 65 p = self.cls('foo') 66 e = UnsupportedOperation 67 with self.assertRaises(e): 68 p.drive 69 with self.assertRaises(e): 70 p.root 71 with self.assertRaises(e): 72 p.anchor 73 with self.assertRaises(e): 74 p.parts 75 with self.assertRaises(e): 76 p.parent 77 with self.assertRaises(e): 78 p.parents 79 with self.assertRaises(e): 80 p.name 81 with self.assertRaises(e): 82 p.stem 83 with self.assertRaises(e): 84 p.suffix 85 with self.assertRaises(e): 86 p.suffixes 87 with self.assertRaises(e): 88 p / 'bar' 89 with self.assertRaises(e): 90 'bar' / p 91 self.assertRaises(e, p.joinpath, 'bar') 92 self.assertRaises(e, p.with_name, 'bar') 93 self.assertRaises(e, p.with_stem, 'bar') 94 self.assertRaises(e, p.with_suffix, '.txt') 95 self.assertRaises(e, p.relative_to, '') 96 self.assertRaises(e, p.is_relative_to, '') 97 self.assertRaises(e, p.is_absolute) 98 self.assertRaises(e, p.match, '*') 99 100 def test_magic_methods(self): 101 P = self.cls 102 self.assertFalse(hasattr(P, '__fspath__')) 103 self.assertFalse(hasattr(P, '__bytes__')) 104 self.assertIs(P.__reduce__, object.__reduce__) 105 self.assertIs(P.__repr__, object.__repr__) 106 self.assertIs(P.__hash__, object.__hash__) 107 self.assertIs(P.__eq__, object.__eq__) 108 self.assertIs(P.__lt__, object.__lt__) 109 self.assertIs(P.__le__, object.__le__) 110 self.assertIs(P.__gt__, object.__gt__) 111 self.assertIs(P.__ge__, object.__ge__) 112 113 def test_parser(self): 114 self.assertIsInstance(self.cls.parser, ParserBase) 115 116 117class DummyPurePath(PurePathBase): 118 __slots__ = () 119 parser = posixpath 120 121 def __eq__(self, other): 122 if not isinstance(other, DummyPurePath): 123 return NotImplemented 124 return str(self) == str(other) 125 126 def __hash__(self): 127 return hash(str(self)) 128 129 def __repr__(self): 130 return "{}({!r})".format(self.__class__.__name__, self.as_posix()) 131 132 133class DummyPurePathTest(unittest.TestCase): 134 cls = DummyPurePath 135 136 # Use a base path that's unrelated to any real filesystem path. 137 base = f'/this/path/kills/fascists/{TESTFN}' 138 139 def setUp(self): 140 name = self.id().split('.')[-1] 141 if name in _tests_needing_posix and self.cls.parser is not posixpath: 142 self.skipTest('requires POSIX-flavoured path class') 143 if name in _tests_needing_windows and self.cls.parser is posixpath: 144 self.skipTest('requires Windows-flavoured path class') 145 p = self.cls('a') 146 self.parser = p.parser 147 self.sep = self.parser.sep 148 self.altsep = self.parser.altsep 149 150 def test_constructor_common(self): 151 P = self.cls 152 p = P('a') 153 self.assertIsInstance(p, P) 154 P('a', 'b', 'c') 155 P('/a', 'b', 'c') 156 P('a/b/c') 157 P('/a/b/c') 158 159 def test_bytes(self): 160 P = self.cls 161 with self.assertRaises(TypeError): 162 P(b'a') 163 with self.assertRaises(TypeError): 164 P(b'a', 'b') 165 with self.assertRaises(TypeError): 166 P('a', b'b') 167 with self.assertRaises(TypeError): 168 P('a').joinpath(b'b') 169 with self.assertRaises(TypeError): 170 P('a') / b'b' 171 with self.assertRaises(TypeError): 172 b'a' / P('b') 173 with self.assertRaises(TypeError): 174 P('a').match(b'b') 175 with self.assertRaises(TypeError): 176 P('a').relative_to(b'b') 177 with self.assertRaises(TypeError): 178 P('a').with_name(b'b') 179 with self.assertRaises(TypeError): 180 P('a').with_stem(b'b') 181 with self.assertRaises(TypeError): 182 P('a').with_suffix(b'b') 183 184 def _check_str_subclass(self, *args): 185 # Issue #21127: it should be possible to construct a PurePath object 186 # from a str subclass instance, and it then gets converted to 187 # a pure str object. 188 class StrSubclass(str): 189 pass 190 P = self.cls 191 p = P(*(StrSubclass(x) for x in args)) 192 self.assertEqual(p, P(*args)) 193 for part in p.parts: 194 self.assertIs(type(part), str) 195 196 def test_str_subclass_common(self): 197 self._check_str_subclass('') 198 self._check_str_subclass('.') 199 self._check_str_subclass('a') 200 self._check_str_subclass('a/b.txt') 201 self._check_str_subclass('/a/b.txt') 202 203 @needs_windows 204 def test_str_subclass_windows(self): 205 self._check_str_subclass('.\\a:b') 206 self._check_str_subclass('c:') 207 self._check_str_subclass('c:a') 208 self._check_str_subclass('c:a\\b.txt') 209 self._check_str_subclass('c:\\') 210 self._check_str_subclass('c:\\a') 211 self._check_str_subclass('c:\\a\\b.txt') 212 self._check_str_subclass('\\\\some\\share') 213 self._check_str_subclass('\\\\some\\share\\a') 214 self._check_str_subclass('\\\\some\\share\\a\\b.txt') 215 216 def test_with_segments_common(self): 217 class P(self.cls): 218 def __init__(self, *pathsegments, session_id): 219 super().__init__(*pathsegments) 220 self.session_id = session_id 221 222 def with_segments(self, *pathsegments): 223 return type(self)(*pathsegments, session_id=self.session_id) 224 p = P('foo', 'bar', session_id=42) 225 self.assertEqual(42, (p / 'foo').session_id) 226 self.assertEqual(42, ('foo' / p).session_id) 227 self.assertEqual(42, p.joinpath('foo').session_id) 228 self.assertEqual(42, p.with_name('foo').session_id) 229 self.assertEqual(42, p.with_stem('foo').session_id) 230 self.assertEqual(42, p.with_suffix('.foo').session_id) 231 self.assertEqual(42, p.with_segments('foo').session_id) 232 self.assertEqual(42, p.relative_to('foo').session_id) 233 self.assertEqual(42, p.parent.session_id) 234 for parent in p.parents: 235 self.assertEqual(42, parent.session_id) 236 237 def test_join_common(self): 238 P = self.cls 239 p = P('a/b') 240 pp = p.joinpath('c') 241 self.assertEqual(pp, P('a/b/c')) 242 self.assertIs(type(pp), type(p)) 243 pp = p.joinpath('c', 'd') 244 self.assertEqual(pp, P('a/b/c/d')) 245 pp = p.joinpath('/c') 246 self.assertEqual(pp, P('/c')) 247 248 @needs_posix 249 def test_join_posix(self): 250 P = self.cls 251 p = P('//a') 252 pp = p.joinpath('b') 253 self.assertEqual(pp, P('//a/b')) 254 pp = P('/a').joinpath('//c') 255 self.assertEqual(pp, P('//c')) 256 pp = P('//a').joinpath('/c') 257 self.assertEqual(pp, P('/c')) 258 259 @needs_windows 260 def test_join_windows(self): 261 P = self.cls 262 p = P('C:/a/b') 263 pp = p.joinpath('x/y') 264 self.assertEqual(pp, P('C:/a/b/x/y')) 265 pp = p.joinpath('/x/y') 266 self.assertEqual(pp, P('C:/x/y')) 267 # Joining with a different drive => the first path is ignored, even 268 # if the second path is relative. 269 pp = p.joinpath('D:x/y') 270 self.assertEqual(pp, P('D:x/y')) 271 pp = p.joinpath('D:/x/y') 272 self.assertEqual(pp, P('D:/x/y')) 273 pp = p.joinpath('//host/share/x/y') 274 self.assertEqual(pp, P('//host/share/x/y')) 275 # Joining with the same drive => the first path is appended to if 276 # the second path is relative. 277 pp = p.joinpath('c:x/y') 278 self.assertEqual(pp, P('C:/a/b/x/y')) 279 pp = p.joinpath('c:/x/y') 280 self.assertEqual(pp, P('C:/x/y')) 281 # Joining with files with NTFS data streams => the filename should 282 # not be parsed as a drive letter 283 pp = p.joinpath(P('./d:s')) 284 self.assertEqual(pp, P('C:/a/b/d:s')) 285 pp = p.joinpath(P('./dd:s')) 286 self.assertEqual(pp, P('C:/a/b/dd:s')) 287 pp = p.joinpath(P('E:d:s')) 288 self.assertEqual(pp, P('E:d:s')) 289 # Joining onto a UNC path with no root 290 pp = P('//').joinpath('server') 291 self.assertEqual(pp, P('//server')) 292 pp = P('//server').joinpath('share') 293 self.assertEqual(pp, P('//server/share')) 294 pp = P('//./BootPartition').joinpath('Windows') 295 self.assertEqual(pp, P('//./BootPartition/Windows')) 296 297 def test_div_common(self): 298 # Basically the same as joinpath(). 299 P = self.cls 300 p = P('a/b') 301 pp = p / 'c' 302 self.assertEqual(pp, P('a/b/c')) 303 self.assertIs(type(pp), type(p)) 304 pp = p / 'c/d' 305 self.assertEqual(pp, P('a/b/c/d')) 306 pp = p / 'c' / 'd' 307 self.assertEqual(pp, P('a/b/c/d')) 308 pp = 'c' / p / 'd' 309 self.assertEqual(pp, P('c/a/b/d')) 310 pp = p/ '/c' 311 self.assertEqual(pp, P('/c')) 312 313 @needs_posix 314 def test_div_posix(self): 315 # Basically the same as joinpath(). 316 P = self.cls 317 p = P('//a') 318 pp = p / 'b' 319 self.assertEqual(pp, P('//a/b')) 320 pp = P('/a') / '//c' 321 self.assertEqual(pp, P('//c')) 322 pp = P('//a') / '/c' 323 self.assertEqual(pp, P('/c')) 324 325 @needs_windows 326 def test_div_windows(self): 327 # Basically the same as joinpath(). 328 P = self.cls 329 p = P('C:/a/b') 330 self.assertEqual(p / 'x/y', P('C:/a/b/x/y')) 331 self.assertEqual(p / 'x' / 'y', P('C:/a/b/x/y')) 332 self.assertEqual(p / '/x/y', P('C:/x/y')) 333 self.assertEqual(p / '/x' / 'y', P('C:/x/y')) 334 # Joining with a different drive => the first path is ignored, even 335 # if the second path is relative. 336 self.assertEqual(p / 'D:x/y', P('D:x/y')) 337 self.assertEqual(p / 'D:' / 'x/y', P('D:x/y')) 338 self.assertEqual(p / 'D:/x/y', P('D:/x/y')) 339 self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y')) 340 self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y')) 341 # Joining with the same drive => the first path is appended to if 342 # the second path is relative. 343 self.assertEqual(p / 'c:x/y', P('C:/a/b/x/y')) 344 self.assertEqual(p / 'c:/x/y', P('C:/x/y')) 345 # Joining with files with NTFS data streams => the filename should 346 # not be parsed as a drive letter 347 self.assertEqual(p / P('./d:s'), P('C:/a/b/d:s')) 348 self.assertEqual(p / P('./dd:s'), P('C:/a/b/dd:s')) 349 self.assertEqual(p / P('E:d:s'), P('E:d:s')) 350 351 def _check_str(self, expected, args): 352 p = self.cls(*args) 353 self.assertEqual(str(p), expected.replace('/', self.sep)) 354 355 def test_str_common(self): 356 # Canonicalized paths roundtrip. 357 for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): 358 self._check_str(pathstr, (pathstr,)) 359 # Other tests for str() are in test_equivalences(). 360 361 @needs_windows 362 def test_str_windows(self): 363 p = self.cls('a/b/c') 364 self.assertEqual(str(p), 'a\\b\\c') 365 p = self.cls('c:/a/b/c') 366 self.assertEqual(str(p), 'c:\\a\\b\\c') 367 p = self.cls('//a/b') 368 self.assertEqual(str(p), '\\\\a\\b\\') 369 p = self.cls('//a/b/c') 370 self.assertEqual(str(p), '\\\\a\\b\\c') 371 p = self.cls('//a/b/c/d') 372 self.assertEqual(str(p), '\\\\a\\b\\c\\d') 373 374 def test_as_posix_common(self): 375 P = self.cls 376 for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): 377 self.assertEqual(P(pathstr).as_posix(), pathstr) 378 # Other tests for as_posix() are in test_equivalences(). 379 380 def test_match_empty(self): 381 P = self.cls 382 self.assertRaises(ValueError, P('a').match, '') 383 384 def test_match_common(self): 385 P = self.cls 386 # Simple relative pattern. 387 self.assertTrue(P('b.py').match('b.py')) 388 self.assertTrue(P('a/b.py').match('b.py')) 389 self.assertTrue(P('/a/b.py').match('b.py')) 390 self.assertFalse(P('a.py').match('b.py')) 391 self.assertFalse(P('b/py').match('b.py')) 392 self.assertFalse(P('/a.py').match('b.py')) 393 self.assertFalse(P('b.py/c').match('b.py')) 394 # Wildcard relative pattern. 395 self.assertTrue(P('b.py').match('*.py')) 396 self.assertTrue(P('a/b.py').match('*.py')) 397 self.assertTrue(P('/a/b.py').match('*.py')) 398 self.assertFalse(P('b.pyc').match('*.py')) 399 self.assertFalse(P('b./py').match('*.py')) 400 self.assertFalse(P('b.py/c').match('*.py')) 401 # Multi-part relative pattern. 402 self.assertTrue(P('ab/c.py').match('a*/*.py')) 403 self.assertTrue(P('/d/ab/c.py').match('a*/*.py')) 404 self.assertFalse(P('a.py').match('a*/*.py')) 405 self.assertFalse(P('/dab/c.py').match('a*/*.py')) 406 self.assertFalse(P('ab/c.py/d').match('a*/*.py')) 407 # Absolute pattern. 408 self.assertTrue(P('/b.py').match('/*.py')) 409 self.assertFalse(P('b.py').match('/*.py')) 410 self.assertFalse(P('a/b.py').match('/*.py')) 411 self.assertFalse(P('/a/b.py').match('/*.py')) 412 # Multi-part absolute pattern. 413 self.assertTrue(P('/a/b.py').match('/a/*.py')) 414 self.assertFalse(P('/ab.py').match('/a/*.py')) 415 self.assertFalse(P('/a/b/c.py').match('/a/*.py')) 416 # Multi-part glob-style pattern. 417 self.assertFalse(P('/a/b/c.py').match('/**/*.py')) 418 self.assertTrue(P('/a/b/c.py').match('/a/**/*.py')) 419 # Case-sensitive flag 420 self.assertFalse(P('A.py').match('a.PY', case_sensitive=True)) 421 self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) 422 self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) 423 self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) 424 # Matching against empty path 425 self.assertFalse(P('').match('*')) 426 self.assertFalse(P('').match('**')) 427 self.assertFalse(P('').match('**/*')) 428 429 @needs_posix 430 def test_match_posix(self): 431 P = self.cls 432 self.assertFalse(P('A.py').match('a.PY')) 433 434 @needs_windows 435 def test_match_windows(self): 436 P = self.cls 437 # Absolute patterns. 438 self.assertTrue(P('c:/b.py').match('*:/*.py')) 439 self.assertTrue(P('c:/b.py').match('c:/*.py')) 440 self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive 441 self.assertFalse(P('b.py').match('/*.py')) 442 self.assertFalse(P('b.py').match('c:*.py')) 443 self.assertFalse(P('b.py').match('c:/*.py')) 444 self.assertFalse(P('c:b.py').match('/*.py')) 445 self.assertFalse(P('c:b.py').match('c:/*.py')) 446 self.assertFalse(P('/b.py').match('c:*.py')) 447 self.assertFalse(P('/b.py').match('c:/*.py')) 448 # UNC patterns. 449 self.assertTrue(P('//some/share/a.py').match('//*/*/*.py')) 450 self.assertTrue(P('//some/share/a.py').match('//some/share/*.py')) 451 self.assertFalse(P('//other/share/a.py').match('//some/share/*.py')) 452 self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py')) 453 # Case-insensitivity. 454 self.assertTrue(P('B.py').match('b.PY')) 455 self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY')) 456 self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY')) 457 # Path anchor doesn't match pattern anchor 458 self.assertFalse(P('c:/b.py').match('/*.py')) # 'c:/' vs '/' 459 self.assertFalse(P('c:/b.py').match('c:*.py')) # 'c:/' vs 'c:' 460 self.assertFalse(P('//some/share/a.py').match('/*.py')) # '//some/share/' vs '/' 461 462 def test_full_match_common(self): 463 P = self.cls 464 # Simple relative pattern. 465 self.assertTrue(P('b.py').full_match('b.py')) 466 self.assertFalse(P('a/b.py').full_match('b.py')) 467 self.assertFalse(P('/a/b.py').full_match('b.py')) 468 self.assertFalse(P('a.py').full_match('b.py')) 469 self.assertFalse(P('b/py').full_match('b.py')) 470 self.assertFalse(P('/a.py').full_match('b.py')) 471 self.assertFalse(P('b.py/c').full_match('b.py')) 472 # Wildcard relative pattern. 473 self.assertTrue(P('b.py').full_match('*.py')) 474 self.assertFalse(P('a/b.py').full_match('*.py')) 475 self.assertFalse(P('/a/b.py').full_match('*.py')) 476 self.assertFalse(P('b.pyc').full_match('*.py')) 477 self.assertFalse(P('b./py').full_match('*.py')) 478 self.assertFalse(P('b.py/c').full_match('*.py')) 479 # Multi-part relative pattern. 480 self.assertTrue(P('ab/c.py').full_match('a*/*.py')) 481 self.assertFalse(P('/d/ab/c.py').full_match('a*/*.py')) 482 self.assertFalse(P('a.py').full_match('a*/*.py')) 483 self.assertFalse(P('/dab/c.py').full_match('a*/*.py')) 484 self.assertFalse(P('ab/c.py/d').full_match('a*/*.py')) 485 # Absolute pattern. 486 self.assertTrue(P('/b.py').full_match('/*.py')) 487 self.assertFalse(P('b.py').full_match('/*.py')) 488 self.assertFalse(P('a/b.py').full_match('/*.py')) 489 self.assertFalse(P('/a/b.py').full_match('/*.py')) 490 # Multi-part absolute pattern. 491 self.assertTrue(P('/a/b.py').full_match('/a/*.py')) 492 self.assertFalse(P('/ab.py').full_match('/a/*.py')) 493 self.assertFalse(P('/a/b/c.py').full_match('/a/*.py')) 494 # Multi-part glob-style pattern. 495 self.assertTrue(P('a').full_match('**')) 496 self.assertTrue(P('c.py').full_match('**')) 497 self.assertTrue(P('a/b/c.py').full_match('**')) 498 self.assertTrue(P('/a/b/c.py').full_match('**')) 499 self.assertTrue(P('/a/b/c.py').full_match('/**')) 500 self.assertTrue(P('/a/b/c.py').full_match('/a/**')) 501 self.assertTrue(P('/a/b/c.py').full_match('**/*.py')) 502 self.assertTrue(P('/a/b/c.py').full_match('/**/*.py')) 503 self.assertTrue(P('/a/b/c.py').full_match('/a/**/*.py')) 504 self.assertTrue(P('/a/b/c.py').full_match('/a/b/**/*.py')) 505 self.assertTrue(P('/a/b/c.py').full_match('/**/**/**/**/*.py')) 506 self.assertFalse(P('c.py').full_match('**/a.py')) 507 self.assertFalse(P('c.py').full_match('c/**')) 508 self.assertFalse(P('a/b/c.py').full_match('**/a')) 509 self.assertFalse(P('a/b/c.py').full_match('**/a/b')) 510 self.assertFalse(P('a/b/c.py').full_match('**/a/b/c')) 511 self.assertFalse(P('a/b/c.py').full_match('**/a/b/c.')) 512 self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**')) 513 self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**')) 514 self.assertFalse(P('a/b/c.py').full_match('/a/b/c.py/**')) 515 self.assertFalse(P('a/b/c.py').full_match('/**/a/b/c.py')) 516 # Case-sensitive flag 517 self.assertFalse(P('A.py').full_match('a.PY', case_sensitive=True)) 518 self.assertTrue(P('A.py').full_match('a.PY', case_sensitive=False)) 519 self.assertFalse(P('c:/a/B.Py').full_match('C:/A/*.pY', case_sensitive=True)) 520 self.assertTrue(P('/a/b/c.py').full_match('/A/*/*.Py', case_sensitive=False)) 521 # Matching against empty path 522 self.assertFalse(P('').full_match('*')) 523 self.assertTrue(P('').full_match('**')) 524 self.assertFalse(P('').full_match('**/*')) 525 # Matching with empty pattern 526 self.assertTrue(P('').full_match('')) 527 self.assertTrue(P('.').full_match('.')) 528 self.assertFalse(P('/').full_match('')) 529 self.assertFalse(P('/').full_match('.')) 530 self.assertFalse(P('foo').full_match('')) 531 self.assertFalse(P('foo').full_match('.')) 532 533 def test_parts_common(self): 534 # `parts` returns a tuple. 535 sep = self.sep 536 P = self.cls 537 p = P('a/b') 538 parts = p.parts 539 self.assertEqual(parts, ('a', 'b')) 540 # When the path is absolute, the anchor is a separate part. 541 p = P('/a/b') 542 parts = p.parts 543 self.assertEqual(parts, (sep, 'a', 'b')) 544 545 @needs_windows 546 def test_parts_windows(self): 547 P = self.cls 548 p = P('c:a/b') 549 parts = p.parts 550 self.assertEqual(parts, ('c:', 'a', 'b')) 551 p = P('c:/a/b') 552 parts = p.parts 553 self.assertEqual(parts, ('c:\\', 'a', 'b')) 554 p = P('//a/b/c/d') 555 parts = p.parts 556 self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd')) 557 558 def test_parent_common(self): 559 # Relative 560 P = self.cls 561 p = P('a/b/c') 562 self.assertEqual(p.parent, P('a/b')) 563 self.assertEqual(p.parent.parent, P('a')) 564 self.assertEqual(p.parent.parent.parent, P('')) 565 self.assertEqual(p.parent.parent.parent.parent, P('')) 566 # Anchored 567 p = P('/a/b/c') 568 self.assertEqual(p.parent, P('/a/b')) 569 self.assertEqual(p.parent.parent, P('/a')) 570 self.assertEqual(p.parent.parent.parent, P('/')) 571 self.assertEqual(p.parent.parent.parent.parent, P('/')) 572 573 @needs_windows 574 def test_parent_windows(self): 575 # Anchored 576 P = self.cls 577 p = P('z:a/b/c') 578 self.assertEqual(p.parent, P('z:a/b')) 579 self.assertEqual(p.parent.parent, P('z:a')) 580 self.assertEqual(p.parent.parent.parent, P('z:')) 581 self.assertEqual(p.parent.parent.parent.parent, P('z:')) 582 p = P('z:/a/b/c') 583 self.assertEqual(p.parent, P('z:/a/b')) 584 self.assertEqual(p.parent.parent, P('z:/a')) 585 self.assertEqual(p.parent.parent.parent, P('z:/')) 586 self.assertEqual(p.parent.parent.parent.parent, P('z:/')) 587 p = P('//a/b/c/d') 588 self.assertEqual(p.parent, P('//a/b/c')) 589 self.assertEqual(p.parent.parent, P('//a/b')) 590 self.assertEqual(p.parent.parent.parent, P('//a/b')) 591 592 def test_parents_common(self): 593 # Relative 594 P = self.cls 595 p = P('a/b/c') 596 par = p.parents 597 self.assertEqual(len(par), 3) 598 self.assertEqual(par[0], P('a/b')) 599 self.assertEqual(par[1], P('a')) 600 self.assertEqual(par[2], P('')) 601 self.assertEqual(par[-1], P('')) 602 self.assertEqual(par[-2], P('a')) 603 self.assertEqual(par[-3], P('a/b')) 604 self.assertEqual(par[0:1], (P('a/b'),)) 605 self.assertEqual(par[:2], (P('a/b'), P('a'))) 606 self.assertEqual(par[:-1], (P('a/b'), P('a'))) 607 self.assertEqual(par[1:], (P('a'), P(''))) 608 self.assertEqual(par[::2], (P('a/b'), P(''))) 609 self.assertEqual(par[::-1], (P(''), P('a'), P('a/b'))) 610 self.assertEqual(list(par), [P('a/b'), P('a'), P('')]) 611 with self.assertRaises(IndexError): 612 par[-4] 613 with self.assertRaises(IndexError): 614 par[3] 615 with self.assertRaises(TypeError): 616 par[0] = p 617 # Anchored 618 p = P('/a/b/c') 619 par = p.parents 620 self.assertEqual(len(par), 3) 621 self.assertEqual(par[0], P('/a/b')) 622 self.assertEqual(par[1], P('/a')) 623 self.assertEqual(par[2], P('/')) 624 self.assertEqual(par[-1], P('/')) 625 self.assertEqual(par[-2], P('/a')) 626 self.assertEqual(par[-3], P('/a/b')) 627 self.assertEqual(par[0:1], (P('/a/b'),)) 628 self.assertEqual(par[:2], (P('/a/b'), P('/a'))) 629 self.assertEqual(par[:-1], (P('/a/b'), P('/a'))) 630 self.assertEqual(par[1:], (P('/a'), P('/'))) 631 self.assertEqual(par[::2], (P('/a/b'), P('/'))) 632 self.assertEqual(par[::-1], (P('/'), P('/a'), P('/a/b'))) 633 self.assertEqual(list(par), [P('/a/b'), P('/a'), P('/')]) 634 with self.assertRaises(IndexError): 635 par[-4] 636 with self.assertRaises(IndexError): 637 par[3] 638 639 @needs_windows 640 def test_parents_windows(self): 641 # Anchored 642 P = self.cls 643 p = P('z:a/b/') 644 par = p.parents 645 self.assertEqual(len(par), 2) 646 self.assertEqual(par[0], P('z:a')) 647 self.assertEqual(par[1], P('z:')) 648 self.assertEqual(par[0:1], (P('z:a'),)) 649 self.assertEqual(par[:-1], (P('z:a'),)) 650 self.assertEqual(par[:2], (P('z:a'), P('z:'))) 651 self.assertEqual(par[1:], (P('z:'),)) 652 self.assertEqual(par[::2], (P('z:a'),)) 653 self.assertEqual(par[::-1], (P('z:'), P('z:a'))) 654 self.assertEqual(list(par), [P('z:a'), P('z:')]) 655 with self.assertRaises(IndexError): 656 par[2] 657 p = P('z:/a/b/') 658 par = p.parents 659 self.assertEqual(len(par), 2) 660 self.assertEqual(par[0], P('z:/a')) 661 self.assertEqual(par[1], P('z:/')) 662 self.assertEqual(par[0:1], (P('z:/a'),)) 663 self.assertEqual(par[0:-1], (P('z:/a'),)) 664 self.assertEqual(par[:2], (P('z:/a'), P('z:/'))) 665 self.assertEqual(par[1:], (P('z:/'),)) 666 self.assertEqual(par[::2], (P('z:/a'),)) 667 self.assertEqual(par[::-1], (P('z:/'), P('z:/a'),)) 668 self.assertEqual(list(par), [P('z:/a'), P('z:/')]) 669 with self.assertRaises(IndexError): 670 par[2] 671 p = P('//a/b/c/d') 672 par = p.parents 673 self.assertEqual(len(par), 2) 674 self.assertEqual(par[0], P('//a/b/c')) 675 self.assertEqual(par[1], P('//a/b')) 676 self.assertEqual(par[0:1], (P('//a/b/c'),)) 677 self.assertEqual(par[0:-1], (P('//a/b/c'),)) 678 self.assertEqual(par[:2], (P('//a/b/c'), P('//a/b'))) 679 self.assertEqual(par[1:], (P('//a/b'),)) 680 self.assertEqual(par[::2], (P('//a/b/c'),)) 681 self.assertEqual(par[::-1], (P('//a/b'), P('//a/b/c'))) 682 self.assertEqual(list(par), [P('//a/b/c'), P('//a/b')]) 683 with self.assertRaises(IndexError): 684 par[2] 685 686 def test_drive_common(self): 687 P = self.cls 688 self.assertEqual(P('a/b').drive, '') 689 self.assertEqual(P('/a/b').drive, '') 690 self.assertEqual(P('').drive, '') 691 692 @needs_windows 693 def test_drive_windows(self): 694 P = self.cls 695 self.assertEqual(P('c:').drive, 'c:') 696 self.assertEqual(P('c:a/b').drive, 'c:') 697 self.assertEqual(P('c:/').drive, 'c:') 698 self.assertEqual(P('c:/a/b/').drive, 'c:') 699 self.assertEqual(P('//a/b').drive, '\\\\a\\b') 700 self.assertEqual(P('//a/b/').drive, '\\\\a\\b') 701 self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') 702 self.assertEqual(P('./c:a').drive, '') 703 704 def test_root_common(self): 705 P = self.cls 706 sep = self.sep 707 self.assertEqual(P('').root, '') 708 self.assertEqual(P('a/b').root, '') 709 self.assertEqual(P('/').root, sep) 710 self.assertEqual(P('/a/b').root, sep) 711 712 @needs_posix 713 def test_root_posix(self): 714 P = self.cls 715 self.assertEqual(P('/a/b').root, '/') 716 # POSIX special case for two leading slashes. 717 self.assertEqual(P('//a/b').root, '//') 718 719 @needs_windows 720 def test_root_windows(self): 721 P = self.cls 722 self.assertEqual(P('c:').root, '') 723 self.assertEqual(P('c:a/b').root, '') 724 self.assertEqual(P('c:/').root, '\\') 725 self.assertEqual(P('c:/a/b/').root, '\\') 726 self.assertEqual(P('//a/b').root, '\\') 727 self.assertEqual(P('//a/b/').root, '\\') 728 self.assertEqual(P('//a/b/c/d').root, '\\') 729 730 def test_anchor_common(self): 731 P = self.cls 732 sep = self.sep 733 self.assertEqual(P('').anchor, '') 734 self.assertEqual(P('a/b').anchor, '') 735 self.assertEqual(P('/').anchor, sep) 736 self.assertEqual(P('/a/b').anchor, sep) 737 738 @needs_windows 739 def test_anchor_windows(self): 740 P = self.cls 741 self.assertEqual(P('c:').anchor, 'c:') 742 self.assertEqual(P('c:a/b').anchor, 'c:') 743 self.assertEqual(P('c:/').anchor, 'c:\\') 744 self.assertEqual(P('c:/a/b/').anchor, 'c:\\') 745 self.assertEqual(P('//a/b').anchor, '\\\\a\\b\\') 746 self.assertEqual(P('//a/b/').anchor, '\\\\a\\b\\') 747 self.assertEqual(P('//a/b/c/d').anchor, '\\\\a\\b\\') 748 749 def test_name_empty(self): 750 P = self.cls 751 self.assertEqual(P('').name, '') 752 self.assertEqual(P('.').name, '.') 753 self.assertEqual(P('/a/b/.').name, '.') 754 755 def test_name_common(self): 756 P = self.cls 757 self.assertEqual(P('/').name, '') 758 self.assertEqual(P('a/b').name, 'b') 759 self.assertEqual(P('/a/b').name, 'b') 760 self.assertEqual(P('a/b.py').name, 'b.py') 761 self.assertEqual(P('/a/b.py').name, 'b.py') 762 763 @needs_windows 764 def test_name_windows(self): 765 P = self.cls 766 self.assertEqual(P('c:').name, '') 767 self.assertEqual(P('c:/').name, '') 768 self.assertEqual(P('c:a/b').name, 'b') 769 self.assertEqual(P('c:/a/b').name, 'b') 770 self.assertEqual(P('c:a/b.py').name, 'b.py') 771 self.assertEqual(P('c:/a/b.py').name, 'b.py') 772 self.assertEqual(P('//My.py/Share.php').name, '') 773 self.assertEqual(P('//My.py/Share.php/a/b').name, 'b') 774 775 def test_suffix_common(self): 776 P = self.cls 777 self.assertEqual(P('').suffix, '') 778 self.assertEqual(P('.').suffix, '') 779 self.assertEqual(P('..').suffix, '') 780 self.assertEqual(P('/').suffix, '') 781 self.assertEqual(P('a/b').suffix, '') 782 self.assertEqual(P('/a/b').suffix, '') 783 self.assertEqual(P('/a/b/.').suffix, '') 784 self.assertEqual(P('a/b.py').suffix, '.py') 785 self.assertEqual(P('/a/b.py').suffix, '.py') 786 self.assertEqual(P('a/.hgrc').suffix, '') 787 self.assertEqual(P('/a/.hgrc').suffix, '') 788 self.assertEqual(P('a/.hg.rc').suffix, '.rc') 789 self.assertEqual(P('/a/.hg.rc').suffix, '.rc') 790 self.assertEqual(P('a/b.tar.gz').suffix, '.gz') 791 self.assertEqual(P('/a/b.tar.gz').suffix, '.gz') 792 self.assertEqual(P('a/Some name. Ending with a dot.').suffix, '') 793 self.assertEqual(P('/a/Some name. Ending with a dot.').suffix, '') 794 795 @needs_windows 796 def test_suffix_windows(self): 797 P = self.cls 798 self.assertEqual(P('c:').suffix, '') 799 self.assertEqual(P('c:/').suffix, '') 800 self.assertEqual(P('c:a/b').suffix, '') 801 self.assertEqual(P('c:/a/b').suffix, '') 802 self.assertEqual(P('c:a/b.py').suffix, '.py') 803 self.assertEqual(P('c:/a/b.py').suffix, '.py') 804 self.assertEqual(P('c:a/.hgrc').suffix, '') 805 self.assertEqual(P('c:/a/.hgrc').suffix, '') 806 self.assertEqual(P('c:a/.hg.rc').suffix, '.rc') 807 self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc') 808 self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz') 809 self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz') 810 self.assertEqual(P('c:a/Some name. Ending with a dot.').suffix, '') 811 self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffix, '') 812 self.assertEqual(P('//My.py/Share.php').suffix, '') 813 self.assertEqual(P('//My.py/Share.php/a/b').suffix, '') 814 815 def test_suffixes_common(self): 816 P = self.cls 817 self.assertEqual(P('').suffixes, []) 818 self.assertEqual(P('.').suffixes, []) 819 self.assertEqual(P('/').suffixes, []) 820 self.assertEqual(P('a/b').suffixes, []) 821 self.assertEqual(P('/a/b').suffixes, []) 822 self.assertEqual(P('/a/b/.').suffixes, []) 823 self.assertEqual(P('a/b.py').suffixes, ['.py']) 824 self.assertEqual(P('/a/b.py').suffixes, ['.py']) 825 self.assertEqual(P('a/.hgrc').suffixes, []) 826 self.assertEqual(P('/a/.hgrc').suffixes, []) 827 self.assertEqual(P('a/.hg.rc').suffixes, ['.rc']) 828 self.assertEqual(P('/a/.hg.rc').suffixes, ['.rc']) 829 self.assertEqual(P('a/b.tar.gz').suffixes, ['.tar', '.gz']) 830 self.assertEqual(P('/a/b.tar.gz').suffixes, ['.tar', '.gz']) 831 self.assertEqual(P('a/Some name. Ending with a dot.').suffixes, []) 832 self.assertEqual(P('/a/Some name. Ending with a dot.').suffixes, []) 833 834 @needs_windows 835 def test_suffixes_windows(self): 836 P = self.cls 837 self.assertEqual(P('c:').suffixes, []) 838 self.assertEqual(P('c:/').suffixes, []) 839 self.assertEqual(P('c:a/b').suffixes, []) 840 self.assertEqual(P('c:/a/b').suffixes, []) 841 self.assertEqual(P('c:a/b.py').suffixes, ['.py']) 842 self.assertEqual(P('c:/a/b.py').suffixes, ['.py']) 843 self.assertEqual(P('c:a/.hgrc').suffixes, []) 844 self.assertEqual(P('c:/a/.hgrc').suffixes, []) 845 self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc']) 846 self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc']) 847 self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz']) 848 self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz']) 849 self.assertEqual(P('//My.py/Share.php').suffixes, []) 850 self.assertEqual(P('//My.py/Share.php/a/b').suffixes, []) 851 self.assertEqual(P('c:a/Some name. Ending with a dot.').suffixes, []) 852 self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffixes, []) 853 854 def test_stem_empty(self): 855 P = self.cls 856 self.assertEqual(P('').stem, '') 857 self.assertEqual(P('.').stem, '.') 858 859 def test_stem_common(self): 860 P = self.cls 861 self.assertEqual(P('..').stem, '..') 862 self.assertEqual(P('/').stem, '') 863 self.assertEqual(P('a/b').stem, 'b') 864 self.assertEqual(P('a/b.py').stem, 'b') 865 self.assertEqual(P('a/.hgrc').stem, '.hgrc') 866 self.assertEqual(P('a/.hg.rc').stem, '.hg') 867 self.assertEqual(P('a/b.tar.gz').stem, 'b.tar') 868 self.assertEqual(P('a/Some name. Ending with a dot.').stem, 869 'Some name. Ending with a dot.') 870 871 @needs_windows 872 def test_stem_windows(self): 873 P = self.cls 874 self.assertEqual(P('c:').stem, '') 875 self.assertEqual(P('c:.').stem, '') 876 self.assertEqual(P('c:..').stem, '..') 877 self.assertEqual(P('c:/').stem, '') 878 self.assertEqual(P('c:a/b').stem, 'b') 879 self.assertEqual(P('c:a/b.py').stem, 'b') 880 self.assertEqual(P('c:a/.hgrc').stem, '.hgrc') 881 self.assertEqual(P('c:a/.hg.rc').stem, '.hg') 882 self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar') 883 self.assertEqual(P('c:a/Some name. Ending with a dot.').stem, 884 'Some name. Ending with a dot.') 885 def test_with_name_common(self): 886 P = self.cls 887 self.assertEqual(P('a/b').with_name('d.xml'), P('a/d.xml')) 888 self.assertEqual(P('/a/b').with_name('d.xml'), P('/a/d.xml')) 889 self.assertEqual(P('a/b.py').with_name('d.xml'), P('a/d.xml')) 890 self.assertEqual(P('/a/b.py').with_name('d.xml'), P('/a/d.xml')) 891 self.assertEqual(P('a/Dot ending.').with_name('d.xml'), P('a/d.xml')) 892 self.assertEqual(P('/a/Dot ending.').with_name('d.xml'), P('/a/d.xml')) 893 894 @needs_windows 895 def test_with_name_windows(self): 896 P = self.cls 897 self.assertEqual(P('c:a/b').with_name('d.xml'), P('c:a/d.xml')) 898 self.assertEqual(P('c:/a/b').with_name('d.xml'), P('c:/a/d.xml')) 899 self.assertEqual(P('c:a/Dot ending.').with_name('d.xml'), P('c:a/d.xml')) 900 self.assertEqual(P('c:/a/Dot ending.').with_name('d.xml'), P('c:/a/d.xml')) 901 self.assertRaises(ValueError, P('c:').with_name, 'd.xml') 902 self.assertRaises(ValueError, P('c:/').with_name, 'd.xml') 903 self.assertRaises(ValueError, P('//My/Share').with_name, 'd.xml') 904 self.assertEqual(str(P('a').with_name('d:')), '.\\d:') 905 self.assertEqual(str(P('a').with_name('d:e')), '.\\d:e') 906 self.assertEqual(P('c:a/b').with_name('d:'), P('c:a/d:')) 907 self.assertEqual(P('c:a/b').with_name('d:e'), P('c:a/d:e')) 908 self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e') 909 self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share') 910 911 def test_with_name_empty(self): 912 P = self.cls 913 self.assertEqual(P('').with_name('d.xml'), P('d.xml')) 914 self.assertEqual(P('.').with_name('d.xml'), P('d.xml')) 915 self.assertEqual(P('/').with_name('d.xml'), P('/d.xml')) 916 self.assertEqual(P('a/b').with_name(''), P('a/')) 917 self.assertEqual(P('a/b').with_name('.'), P('a/.')) 918 919 def test_with_name_seps(self): 920 P = self.cls 921 self.assertRaises(ValueError, P('a/b').with_name, '/c') 922 self.assertRaises(ValueError, P('a/b').with_name, 'c/') 923 self.assertRaises(ValueError, P('a/b').with_name, 'c/d') 924 925 def test_with_stem_common(self): 926 P = self.cls 927 self.assertEqual(P('a/b').with_stem('d'), P('a/d')) 928 self.assertEqual(P('/a/b').with_stem('d'), P('/a/d')) 929 self.assertEqual(P('a/b.py').with_stem('d'), P('a/d.py')) 930 self.assertEqual(P('/a/b.py').with_stem('d'), P('/a/d.py')) 931 self.assertEqual(P('/a/b.tar.gz').with_stem('d'), P('/a/d.gz')) 932 self.assertEqual(P('a/Dot ending.').with_stem('d'), P('a/d')) 933 self.assertEqual(P('/a/Dot ending.').with_stem('d'), P('/a/d')) 934 935 @needs_windows 936 def test_with_stem_windows(self): 937 P = self.cls 938 self.assertEqual(P('c:a/b').with_stem('d'), P('c:a/d')) 939 self.assertEqual(P('c:/a/b').with_stem('d'), P('c:/a/d')) 940 self.assertEqual(P('c:a/Dot ending.').with_stem('d'), P('c:a/d')) 941 self.assertEqual(P('c:/a/Dot ending.').with_stem('d'), P('c:/a/d')) 942 self.assertRaises(ValueError, P('c:').with_stem, 'd') 943 self.assertRaises(ValueError, P('c:/').with_stem, 'd') 944 self.assertRaises(ValueError, P('//My/Share').with_stem, 'd') 945 self.assertEqual(str(P('a').with_stem('d:')), '.\\d:') 946 self.assertEqual(str(P('a').with_stem('d:e')), '.\\d:e') 947 self.assertEqual(P('c:a/b').with_stem('d:'), P('c:a/d:')) 948 self.assertEqual(P('c:a/b').with_stem('d:e'), P('c:a/d:e')) 949 self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:/e') 950 self.assertRaises(ValueError, P('c:a/b').with_stem, '//My/Share') 951 952 def test_with_stem_empty(self): 953 P = self.cls 954 self.assertEqual(P('').with_stem('d'), P('d')) 955 self.assertEqual(P('.').with_stem('d'), P('d')) 956 self.assertEqual(P('/').with_stem('d'), P('/d')) 957 self.assertEqual(P('a/b').with_stem(''), P('a/')) 958 self.assertEqual(P('a/b').with_stem('.'), P('a/.')) 959 self.assertRaises(ValueError, P('foo.gz').with_stem, '') 960 self.assertRaises(ValueError, P('/a/b/foo.gz').with_stem, '') 961 962 def test_with_stem_seps(self): 963 P = self.cls 964 self.assertRaises(ValueError, P('a/b').with_stem, '/c') 965 self.assertRaises(ValueError, P('a/b').with_stem, 'c/') 966 self.assertRaises(ValueError, P('a/b').with_stem, 'c/d') 967 968 def test_with_suffix_common(self): 969 P = self.cls 970 self.assertEqual(P('a/b').with_suffix('.gz'), P('a/b.gz')) 971 self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz')) 972 self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz')) 973 self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz')) 974 # Stripping suffix. 975 self.assertEqual(P('a/b.py').with_suffix(''), P('a/b')) 976 self.assertEqual(P('/a/b').with_suffix(''), P('/a/b')) 977 978 @needs_windows 979 def test_with_suffix_windows(self): 980 P = self.cls 981 self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz')) 982 self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz')) 983 self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz')) 984 self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz')) 985 # Path doesn't have a "filename" component. 986 self.assertRaises(ValueError, P('').with_suffix, '.gz') 987 self.assertRaises(ValueError, P('.').with_suffix, '.gz') 988 self.assertRaises(ValueError, P('/').with_suffix, '.gz') 989 self.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz') 990 # Invalid suffix. 991 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz') 992 self.assertRaises(ValueError, P('c:a/b').with_suffix, '/') 993 self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\') 994 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:') 995 self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz') 996 self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz') 997 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz') 998 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d') 999 self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d') 1000 self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d') 1001 self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d') 1002 self.assertRaises(TypeError, P('c:a/b').with_suffix, None) 1003 1004 def test_with_suffix_empty(self): 1005 P = self.cls 1006 # Path doesn't have a "filename" component. 1007 self.assertRaises(ValueError, P('').with_suffix, '.gz') 1008 self.assertRaises(ValueError, P('/').with_suffix, '.gz') 1009 1010 def test_with_suffix_invalid(self): 1011 P = self.cls 1012 # Invalid suffix. 1013 self.assertRaises(ValueError, P('a/b').with_suffix, 'gz') 1014 self.assertRaises(ValueError, P('a/b').with_suffix, '/') 1015 self.assertRaises(ValueError, P('a/b').with_suffix, '.') 1016 self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz') 1017 self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d') 1018 self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d') 1019 self.assertRaises(ValueError, P('a/b').with_suffix, './.d') 1020 self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.') 1021 self.assertRaises(TypeError, P('a/b').with_suffix, None) 1022 1023 def test_relative_to_common(self): 1024 P = self.cls 1025 p = P('a/b') 1026 self.assertRaises(TypeError, p.relative_to) 1027 self.assertRaises(TypeError, p.relative_to, b'a') 1028 self.assertEqual(p.relative_to(P('')), P('a/b')) 1029 self.assertEqual(p.relative_to(''), P('a/b')) 1030 self.assertEqual(p.relative_to(P('a')), P('b')) 1031 self.assertEqual(p.relative_to('a'), P('b')) 1032 self.assertEqual(p.relative_to('a/'), P('b')) 1033 self.assertEqual(p.relative_to(P('a/b')), P('')) 1034 self.assertEqual(p.relative_to('a/b'), P('')) 1035 self.assertEqual(p.relative_to(P(''), walk_up=True), P('a/b')) 1036 self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) 1037 self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) 1038 self.assertEqual(p.relative_to('a', walk_up=True), P('b')) 1039 self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) 1040 self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P('')) 1041 self.assertEqual(p.relative_to('a/b', walk_up=True), P('')) 1042 self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) 1043 self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) 1044 self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) 1045 self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..')) 1046 self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b')) 1047 self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b')) 1048 # Unrelated paths. 1049 self.assertRaises(ValueError, p.relative_to, P('c')) 1050 self.assertRaises(ValueError, p.relative_to, P('a/b/c')) 1051 self.assertRaises(ValueError, p.relative_to, P('a/c')) 1052 self.assertRaises(ValueError, p.relative_to, P('/a')) 1053 self.assertRaises(ValueError, p.relative_to, P("../a")) 1054 self.assertRaises(ValueError, p.relative_to, P("a/..")) 1055 self.assertRaises(ValueError, p.relative_to, P("/a/..")) 1056 self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) 1057 self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) 1058 self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) 1059 self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) 1060 self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) 1061 p = P('/a/b') 1062 self.assertEqual(p.relative_to(P('/')), P('a/b')) 1063 self.assertEqual(p.relative_to('/'), P('a/b')) 1064 self.assertEqual(p.relative_to(P('/a')), P('b')) 1065 self.assertEqual(p.relative_to('/a'), P('b')) 1066 self.assertEqual(p.relative_to('/a/'), P('b')) 1067 self.assertEqual(p.relative_to(P('/a/b')), P('')) 1068 self.assertEqual(p.relative_to('/a/b'), P('')) 1069 self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) 1070 self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) 1071 self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) 1072 self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) 1073 self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) 1074 self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P('')) 1075 self.assertEqual(p.relative_to('/a/b', walk_up=True), P('')) 1076 self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) 1077 self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) 1078 self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) 1079 self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..')) 1080 self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b')) 1081 self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b')) 1082 # Unrelated paths. 1083 self.assertRaises(ValueError, p.relative_to, P('/c')) 1084 self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) 1085 self.assertRaises(ValueError, p.relative_to, P('/a/c')) 1086 self.assertRaises(ValueError, p.relative_to, P('')) 1087 self.assertRaises(ValueError, p.relative_to, '') 1088 self.assertRaises(ValueError, p.relative_to, P('a')) 1089 self.assertRaises(ValueError, p.relative_to, P("../a")) 1090 self.assertRaises(ValueError, p.relative_to, P("a/..")) 1091 self.assertRaises(ValueError, p.relative_to, P("/a/..")) 1092 self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) 1093 self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) 1094 self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) 1095 self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) 1096 self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) 1097 1098 @needs_windows 1099 def test_relative_to_windows(self): 1100 P = self.cls 1101 p = P('C:Foo/Bar') 1102 self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar')) 1103 self.assertEqual(p.relative_to('c:'), P('Foo/Bar')) 1104 self.assertEqual(p.relative_to(P('c:foO')), P('Bar')) 1105 self.assertEqual(p.relative_to('c:foO'), P('Bar')) 1106 self.assertEqual(p.relative_to('c:foO/'), P('Bar')) 1107 self.assertEqual(p.relative_to(P('c:foO/baR')), P()) 1108 self.assertEqual(p.relative_to('c:foO/baR'), P()) 1109 self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar')) 1110 self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar')) 1111 self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar')) 1112 self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar')) 1113 self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar')) 1114 self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P()) 1115 self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P()) 1116 self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..')) 1117 self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar')) 1118 self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar')) 1119 # Unrelated paths. 1120 self.assertRaises(ValueError, p.relative_to, P()) 1121 self.assertRaises(ValueError, p.relative_to, '') 1122 self.assertRaises(ValueError, p.relative_to, P('d:')) 1123 self.assertRaises(ValueError, p.relative_to, P('/')) 1124 self.assertRaises(ValueError, p.relative_to, P('Foo')) 1125 self.assertRaises(ValueError, p.relative_to, P('/Foo')) 1126 self.assertRaises(ValueError, p.relative_to, P('C:/Foo')) 1127 self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz')) 1128 self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz')) 1129 self.assertRaises(ValueError, p.relative_to, P(), walk_up=True) 1130 self.assertRaises(ValueError, p.relative_to, '', walk_up=True) 1131 self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) 1132 self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) 1133 self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True) 1134 self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) 1135 self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True) 1136 p = P('C:/Foo/Bar') 1137 self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar')) 1138 self.assertEqual(p.relative_to('c:/'), P('Foo/Bar')) 1139 self.assertEqual(p.relative_to(P('c:/foO')), P('Bar')) 1140 self.assertEqual(p.relative_to('c:/foO'), P('Bar')) 1141 self.assertEqual(p.relative_to('c:/foO/'), P('Bar')) 1142 self.assertEqual(p.relative_to(P('c:/foO/baR')), P()) 1143 self.assertEqual(p.relative_to('c:/foO/baR'), P()) 1144 self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar')) 1145 self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar')) 1146 self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar')) 1147 self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar')) 1148 self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar')) 1149 self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P()) 1150 self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P()) 1151 self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar')) 1152 self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..')) 1153 self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar')) 1154 # Unrelated paths. 1155 self.assertRaises(ValueError, p.relative_to, 'c:') 1156 self.assertRaises(ValueError, p.relative_to, P('c:')) 1157 self.assertRaises(ValueError, p.relative_to, P('C:/Baz')) 1158 self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz')) 1159 self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz')) 1160 self.assertRaises(ValueError, p.relative_to, P('C:Foo')) 1161 self.assertRaises(ValueError, p.relative_to, P('d:')) 1162 self.assertRaises(ValueError, p.relative_to, P('d:/')) 1163 self.assertRaises(ValueError, p.relative_to, P('/')) 1164 self.assertRaises(ValueError, p.relative_to, P('/Foo')) 1165 self.assertRaises(ValueError, p.relative_to, P('//C/Foo')) 1166 self.assertRaises(ValueError, p.relative_to, 'c:', walk_up=True) 1167 self.assertRaises(ValueError, p.relative_to, P('c:'), walk_up=True) 1168 self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True) 1169 self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) 1170 self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True) 1171 self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) 1172 self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) 1173 self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True) 1174 # UNC paths. 1175 p = P('//Server/Share/Foo/Bar') 1176 self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar')) 1177 self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar')) 1178 self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar')) 1179 self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar')) 1180 self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar')) 1181 self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar')) 1182 self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P()) 1183 self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P()) 1184 self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar')) 1185 self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar')) 1186 self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar')) 1187 self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar')) 1188 self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar')) 1189 self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar')) 1190 self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P()) 1191 self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P()) 1192 self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar')) 1193 self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar')) 1194 # Unrelated paths. 1195 self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo')) 1196 self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo')) 1197 self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo')) 1198 self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo')) 1199 self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True) 1200 self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True) 1201 self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True) 1202 self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True) 1203 1204 def test_is_relative_to_common(self): 1205 P = self.cls 1206 p = P('a/b') 1207 self.assertRaises(TypeError, p.is_relative_to) 1208 self.assertRaises(TypeError, p.is_relative_to, b'a') 1209 self.assertTrue(p.is_relative_to(P(''))) 1210 self.assertTrue(p.is_relative_to('')) 1211 self.assertTrue(p.is_relative_to(P('a'))) 1212 self.assertTrue(p.is_relative_to('a/')) 1213 self.assertTrue(p.is_relative_to(P('a/b'))) 1214 self.assertTrue(p.is_relative_to('a/b')) 1215 # Unrelated paths. 1216 self.assertFalse(p.is_relative_to(P('c'))) 1217 self.assertFalse(p.is_relative_to(P('a/b/c'))) 1218 self.assertFalse(p.is_relative_to(P('a/c'))) 1219 self.assertFalse(p.is_relative_to(P('/a'))) 1220 p = P('/a/b') 1221 self.assertTrue(p.is_relative_to(P('/'))) 1222 self.assertTrue(p.is_relative_to('/')) 1223 self.assertTrue(p.is_relative_to(P('/a'))) 1224 self.assertTrue(p.is_relative_to('/a')) 1225 self.assertTrue(p.is_relative_to('/a/')) 1226 self.assertTrue(p.is_relative_to(P('/a/b'))) 1227 self.assertTrue(p.is_relative_to('/a/b')) 1228 # Unrelated paths. 1229 self.assertFalse(p.is_relative_to(P('/c'))) 1230 self.assertFalse(p.is_relative_to(P('/a/b/c'))) 1231 self.assertFalse(p.is_relative_to(P('/a/c'))) 1232 self.assertFalse(p.is_relative_to(P(''))) 1233 self.assertFalse(p.is_relative_to('')) 1234 self.assertFalse(p.is_relative_to(P('a'))) 1235 1236 @needs_windows 1237 def test_is_relative_to_windows(self): 1238 P = self.cls 1239 p = P('C:Foo/Bar') 1240 self.assertTrue(p.is_relative_to(P('c:'))) 1241 self.assertTrue(p.is_relative_to('c:')) 1242 self.assertTrue(p.is_relative_to(P('c:foO'))) 1243 self.assertTrue(p.is_relative_to('c:foO')) 1244 self.assertTrue(p.is_relative_to('c:foO/')) 1245 self.assertTrue(p.is_relative_to(P('c:foO/baR'))) 1246 self.assertTrue(p.is_relative_to('c:foO/baR')) 1247 # Unrelated paths. 1248 self.assertFalse(p.is_relative_to(P())) 1249 self.assertFalse(p.is_relative_to('')) 1250 self.assertFalse(p.is_relative_to(P('d:'))) 1251 self.assertFalse(p.is_relative_to(P('/'))) 1252 self.assertFalse(p.is_relative_to(P('Foo'))) 1253 self.assertFalse(p.is_relative_to(P('/Foo'))) 1254 self.assertFalse(p.is_relative_to(P('C:/Foo'))) 1255 self.assertFalse(p.is_relative_to(P('C:Foo/Bar/Baz'))) 1256 self.assertFalse(p.is_relative_to(P('C:Foo/Baz'))) 1257 p = P('C:/Foo/Bar') 1258 self.assertTrue(p.is_relative_to(P('c:/'))) 1259 self.assertTrue(p.is_relative_to(P('c:/foO'))) 1260 self.assertTrue(p.is_relative_to('c:/foO/')) 1261 self.assertTrue(p.is_relative_to(P('c:/foO/baR'))) 1262 self.assertTrue(p.is_relative_to('c:/foO/baR')) 1263 # Unrelated paths. 1264 self.assertFalse(p.is_relative_to('c:')) 1265 self.assertFalse(p.is_relative_to(P('C:/Baz'))) 1266 self.assertFalse(p.is_relative_to(P('C:/Foo/Bar/Baz'))) 1267 self.assertFalse(p.is_relative_to(P('C:/Foo/Baz'))) 1268 self.assertFalse(p.is_relative_to(P('C:Foo'))) 1269 self.assertFalse(p.is_relative_to(P('d:'))) 1270 self.assertFalse(p.is_relative_to(P('d:/'))) 1271 self.assertFalse(p.is_relative_to(P('/'))) 1272 self.assertFalse(p.is_relative_to(P('/Foo'))) 1273 self.assertFalse(p.is_relative_to(P('//C/Foo'))) 1274 # UNC paths. 1275 p = P('//Server/Share/Foo/Bar') 1276 self.assertTrue(p.is_relative_to(P('//sErver/sHare'))) 1277 self.assertTrue(p.is_relative_to('//sErver/sHare')) 1278 self.assertTrue(p.is_relative_to('//sErver/sHare/')) 1279 self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo'))) 1280 self.assertTrue(p.is_relative_to('//sErver/sHare/Foo')) 1281 self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/')) 1282 self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo/Bar'))) 1283 self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/Bar')) 1284 # Unrelated paths. 1285 self.assertFalse(p.is_relative_to(P('/Server/Share/Foo'))) 1286 self.assertFalse(p.is_relative_to(P('c:/Server/Share/Foo'))) 1287 self.assertFalse(p.is_relative_to(P('//z/Share/Foo'))) 1288 self.assertFalse(p.is_relative_to(P('//Server/z/Foo'))) 1289 1290 @needs_posix 1291 def test_is_absolute_posix(self): 1292 P = self.cls 1293 self.assertFalse(P('').is_absolute()) 1294 self.assertFalse(P('a').is_absolute()) 1295 self.assertFalse(P('a/b/').is_absolute()) 1296 self.assertTrue(P('/').is_absolute()) 1297 self.assertTrue(P('/a').is_absolute()) 1298 self.assertTrue(P('/a/b/').is_absolute()) 1299 self.assertTrue(P('//a').is_absolute()) 1300 self.assertTrue(P('//a/b').is_absolute()) 1301 1302 @needs_windows 1303 def test_is_absolute_windows(self): 1304 P = self.cls 1305 # Under NT, only paths with both a drive and a root are absolute. 1306 self.assertFalse(P().is_absolute()) 1307 self.assertFalse(P('a').is_absolute()) 1308 self.assertFalse(P('a/b/').is_absolute()) 1309 self.assertFalse(P('/').is_absolute()) 1310 self.assertFalse(P('/a').is_absolute()) 1311 self.assertFalse(P('/a/b/').is_absolute()) 1312 self.assertFalse(P('c:').is_absolute()) 1313 self.assertFalse(P('c:a').is_absolute()) 1314 self.assertFalse(P('c:a/b/').is_absolute()) 1315 self.assertTrue(P('c:/').is_absolute()) 1316 self.assertTrue(P('c:/a').is_absolute()) 1317 self.assertTrue(P('c:/a/b/').is_absolute()) 1318 # UNC paths are absolute by definition. 1319 self.assertTrue(P('//').is_absolute()) 1320 self.assertTrue(P('//a').is_absolute()) 1321 self.assertTrue(P('//a/b').is_absolute()) 1322 self.assertTrue(P('//a/b/').is_absolute()) 1323 self.assertTrue(P('//a/b/c').is_absolute()) 1324 self.assertTrue(P('//a/b/c/d').is_absolute()) 1325 self.assertTrue(P('//?/UNC/').is_absolute()) 1326 self.assertTrue(P('//?/UNC/spam').is_absolute()) 1327 1328 1329# 1330# Tests for the virtual classes. 1331# 1332 1333class PathBaseTest(PurePathBaseTest): 1334 cls = PathBase 1335 1336 def test_unsupported_operation(self): 1337 P = self.cls 1338 p = self.cls('') 1339 e = UnsupportedOperation 1340 self.assertRaises(e, p.stat) 1341 self.assertRaises(e, p.lstat) 1342 self.assertRaises(e, p.exists) 1343 self.assertRaises(e, p.samefile, 'foo') 1344 self.assertRaises(e, p.is_dir) 1345 self.assertRaises(e, p.is_file) 1346 self.assertRaises(e, p.is_mount) 1347 self.assertRaises(e, p.is_symlink) 1348 self.assertRaises(e, p.is_block_device) 1349 self.assertRaises(e, p.is_char_device) 1350 self.assertRaises(e, p.is_fifo) 1351 self.assertRaises(e, p.is_socket) 1352 self.assertRaises(e, p.open) 1353 self.assertRaises(e, p.read_bytes) 1354 self.assertRaises(e, p.read_text) 1355 self.assertRaises(e, p.write_bytes, b'foo') 1356 self.assertRaises(e, p.write_text, 'foo') 1357 self.assertRaises(e, p.iterdir) 1358 self.assertRaises(e, p.glob, '*') 1359 self.assertRaises(e, p.rglob, '*') 1360 self.assertRaises(e, lambda: list(p.walk())) 1361 self.assertRaises(e, p.absolute) 1362 self.assertRaises(e, P.cwd) 1363 self.assertRaises(e, p.expanduser) 1364 self.assertRaises(e, p.home) 1365 self.assertRaises(e, p.readlink) 1366 self.assertRaises(e, p.symlink_to, 'foo') 1367 self.assertRaises(e, p.hardlink_to, 'foo') 1368 self.assertRaises(e, p.mkdir) 1369 self.assertRaises(e, p.touch) 1370 self.assertRaises(e, p.rename, 'foo') 1371 self.assertRaises(e, p.replace, 'foo') 1372 self.assertRaises(e, p.chmod, 0o755) 1373 self.assertRaises(e, p.lchmod, 0o755) 1374 self.assertRaises(e, p.unlink) 1375 self.assertRaises(e, p.rmdir) 1376 self.assertRaises(e, p.owner) 1377 self.assertRaises(e, p.group) 1378 self.assertRaises(e, p.as_uri) 1379 1380 def test_as_uri_common(self): 1381 e = UnsupportedOperation 1382 self.assertRaises(e, self.cls('').as_uri) 1383 1384 def test_fspath_common(self): 1385 self.assertRaises(TypeError, os.fspath, self.cls('')) 1386 1387 def test_as_bytes_common(self): 1388 self.assertRaises(TypeError, bytes, self.cls('')) 1389 1390 1391class DummyPathIO(io.BytesIO): 1392 """ 1393 Used by DummyPath to implement `open('w')` 1394 """ 1395 1396 def __init__(self, files, path): 1397 super().__init__() 1398 self.files = files 1399 self.path = path 1400 1401 def close(self): 1402 self.files[self.path] = self.getvalue() 1403 super().close() 1404 1405 1406DummyPathStatResult = collections.namedtuple( 1407 'DummyPathStatResult', 1408 'st_mode st_ino st_dev st_nlink st_uid st_gid st_size st_atime st_mtime st_ctime') 1409 1410 1411class DummyPath(PathBase): 1412 """ 1413 Simple implementation of PathBase that keeps files and directories in 1414 memory. 1415 """ 1416 __slots__ = () 1417 parser = posixpath 1418 1419 _files = {} 1420 _directories = {} 1421 _symlinks = {} 1422 1423 def __eq__(self, other): 1424 if not isinstance(other, DummyPath): 1425 return NotImplemented 1426 return str(self) == str(other) 1427 1428 def __hash__(self): 1429 return hash(str(self)) 1430 1431 def __repr__(self): 1432 return "{}({!r})".format(self.__class__.__name__, self.as_posix()) 1433 1434 def stat(self, *, follow_symlinks=True): 1435 if follow_symlinks or self.name in ('', '.', '..'): 1436 path = str(self.resolve(strict=True)) 1437 else: 1438 path = str(self.parent.resolve(strict=True) / self.name) 1439 if path in self._files: 1440 st_mode = stat.S_IFREG 1441 elif path in self._directories: 1442 st_mode = stat.S_IFDIR 1443 elif path in self._symlinks: 1444 st_mode = stat.S_IFLNK 1445 else: 1446 raise FileNotFoundError(errno.ENOENT, "Not found", str(self)) 1447 return DummyPathStatResult(st_mode, hash(str(self)), 0, 0, 0, 0, 0, 0, 0, 0) 1448 1449 def open(self, mode='r', buffering=-1, encoding=None, 1450 errors=None, newline=None): 1451 if buffering != -1: 1452 raise NotImplementedError 1453 path_obj = self.resolve() 1454 path = str(path_obj) 1455 name = path_obj.name 1456 parent = str(path_obj.parent) 1457 if path in self._directories: 1458 raise IsADirectoryError(errno.EISDIR, "Is a directory", path) 1459 1460 text = 'b' not in mode 1461 mode = ''.join(c for c in mode if c not in 'btU') 1462 if mode == 'r': 1463 if path not in self._files: 1464 raise FileNotFoundError(errno.ENOENT, "File not found", path) 1465 stream = io.BytesIO(self._files[path]) 1466 elif mode == 'w': 1467 if parent not in self._directories: 1468 raise FileNotFoundError(errno.ENOENT, "File not found", parent) 1469 stream = DummyPathIO(self._files, path) 1470 self._files[path] = b'' 1471 self._directories[parent].add(name) 1472 else: 1473 raise NotImplementedError 1474 if text: 1475 stream = io.TextIOWrapper(stream, encoding=encoding, errors=errors, newline=newline) 1476 return stream 1477 1478 def iterdir(self): 1479 path = str(self.resolve()) 1480 if path in self._files: 1481 raise NotADirectoryError(errno.ENOTDIR, "Not a directory", path) 1482 elif path in self._directories: 1483 return (self / name for name in self._directories[path]) 1484 else: 1485 raise FileNotFoundError(errno.ENOENT, "File not found", path) 1486 1487 def mkdir(self, mode=0o777, parents=False, exist_ok=False): 1488 path = str(self.resolve()) 1489 if path in self._directories: 1490 if exist_ok: 1491 return 1492 else: 1493 raise FileExistsError(errno.EEXIST, "File exists", path) 1494 try: 1495 if self.name: 1496 self._directories[str(self.parent)].add(self.name) 1497 self._directories[path] = set() 1498 except KeyError: 1499 if not parents: 1500 raise FileNotFoundError(errno.ENOENT, "File not found", str(self.parent)) from None 1501 self.parent.mkdir(parents=True, exist_ok=True) 1502 self.mkdir(mode, parents=False, exist_ok=exist_ok) 1503 1504 1505class DummyPathTest(DummyPurePathTest): 1506 """Tests for PathBase methods that use stat(), open() and iterdir().""" 1507 1508 cls = DummyPath 1509 can_symlink = False 1510 1511 # (self.base) 1512 # | 1513 # |-- brokenLink -> non-existing 1514 # |-- dirA 1515 # | `-- linkC -> ../dirB 1516 # |-- dirB 1517 # | |-- fileB 1518 # | `-- linkD -> ../dirB 1519 # |-- dirC 1520 # | |-- dirD 1521 # | | `-- fileD 1522 # | `-- fileC 1523 # | `-- novel.txt 1524 # |-- dirE # No permissions 1525 # |-- fileA 1526 # |-- linkA -> fileA 1527 # |-- linkB -> dirB 1528 # `-- brokenLinkLoop -> brokenLinkLoop 1529 # 1530 1531 def setUp(self): 1532 super().setUp() 1533 name = self.id().split('.')[-1] 1534 if name in _tests_needing_symlinks and not self.can_symlink: 1535 self.skipTest('requires symlinks') 1536 parser = self.cls.parser 1537 p = self.cls(self.base) 1538 p.mkdir(parents=True) 1539 p.joinpath('dirA').mkdir() 1540 p.joinpath('dirB').mkdir() 1541 p.joinpath('dirC').mkdir() 1542 p.joinpath('dirC', 'dirD').mkdir() 1543 p.joinpath('dirE').mkdir() 1544 with p.joinpath('fileA').open('wb') as f: 1545 f.write(b"this is file A\n") 1546 with p.joinpath('dirB', 'fileB').open('wb') as f: 1547 f.write(b"this is file B\n") 1548 with p.joinpath('dirC', 'fileC').open('wb') as f: 1549 f.write(b"this is file C\n") 1550 with p.joinpath('dirC', 'novel.txt').open('wb') as f: 1551 f.write(b"this is a novel\n") 1552 with p.joinpath('dirC', 'dirD', 'fileD').open('wb') as f: 1553 f.write(b"this is file D\n") 1554 if self.can_symlink: 1555 p.joinpath('linkA').symlink_to('fileA') 1556 p.joinpath('brokenLink').symlink_to('non-existing') 1557 p.joinpath('linkB').symlink_to('dirB') 1558 p.joinpath('dirA', 'linkC').symlink_to(parser.join('..', 'dirB')) 1559 p.joinpath('dirB', 'linkD').symlink_to(parser.join('..', 'dirB')) 1560 p.joinpath('brokenLinkLoop').symlink_to('brokenLinkLoop') 1561 1562 def tearDown(self): 1563 cls = self.cls 1564 cls._files.clear() 1565 cls._directories.clear() 1566 cls._symlinks.clear() 1567 1568 def tempdir(self): 1569 path = self.cls(self.base).with_name('tmp-dirD') 1570 path.mkdir() 1571 return path 1572 1573 def assertFileNotFound(self, func, *args, **kwargs): 1574 with self.assertRaises(FileNotFoundError) as cm: 1575 func(*args, **kwargs) 1576 self.assertEqual(cm.exception.errno, errno.ENOENT) 1577 1578 def assertEqualNormCase(self, path_a, path_b): 1579 normcase = self.parser.normcase 1580 self.assertEqual(normcase(path_a), normcase(path_b)) 1581 1582 def test_samefile(self): 1583 parser = self.parser 1584 fileA_path = parser.join(self.base, 'fileA') 1585 fileB_path = parser.join(self.base, 'dirB', 'fileB') 1586 p = self.cls(fileA_path) 1587 pp = self.cls(fileA_path) 1588 q = self.cls(fileB_path) 1589 self.assertTrue(p.samefile(fileA_path)) 1590 self.assertTrue(p.samefile(pp)) 1591 self.assertFalse(p.samefile(fileB_path)) 1592 self.assertFalse(p.samefile(q)) 1593 # Test the non-existent file case 1594 non_existent = parser.join(self.base, 'foo') 1595 r = self.cls(non_existent) 1596 self.assertRaises(FileNotFoundError, p.samefile, r) 1597 self.assertRaises(FileNotFoundError, p.samefile, non_existent) 1598 self.assertRaises(FileNotFoundError, r.samefile, p) 1599 self.assertRaises(FileNotFoundError, r.samefile, non_existent) 1600 self.assertRaises(FileNotFoundError, r.samefile, r) 1601 self.assertRaises(FileNotFoundError, r.samefile, non_existent) 1602 1603 def test_exists(self): 1604 P = self.cls 1605 p = P(self.base) 1606 self.assertIs(True, p.exists()) 1607 self.assertIs(True, (p / 'dirA').exists()) 1608 self.assertIs(True, (p / 'fileA').exists()) 1609 self.assertIs(False, (p / 'fileA' / 'bah').exists()) 1610 if self.can_symlink: 1611 self.assertIs(True, (p / 'linkA').exists()) 1612 self.assertIs(True, (p / 'linkB').exists()) 1613 self.assertIs(True, (p / 'linkB' / 'fileB').exists()) 1614 self.assertIs(False, (p / 'linkA' / 'bah').exists()) 1615 self.assertIs(False, (p / 'brokenLink').exists()) 1616 self.assertIs(True, (p / 'brokenLink').exists(follow_symlinks=False)) 1617 self.assertIs(False, (p / 'foo').exists()) 1618 self.assertIs(False, P('/xyzzy').exists()) 1619 self.assertIs(False, P(self.base + '\udfff').exists()) 1620 self.assertIs(False, P(self.base + '\x00').exists()) 1621 1622 def test_open_common(self): 1623 p = self.cls(self.base) 1624 with (p / 'fileA').open('r') as f: 1625 self.assertIsInstance(f, io.TextIOBase) 1626 self.assertEqual(f.read(), "this is file A\n") 1627 with (p / 'fileA').open('rb') as f: 1628 self.assertIsInstance(f, io.BufferedIOBase) 1629 self.assertEqual(f.read().strip(), b"this is file A") 1630 1631 def test_read_write_bytes(self): 1632 p = self.cls(self.base) 1633 (p / 'fileA').write_bytes(b'abcdefg') 1634 self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') 1635 # Check that trying to write str does not truncate the file. 1636 self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr') 1637 self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') 1638 1639 def test_read_write_text(self): 1640 p = self.cls(self.base) 1641 (p / 'fileA').write_text('äbcdefg', encoding='latin-1') 1642 self.assertEqual((p / 'fileA').read_text( 1643 encoding='utf-8', errors='ignore'), 'bcdefg') 1644 # Check that trying to write bytes does not truncate the file. 1645 self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes') 1646 self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg') 1647 1648 def test_read_text_with_newlines(self): 1649 p = self.cls(self.base) 1650 # Check that `\n` character change nothing 1651 (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') 1652 self.assertEqual((p / 'fileA').read_text(newline='\n'), 1653 'abcde\r\nfghlk\n\rmnopq') 1654 # Check that `\r` character replaces `\n` 1655 (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') 1656 self.assertEqual((p / 'fileA').read_text(newline='\r'), 1657 'abcde\r\nfghlk\n\rmnopq') 1658 # Check that `\r\n` character replaces `\n` 1659 (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') 1660 self.assertEqual((p / 'fileA').read_text(newline='\r\n'), 1661 'abcde\r\nfghlk\n\rmnopq') 1662 1663 def test_write_text_with_newlines(self): 1664 p = self.cls(self.base) 1665 # Check that `\n` character change nothing 1666 (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n') 1667 self.assertEqual((p / 'fileA').read_bytes(), 1668 b'abcde\r\nfghlk\n\rmnopq') 1669 # Check that `\r` character replaces `\n` 1670 (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r') 1671 self.assertEqual((p / 'fileA').read_bytes(), 1672 b'abcde\r\rfghlk\r\rmnopq') 1673 # Check that `\r\n` character replaces `\n` 1674 (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n') 1675 self.assertEqual((p / 'fileA').read_bytes(), 1676 b'abcde\r\r\nfghlk\r\n\rmnopq') 1677 # Check that no argument passed will change `\n` to `os.linesep` 1678 os_linesep_byte = bytes(os.linesep, encoding='ascii') 1679 (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq') 1680 self.assertEqual((p / 'fileA').read_bytes(), 1681 b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq') 1682 1683 def test_iterdir(self): 1684 P = self.cls 1685 p = P(self.base) 1686 it = p.iterdir() 1687 paths = set(it) 1688 expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA'] 1689 if self.can_symlink: 1690 expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop'] 1691 self.assertEqual(paths, { P(self.base, q) for q in expected }) 1692 1693 @needs_symlinks 1694 def test_iterdir_symlink(self): 1695 # __iter__ on a symlink to a directory. 1696 P = self.cls 1697 p = P(self.base, 'linkB') 1698 paths = set(p.iterdir()) 1699 expected = { P(self.base, 'linkB', q) for q in ['fileB', 'linkD'] } 1700 self.assertEqual(paths, expected) 1701 1702 def test_iterdir_nodir(self): 1703 # __iter__ on something that is not a directory. 1704 p = self.cls(self.base, 'fileA') 1705 with self.assertRaises(OSError) as cm: 1706 p.iterdir() 1707 # ENOENT or EINVAL under Windows, ENOTDIR otherwise 1708 # (see issue #12802). 1709 self.assertIn(cm.exception.errno, (errno.ENOTDIR, 1710 errno.ENOENT, errno.EINVAL)) 1711 1712 def test_glob_common(self): 1713 def _check(glob, expected): 1714 self.assertEqual(set(glob), { P(self.base, q) for q in expected }) 1715 P = self.cls 1716 p = P(self.base) 1717 it = p.glob("fileA") 1718 self.assertIsInstance(it, collections.abc.Iterator) 1719 _check(it, ["fileA"]) 1720 _check(p.glob("fileB"), []) 1721 _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) 1722 if not self.can_symlink: 1723 _check(p.glob("*A"), ['dirA', 'fileA']) 1724 else: 1725 _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) 1726 if not self.can_symlink: 1727 _check(p.glob("*B/*"), ['dirB/fileB']) 1728 else: 1729 _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', 1730 'linkB/fileB', 'linkB/linkD']) 1731 if not self.can_symlink: 1732 _check(p.glob("*/fileB"), ['dirB/fileB']) 1733 else: 1734 _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) 1735 if self.can_symlink: 1736 _check(p.glob("brokenLink"), ['brokenLink']) 1737 1738 if not self.can_symlink: 1739 _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/"]) 1740 else: 1741 _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) 1742 1743 @needs_posix 1744 def test_glob_posix(self): 1745 P = self.cls 1746 p = P(self.base) 1747 q = p / "FILEa" 1748 given = set(p.glob("FILEa")) 1749 expect = {q} if q.exists() else set() 1750 self.assertEqual(given, expect) 1751 self.assertEqual(set(p.glob("FILEa*")), set()) 1752 1753 @needs_windows 1754 def test_glob_windows(self): 1755 P = self.cls 1756 p = P(self.base) 1757 self.assertEqual(set(p.glob("FILEa")), { P(self.base, "fileA") }) 1758 self.assertEqual(set(p.glob("*a\\")), { P(self.base, "dirA/") }) 1759 self.assertEqual(set(p.glob("F*a")), { P(self.base, "fileA") }) 1760 1761 def test_glob_empty_pattern(self): 1762 P = self.cls 1763 p = P(self.base) 1764 self.assertEqual(list(p.glob("")), [p]) 1765 self.assertEqual(list(p.glob(".")), [p / "."]) 1766 self.assertEqual(list(p.glob("./")), [p / "./"]) 1767 1768 def test_glob_case_sensitive(self): 1769 P = self.cls 1770 def _check(path, pattern, case_sensitive, expected): 1771 actual = {str(q) for q in path.glob(pattern, case_sensitive=case_sensitive)} 1772 expected = {str(P(self.base, q)) for q in expected} 1773 self.assertEqual(actual, expected) 1774 path = P(self.base) 1775 _check(path, "DIRB/FILE*", True, []) 1776 _check(path, "DIRB/FILE*", False, ["dirB/fileB"]) 1777 _check(path, "dirb/file*", True, []) 1778 _check(path, "dirb/file*", False, ["dirB/fileB"]) 1779 1780 @needs_symlinks 1781 def test_glob_recurse_symlinks_common(self): 1782 def _check(path, glob, expected): 1783 actual = {path for path in path.glob(glob, recurse_symlinks=True) 1784 if path.parts.count("linkD") <= 1} # exclude symlink loop. 1785 self.assertEqual(actual, { P(self.base, q) for q in expected }) 1786 P = self.cls 1787 p = P(self.base) 1788 _check(p, "fileB", []) 1789 _check(p, "dir*/file*", ["dirB/fileB", "dirC/fileC"]) 1790 _check(p, "*A", ["dirA", "fileA", "linkA"]) 1791 _check(p, "*B/*", ["dirB/fileB", "dirB/linkD", "linkB/fileB", "linkB/linkD"]) 1792 _check(p, "*/fileB", ["dirB/fileB", "linkB/fileB"]) 1793 _check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) 1794 _check(p, "dir*/*/..", ["dirC/dirD/..", "dirA/linkC/..", "dirB/linkD/.."]) 1795 _check(p, "dir*/**", [ 1796 "dirA/", "dirA/linkC", "dirA/linkC/fileB", "dirA/linkC/linkD", "dirA/linkC/linkD/fileB", 1797 "dirB/", "dirB/fileB", "dirB/linkD", "dirB/linkD/fileB", 1798 "dirC/", "dirC/fileC", "dirC/dirD", "dirC/dirD/fileD", "dirC/novel.txt", 1799 "dirE/"]) 1800 _check(p, "dir*/**/", ["dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/", 1801 "dirC/", "dirC/dirD/", "dirE/"]) 1802 _check(p, "dir*/**/..", ["dirA/..", "dirA/linkC/..", "dirB/..", 1803 "dirB/linkD/..", "dirA/linkC/linkD/..", 1804 "dirC/..", "dirC/dirD/..", "dirE/.."]) 1805 _check(p, "dir*/*/**", [ 1806 "dirA/linkC/", "dirA/linkC/linkD", "dirA/linkC/fileB", "dirA/linkC/linkD/fileB", 1807 "dirB/linkD/", "dirB/linkD/fileB", 1808 "dirC/dirD/", "dirC/dirD/fileD"]) 1809 _check(p, "dir*/*/**/", ["dirA/linkC/", "dirA/linkC/linkD/", "dirB/linkD/", "dirC/dirD/"]) 1810 _check(p, "dir*/*/**/..", ["dirA/linkC/..", "dirA/linkC/linkD/..", 1811 "dirB/linkD/..", "dirC/dirD/.."]) 1812 _check(p, "dir*/**/fileC", ["dirC/fileC"]) 1813 _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD/"]) 1814 _check(p, "*/dirD/**", ["dirC/dirD/", "dirC/dirD/fileD"]) 1815 _check(p, "*/dirD/**/", ["dirC/dirD/"]) 1816 1817 def test_rglob_recurse_symlinks_false(self): 1818 def _check(path, glob, expected): 1819 actual = set(path.rglob(glob, recurse_symlinks=False)) 1820 self.assertEqual(actual, { P(self.base, q) for q in expected }) 1821 P = self.cls 1822 p = P(self.base) 1823 it = p.rglob("fileA") 1824 self.assertIsInstance(it, collections.abc.Iterator) 1825 _check(p, "fileA", ["fileA"]) 1826 _check(p, "fileB", ["dirB/fileB"]) 1827 _check(p, "**/fileB", ["dirB/fileB"]) 1828 _check(p, "*/fileA", []) 1829 1830 if self.can_symlink: 1831 _check(p, "*/fileB", ["dirB/fileB", "dirB/linkD/fileB", 1832 "linkB/fileB", "dirA/linkC/fileB"]) 1833 _check(p, "*/", [ 1834 "dirA/", "dirA/linkC/", "dirB/", "dirB/linkD/", "dirC/", 1835 "dirC/dirD/", "dirE/", "linkB/"]) 1836 else: 1837 _check(p, "*/fileB", ["dirB/fileB"]) 1838 _check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirC/dirD/", "dirE/"]) 1839 1840 _check(p, "file*", ["fileA", "dirB/fileB", "dirC/fileC", "dirC/dirD/fileD"]) 1841 _check(p, "", ["", "dirA/", "dirB/", "dirC/", "dirE/", "dirC/dirD/"]) 1842 p = P(self.base, "dirC") 1843 _check(p, "*", ["dirC/fileC", "dirC/novel.txt", 1844 "dirC/dirD", "dirC/dirD/fileD"]) 1845 _check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"]) 1846 _check(p, "**/file*", ["dirC/fileC", "dirC/dirD/fileD"]) 1847 _check(p, "dir*/**", ["dirC/dirD/", "dirC/dirD/fileD"]) 1848 _check(p, "dir*/**/", ["dirC/dirD/"]) 1849 _check(p, "*/*", ["dirC/dirD/fileD"]) 1850 _check(p, "*/", ["dirC/dirD/"]) 1851 _check(p, "", ["dirC/", "dirC/dirD/"]) 1852 _check(p, "**", ["dirC/", "dirC/fileC", "dirC/dirD", "dirC/dirD/fileD", "dirC/novel.txt"]) 1853 _check(p, "**/", ["dirC/", "dirC/dirD/"]) 1854 # gh-91616, a re module regression 1855 _check(p, "*.txt", ["dirC/novel.txt"]) 1856 _check(p, "*.*", ["dirC/novel.txt"]) 1857 1858 @needs_posix 1859 def test_rglob_posix(self): 1860 P = self.cls 1861 p = P(self.base, "dirC") 1862 q = p / "dirD" / "FILEd" 1863 given = set(p.rglob("FILEd")) 1864 expect = {q} if q.exists() else set() 1865 self.assertEqual(given, expect) 1866 self.assertEqual(set(p.rglob("FILEd*")), set()) 1867 1868 @needs_windows 1869 def test_rglob_windows(self): 1870 P = self.cls 1871 p = P(self.base, "dirC") 1872 self.assertEqual(set(p.rglob("FILEd")), { P(self.base, "dirC/dirD/fileD") }) 1873 self.assertEqual(set(p.rglob("*\\")), { P(self.base, "dirC/dirD/") }) 1874 1875 @needs_symlinks 1876 def test_rglob_recurse_symlinks_common(self): 1877 def _check(path, glob, expected): 1878 actual = {path for path in path.rglob(glob, recurse_symlinks=True) 1879 if path.parts.count("linkD") <= 1} # exclude symlink loop. 1880 self.assertEqual(actual, { P(self.base, q) for q in expected }) 1881 P = self.cls 1882 p = P(self.base) 1883 _check(p, "fileB", ["dirB/fileB", "dirA/linkC/fileB", "linkB/fileB", 1884 "dirA/linkC/linkD/fileB", "dirB/linkD/fileB", "linkB/linkD/fileB"]) 1885 _check(p, "*/fileA", []) 1886 _check(p, "*/fileB", ["dirB/fileB", "dirA/linkC/fileB", "linkB/fileB", 1887 "dirA/linkC/linkD/fileB", "dirB/linkD/fileB", "linkB/linkD/fileB"]) 1888 _check(p, "file*", ["fileA", "dirA/linkC/fileB", "dirB/fileB", 1889 "dirA/linkC/linkD/fileB", "dirB/linkD/fileB", "linkB/linkD/fileB", 1890 "dirC/fileC", "dirC/dirD/fileD", "linkB/fileB"]) 1891 _check(p, "*/", ["dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/", 1892 "dirC/", "dirC/dirD/", "dirE/", "linkB/", "linkB/linkD/"]) 1893 _check(p, "", ["", "dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/", 1894 "dirC/", "dirE/", "dirC/dirD/", "linkB/", "linkB/linkD/"]) 1895 1896 p = P(self.base, "dirC") 1897 _check(p, "*", ["dirC/fileC", "dirC/novel.txt", 1898 "dirC/dirD", "dirC/dirD/fileD"]) 1899 _check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"]) 1900 _check(p, "*/*", ["dirC/dirD/fileD"]) 1901 _check(p, "*/", ["dirC/dirD/"]) 1902 _check(p, "", ["dirC/", "dirC/dirD/"]) 1903 # gh-91616, a re module regression 1904 _check(p, "*.txt", ["dirC/novel.txt"]) 1905 _check(p, "*.*", ["dirC/novel.txt"]) 1906 1907 @needs_symlinks 1908 def test_rglob_symlink_loop(self): 1909 # Don't get fooled by symlink loops (Issue #26012). 1910 P = self.cls 1911 p = P(self.base) 1912 given = set(p.rglob('*', recurse_symlinks=False)) 1913 expect = {'brokenLink', 1914 'dirA', 'dirA/linkC', 1915 'dirB', 'dirB/fileB', 'dirB/linkD', 1916 'dirC', 'dirC/dirD', 'dirC/dirD/fileD', 1917 'dirC/fileC', 'dirC/novel.txt', 1918 'dirE', 1919 'fileA', 1920 'linkA', 1921 'linkB', 1922 'brokenLinkLoop', 1923 } 1924 self.assertEqual(given, {p / x for x in expect}) 1925 1926 # See https://github.com/WebAssembly/wasi-filesystem/issues/26 1927 @unittest.skipIf(is_wasi, "WASI resolution of '..' parts doesn't match POSIX") 1928 def test_glob_dotdot(self): 1929 # ".." is not special in globs. 1930 P = self.cls 1931 p = P(self.base) 1932 self.assertEqual(set(p.glob("..")), { P(self.base, "..") }) 1933 self.assertEqual(set(p.glob("../..")), { P(self.base, "..", "..") }) 1934 self.assertEqual(set(p.glob("dirA/..")), { P(self.base, "dirA", "..") }) 1935 self.assertEqual(set(p.glob("dirA/../file*")), { P(self.base, "dirA/../fileA") }) 1936 self.assertEqual(set(p.glob("dirA/../file*/..")), set()) 1937 self.assertEqual(set(p.glob("../xyzzy")), set()) 1938 if self.cls.parser is posixpath: 1939 self.assertEqual(set(p.glob("xyzzy/..")), set()) 1940 else: 1941 # ".." segments are normalized first on Windows, so this path is stat()able. 1942 self.assertEqual(set(p.glob("xyzzy/..")), { P(self.base, "xyzzy", "..") }) 1943 self.assertEqual(set(p.glob("/".join([".."] * 50))), { P(self.base, *[".."] * 50)}) 1944 1945 @needs_symlinks 1946 def test_glob_permissions(self): 1947 # See bpo-38894 1948 P = self.cls 1949 base = P(self.base) / 'permissions' 1950 base.mkdir() 1951 1952 for i in range(100): 1953 link = base / f"link{i}" 1954 if i % 2: 1955 link.symlink_to(P(self.base, "dirE", "nonexistent")) 1956 else: 1957 link.symlink_to(P(self.base, "dirC")) 1958 1959 self.assertEqual(len(set(base.glob("*"))), 100) 1960 self.assertEqual(len(set(base.glob("*/"))), 50) 1961 self.assertEqual(len(set(base.glob("*/fileC"))), 50) 1962 self.assertEqual(len(set(base.glob("*/file*"))), 50) 1963 1964 @needs_symlinks 1965 def test_glob_long_symlink(self): 1966 # See gh-87695 1967 base = self.cls(self.base) / 'long_symlink' 1968 base.mkdir() 1969 bad_link = base / 'bad_link' 1970 bad_link.symlink_to("bad" * 200) 1971 self.assertEqual(sorted(base.glob('**/*')), [bad_link]) 1972 1973 @needs_symlinks 1974 def test_readlink(self): 1975 P = self.cls(self.base) 1976 self.assertEqual((P / 'linkA').readlink(), self.cls('fileA')) 1977 self.assertEqual((P / 'brokenLink').readlink(), 1978 self.cls('non-existing')) 1979 self.assertEqual((P / 'linkB').readlink(), self.cls('dirB')) 1980 self.assertEqual((P / 'linkB' / 'linkD').readlink(), self.cls('../dirB')) 1981 with self.assertRaises(OSError): 1982 (P / 'fileA').readlink() 1983 1984 @unittest.skipIf(hasattr(os, "readlink"), "os.readlink() is present") 1985 def test_readlink_unsupported(self): 1986 P = self.cls(self.base) 1987 p = P / 'fileA' 1988 with self.assertRaises(UnsupportedOperation): 1989 q.readlink(p) 1990 1991 def _check_resolve(self, p, expected, strict=True): 1992 q = p.resolve(strict) 1993 self.assertEqual(q, expected) 1994 1995 # This can be used to check both relative and absolute resolutions. 1996 _check_resolve_relative = _check_resolve_absolute = _check_resolve 1997 1998 @needs_symlinks 1999 def test_resolve_common(self): 2000 P = self.cls 2001 p = P(self.base, 'foo') 2002 with self.assertRaises(OSError) as cm: 2003 p.resolve(strict=True) 2004 self.assertEqual(cm.exception.errno, errno.ENOENT) 2005 # Non-strict 2006 parser = self.parser 2007 self.assertEqualNormCase(str(p.resolve(strict=False)), 2008 parser.join(self.base, 'foo')) 2009 p = P(self.base, 'foo', 'in', 'spam') 2010 self.assertEqualNormCase(str(p.resolve(strict=False)), 2011 parser.join(self.base, 'foo', 'in', 'spam')) 2012 p = P(self.base, '..', 'foo', 'in', 'spam') 2013 self.assertEqualNormCase(str(p.resolve(strict=False)), 2014 parser.join(parser.dirname(self.base), 'foo', 'in', 'spam')) 2015 # These are all relative symlinks. 2016 p = P(self.base, 'dirB', 'fileB') 2017 self._check_resolve_relative(p, p) 2018 p = P(self.base, 'linkA') 2019 self._check_resolve_relative(p, P(self.base, 'fileA')) 2020 p = P(self.base, 'dirA', 'linkC', 'fileB') 2021 self._check_resolve_relative(p, P(self.base, 'dirB', 'fileB')) 2022 p = P(self.base, 'dirB', 'linkD', 'fileB') 2023 self._check_resolve_relative(p, P(self.base, 'dirB', 'fileB')) 2024 # Non-strict 2025 p = P(self.base, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam') 2026 self._check_resolve_relative(p, P(self.base, 'dirB', 'fileB', 'foo', 'in', 2027 'spam'), False) 2028 p = P(self.base, 'dirA', 'linkC', '..', 'foo', 'in', 'spam') 2029 if self.cls.parser is not posixpath: 2030 # In Windows, if linkY points to dirB, 'dirA\linkY\..' 2031 # resolves to 'dirA' without resolving linkY first. 2032 self._check_resolve_relative(p, P(self.base, 'dirA', 'foo', 'in', 2033 'spam'), False) 2034 else: 2035 # In Posix, if linkY points to dirB, 'dirA/linkY/..' 2036 # resolves to 'dirB/..' first before resolving to parent of dirB. 2037 self._check_resolve_relative(p, P(self.base, 'foo', 'in', 'spam'), False) 2038 # Now create absolute symlinks. 2039 d = self.tempdir() 2040 P(self.base, 'dirA', 'linkX').symlink_to(d) 2041 P(self.base, str(d), 'linkY').symlink_to(self.parser.join(self.base, 'dirB')) 2042 p = P(self.base, 'dirA', 'linkX', 'linkY', 'fileB') 2043 self._check_resolve_absolute(p, P(self.base, 'dirB', 'fileB')) 2044 # Non-strict 2045 p = P(self.base, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam') 2046 self._check_resolve_relative(p, P(self.base, 'dirB', 'foo', 'in', 'spam'), 2047 False) 2048 p = P(self.base, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam') 2049 if self.cls.parser is not posixpath: 2050 # In Windows, if linkY points to dirB, 'dirA\linkY\..' 2051 # resolves to 'dirA' without resolving linkY first. 2052 self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False) 2053 else: 2054 # In Posix, if linkY points to dirB, 'dirA/linkY/..' 2055 # resolves to 'dirB/..' first before resolving to parent of dirB. 2056 self._check_resolve_relative(p, P(self.base, 'foo', 'in', 'spam'), False) 2057 2058 @needs_symlinks 2059 def test_resolve_dot(self): 2060 # See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/ 2061 parser = self.parser 2062 p = self.cls(self.base) 2063 p.joinpath('0').symlink_to('.', target_is_directory=True) 2064 p.joinpath('1').symlink_to(parser.join('0', '0'), target_is_directory=True) 2065 p.joinpath('2').symlink_to(parser.join('1', '1'), target_is_directory=True) 2066 q = p / '2' 2067 self.assertEqual(q.resolve(strict=True), p) 2068 r = q / '3' / '4' 2069 self.assertRaises(FileNotFoundError, r.resolve, strict=True) 2070 # Non-strict 2071 self.assertEqual(r.resolve(strict=False), p / '3' / '4') 2072 2073 def _check_symlink_loop(self, *args): 2074 path = self.cls(*args) 2075 with self.assertRaises(OSError) as cm: 2076 path.resolve(strict=True) 2077 self.assertEqual(cm.exception.errno, errno.ELOOP) 2078 2079 @needs_posix 2080 @needs_symlinks 2081 def test_resolve_loop(self): 2082 # Loops with relative symlinks. 2083 self.cls(self.base, 'linkX').symlink_to('linkX/inside') 2084 self._check_symlink_loop(self.base, 'linkX') 2085 self.cls(self.base, 'linkY').symlink_to('linkY') 2086 self._check_symlink_loop(self.base, 'linkY') 2087 self.cls(self.base, 'linkZ').symlink_to('linkZ/../linkZ') 2088 self._check_symlink_loop(self.base, 'linkZ') 2089 # Non-strict 2090 p = self.cls(self.base, 'linkZ', 'foo') 2091 self.assertEqual(p.resolve(strict=False), p) 2092 # Loops with absolute symlinks. 2093 self.cls(self.base, 'linkU').symlink_to(self.parser.join(self.base, 'linkU/inside')) 2094 self._check_symlink_loop(self.base, 'linkU') 2095 self.cls(self.base, 'linkV').symlink_to(self.parser.join(self.base, 'linkV')) 2096 self._check_symlink_loop(self.base, 'linkV') 2097 self.cls(self.base, 'linkW').symlink_to(self.parser.join(self.base, 'linkW/../linkW')) 2098 self._check_symlink_loop(self.base, 'linkW') 2099 # Non-strict 2100 q = self.cls(self.base, 'linkW', 'foo') 2101 self.assertEqual(q.resolve(strict=False), q) 2102 2103 def test_stat(self): 2104 statA = self.cls(self.base).joinpath('fileA').stat() 2105 statB = self.cls(self.base).joinpath('dirB', 'fileB').stat() 2106 statC = self.cls(self.base).joinpath('dirC').stat() 2107 # st_mode: files are the same, directory differs. 2108 self.assertIsInstance(statA.st_mode, int) 2109 self.assertEqual(statA.st_mode, statB.st_mode) 2110 self.assertNotEqual(statA.st_mode, statC.st_mode) 2111 self.assertNotEqual(statB.st_mode, statC.st_mode) 2112 # st_ino: all different, 2113 self.assertIsInstance(statA.st_ino, int) 2114 self.assertNotEqual(statA.st_ino, statB.st_ino) 2115 self.assertNotEqual(statA.st_ino, statC.st_ino) 2116 self.assertNotEqual(statB.st_ino, statC.st_ino) 2117 # st_dev: all the same. 2118 self.assertIsInstance(statA.st_dev, int) 2119 self.assertEqual(statA.st_dev, statB.st_dev) 2120 self.assertEqual(statA.st_dev, statC.st_dev) 2121 # other attributes not used by pathlib. 2122 2123 @needs_symlinks 2124 def test_stat_no_follow_symlinks(self): 2125 p = self.cls(self.base) / 'linkA' 2126 st = p.stat() 2127 self.assertNotEqual(st, p.stat(follow_symlinks=False)) 2128 2129 def test_stat_no_follow_symlinks_nosymlink(self): 2130 p = self.cls(self.base) / 'fileA' 2131 st = p.stat() 2132 self.assertEqual(st, p.stat(follow_symlinks=False)) 2133 2134 @needs_symlinks 2135 def test_lstat(self): 2136 p = self.cls(self.base)/ 'linkA' 2137 st = p.stat() 2138 self.assertNotEqual(st, p.lstat()) 2139 2140 def test_lstat_nosymlink(self): 2141 p = self.cls(self.base) / 'fileA' 2142 st = p.stat() 2143 self.assertEqual(st, p.lstat()) 2144 2145 def test_is_dir(self): 2146 P = self.cls(self.base) 2147 self.assertTrue((P / 'dirA').is_dir()) 2148 self.assertFalse((P / 'fileA').is_dir()) 2149 self.assertFalse((P / 'non-existing').is_dir()) 2150 self.assertFalse((P / 'fileA' / 'bah').is_dir()) 2151 if self.can_symlink: 2152 self.assertFalse((P / 'linkA').is_dir()) 2153 self.assertTrue((P / 'linkB').is_dir()) 2154 self.assertFalse((P/ 'brokenLink').is_dir()) 2155 self.assertFalse((P / 'dirA\udfff').is_dir()) 2156 self.assertFalse((P / 'dirA\x00').is_dir()) 2157 2158 def test_is_dir_no_follow_symlinks(self): 2159 P = self.cls(self.base) 2160 self.assertTrue((P / 'dirA').is_dir(follow_symlinks=False)) 2161 self.assertFalse((P / 'fileA').is_dir(follow_symlinks=False)) 2162 self.assertFalse((P / 'non-existing').is_dir(follow_symlinks=False)) 2163 self.assertFalse((P / 'fileA' / 'bah').is_dir(follow_symlinks=False)) 2164 if self.can_symlink: 2165 self.assertFalse((P / 'linkA').is_dir(follow_symlinks=False)) 2166 self.assertFalse((P / 'linkB').is_dir(follow_symlinks=False)) 2167 self.assertFalse((P/ 'brokenLink').is_dir(follow_symlinks=False)) 2168 self.assertFalse((P / 'dirA\udfff').is_dir(follow_symlinks=False)) 2169 self.assertFalse((P / 'dirA\x00').is_dir(follow_symlinks=False)) 2170 2171 def test_is_file(self): 2172 P = self.cls(self.base) 2173 self.assertTrue((P / 'fileA').is_file()) 2174 self.assertFalse((P / 'dirA').is_file()) 2175 self.assertFalse((P / 'non-existing').is_file()) 2176 self.assertFalse((P / 'fileA' / 'bah').is_file()) 2177 if self.can_symlink: 2178 self.assertTrue((P / 'linkA').is_file()) 2179 self.assertFalse((P / 'linkB').is_file()) 2180 self.assertFalse((P/ 'brokenLink').is_file()) 2181 self.assertFalse((P / 'fileA\udfff').is_file()) 2182 self.assertFalse((P / 'fileA\x00').is_file()) 2183 2184 def test_is_file_no_follow_symlinks(self): 2185 P = self.cls(self.base) 2186 self.assertTrue((P / 'fileA').is_file(follow_symlinks=False)) 2187 self.assertFalse((P / 'dirA').is_file(follow_symlinks=False)) 2188 self.assertFalse((P / 'non-existing').is_file(follow_symlinks=False)) 2189 self.assertFalse((P / 'fileA' / 'bah').is_file(follow_symlinks=False)) 2190 if self.can_symlink: 2191 self.assertFalse((P / 'linkA').is_file(follow_symlinks=False)) 2192 self.assertFalse((P / 'linkB').is_file(follow_symlinks=False)) 2193 self.assertFalse((P/ 'brokenLink').is_file(follow_symlinks=False)) 2194 self.assertFalse((P / 'fileA\udfff').is_file(follow_symlinks=False)) 2195 self.assertFalse((P / 'fileA\x00').is_file(follow_symlinks=False)) 2196 2197 def test_is_mount(self): 2198 P = self.cls(self.base) 2199 self.assertFalse((P / 'fileA').is_mount()) 2200 self.assertFalse((P / 'dirA').is_mount()) 2201 self.assertFalse((P / 'non-existing').is_mount()) 2202 self.assertFalse((P / 'fileA' / 'bah').is_mount()) 2203 if self.can_symlink: 2204 self.assertFalse((P / 'linkA').is_mount()) 2205 2206 def test_is_symlink(self): 2207 P = self.cls(self.base) 2208 self.assertFalse((P / 'fileA').is_symlink()) 2209 self.assertFalse((P / 'dirA').is_symlink()) 2210 self.assertFalse((P / 'non-existing').is_symlink()) 2211 self.assertFalse((P / 'fileA' / 'bah').is_symlink()) 2212 if self.can_symlink: 2213 self.assertTrue((P / 'linkA').is_symlink()) 2214 self.assertTrue((P / 'linkB').is_symlink()) 2215 self.assertTrue((P/ 'brokenLink').is_symlink()) 2216 self.assertIs((P / 'fileA\udfff').is_file(), False) 2217 self.assertIs((P / 'fileA\x00').is_file(), False) 2218 if self.can_symlink: 2219 self.assertIs((P / 'linkA\udfff').is_file(), False) 2220 self.assertIs((P / 'linkA\x00').is_file(), False) 2221 2222 def test_is_junction_false(self): 2223 P = self.cls(self.base) 2224 self.assertFalse((P / 'fileA').is_junction()) 2225 self.assertFalse((P / 'dirA').is_junction()) 2226 self.assertFalse((P / 'non-existing').is_junction()) 2227 self.assertFalse((P / 'fileA' / 'bah').is_junction()) 2228 self.assertFalse((P / 'fileA\udfff').is_junction()) 2229 self.assertFalse((P / 'fileA\x00').is_junction()) 2230 2231 def test_is_fifo_false(self): 2232 P = self.cls(self.base) 2233 self.assertFalse((P / 'fileA').is_fifo()) 2234 self.assertFalse((P / 'dirA').is_fifo()) 2235 self.assertFalse((P / 'non-existing').is_fifo()) 2236 self.assertFalse((P / 'fileA' / 'bah').is_fifo()) 2237 self.assertIs((P / 'fileA\udfff').is_fifo(), False) 2238 self.assertIs((P / 'fileA\x00').is_fifo(), False) 2239 2240 def test_is_socket_false(self): 2241 P = self.cls(self.base) 2242 self.assertFalse((P / 'fileA').is_socket()) 2243 self.assertFalse((P / 'dirA').is_socket()) 2244 self.assertFalse((P / 'non-existing').is_socket()) 2245 self.assertFalse((P / 'fileA' / 'bah').is_socket()) 2246 self.assertIs((P / 'fileA\udfff').is_socket(), False) 2247 self.assertIs((P / 'fileA\x00').is_socket(), False) 2248 2249 def test_is_block_device_false(self): 2250 P = self.cls(self.base) 2251 self.assertFalse((P / 'fileA').is_block_device()) 2252 self.assertFalse((P / 'dirA').is_block_device()) 2253 self.assertFalse((P / 'non-existing').is_block_device()) 2254 self.assertFalse((P / 'fileA' / 'bah').is_block_device()) 2255 self.assertIs((P / 'fileA\udfff').is_block_device(), False) 2256 self.assertIs((P / 'fileA\x00').is_block_device(), False) 2257 2258 def test_is_char_device_false(self): 2259 P = self.cls(self.base) 2260 self.assertFalse((P / 'fileA').is_char_device()) 2261 self.assertFalse((P / 'dirA').is_char_device()) 2262 self.assertFalse((P / 'non-existing').is_char_device()) 2263 self.assertFalse((P / 'fileA' / 'bah').is_char_device()) 2264 self.assertIs((P / 'fileA\udfff').is_char_device(), False) 2265 self.assertIs((P / 'fileA\x00').is_char_device(), False) 2266 2267 def _check_complex_symlinks(self, link0_target): 2268 # Test solving a non-looping chain of symlinks (issue #19887). 2269 parser = self.parser 2270 P = self.cls(self.base) 2271 P.joinpath('link1').symlink_to(parser.join('link0', 'link0'), target_is_directory=True) 2272 P.joinpath('link2').symlink_to(parser.join('link1', 'link1'), target_is_directory=True) 2273 P.joinpath('link3').symlink_to(parser.join('link2', 'link2'), target_is_directory=True) 2274 P.joinpath('link0').symlink_to(link0_target, target_is_directory=True) 2275 2276 # Resolve absolute paths. 2277 p = (P / 'link0').resolve() 2278 self.assertEqual(p, P) 2279 self.assertEqualNormCase(str(p), self.base) 2280 p = (P / 'link1').resolve() 2281 self.assertEqual(p, P) 2282 self.assertEqualNormCase(str(p), self.base) 2283 p = (P / 'link2').resolve() 2284 self.assertEqual(p, P) 2285 self.assertEqualNormCase(str(p), self.base) 2286 p = (P / 'link3').resolve() 2287 self.assertEqual(p, P) 2288 self.assertEqualNormCase(str(p), self.base) 2289 2290 # Resolve relative paths. 2291 try: 2292 self.cls('').absolute() 2293 except UnsupportedOperation: 2294 return 2295 old_path = os.getcwd() 2296 os.chdir(self.base) 2297 try: 2298 p = self.cls('link0').resolve() 2299 self.assertEqual(p, P) 2300 self.assertEqualNormCase(str(p), self.base) 2301 p = self.cls('link1').resolve() 2302 self.assertEqual(p, P) 2303 self.assertEqualNormCase(str(p), self.base) 2304 p = self.cls('link2').resolve() 2305 self.assertEqual(p, P) 2306 self.assertEqualNormCase(str(p), self.base) 2307 p = self.cls('link3').resolve() 2308 self.assertEqual(p, P) 2309 self.assertEqualNormCase(str(p), self.base) 2310 finally: 2311 os.chdir(old_path) 2312 2313 @needs_symlinks 2314 def test_complex_symlinks_absolute(self): 2315 self._check_complex_symlinks(self.base) 2316 2317 @needs_symlinks 2318 def test_complex_symlinks_relative(self): 2319 self._check_complex_symlinks('.') 2320 2321 @needs_symlinks 2322 def test_complex_symlinks_relative_dot_dot(self): 2323 self._check_complex_symlinks(self.parser.join('dirA', '..')) 2324 2325 def setUpWalk(self): 2326 # Build: 2327 # TESTFN/ 2328 # TEST1/ a file kid and two directory kids 2329 # tmp1 2330 # SUB1/ a file kid and a directory kid 2331 # tmp2 2332 # SUB11/ no kids 2333 # SUB2/ a file kid and a dirsymlink kid 2334 # tmp3 2335 # link/ a symlink to TEST2 2336 # broken_link 2337 # broken_link2 2338 # TEST2/ 2339 # tmp4 a lone file 2340 self.walk_path = self.cls(self.base, "TEST1") 2341 self.sub1_path = self.walk_path / "SUB1" 2342 self.sub11_path = self.sub1_path / "SUB11" 2343 self.sub2_path = self.walk_path / "SUB2" 2344 tmp1_path = self.walk_path / "tmp1" 2345 tmp2_path = self.sub1_path / "tmp2" 2346 tmp3_path = self.sub2_path / "tmp3" 2347 self.link_path = self.sub2_path / "link" 2348 t2_path = self.cls(self.base, "TEST2") 2349 tmp4_path = self.cls(self.base, "TEST2", "tmp4") 2350 broken_link_path = self.sub2_path / "broken_link" 2351 broken_link2_path = self.sub2_path / "broken_link2" 2352 2353 self.sub11_path.mkdir(parents=True) 2354 self.sub2_path.mkdir(parents=True) 2355 t2_path.mkdir(parents=True) 2356 2357 for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: 2358 with path.open("w", encoding='utf-8') as f: 2359 f.write(f"I'm {path} and proud of it. Blame test_pathlib.\n") 2360 2361 if self.can_symlink: 2362 self.link_path.symlink_to(t2_path) 2363 broken_link_path.symlink_to('broken') 2364 broken_link2_path.symlink_to(self.cls('tmp3', 'broken')) 2365 self.sub2_tree = (self.sub2_path, [], ["broken_link", "broken_link2", "link", "tmp3"]) 2366 else: 2367 self.sub2_tree = (self.sub2_path, [], ["tmp3"]) 2368 2369 def test_walk_topdown(self): 2370 self.setUpWalk() 2371 walker = self.walk_path.walk() 2372 entry = next(walker) 2373 entry[1].sort() # Ensure we visit SUB1 before SUB2 2374 self.assertEqual(entry, (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) 2375 entry = next(walker) 2376 self.assertEqual(entry, (self.sub1_path, ["SUB11"], ["tmp2"])) 2377 entry = next(walker) 2378 self.assertEqual(entry, (self.sub11_path, [], [])) 2379 entry = next(walker) 2380 entry[1].sort() 2381 entry[2].sort() 2382 self.assertEqual(entry, self.sub2_tree) 2383 with self.assertRaises(StopIteration): 2384 next(walker) 2385 2386 def test_walk_prune(self): 2387 self.setUpWalk() 2388 # Prune the search. 2389 all = [] 2390 for root, dirs, files in self.walk_path.walk(): 2391 all.append((root, dirs, files)) 2392 if 'SUB1' in dirs: 2393 # Note that this also mutates the dirs we appended to all! 2394 dirs.remove('SUB1') 2395 2396 self.assertEqual(len(all), 2) 2397 self.assertEqual(all[0], (self.walk_path, ["SUB2"], ["tmp1"])) 2398 2399 all[1][-1].sort() 2400 all[1][1].sort() 2401 self.assertEqual(all[1], self.sub2_tree) 2402 2403 def test_walk_bottom_up(self): 2404 self.setUpWalk() 2405 seen_testfn = seen_sub1 = seen_sub11 = seen_sub2 = False 2406 for path, dirnames, filenames in self.walk_path.walk(top_down=False): 2407 if path == self.walk_path: 2408 self.assertFalse(seen_testfn) 2409 self.assertTrue(seen_sub1) 2410 self.assertTrue(seen_sub2) 2411 self.assertEqual(sorted(dirnames), ["SUB1", "SUB2"]) 2412 self.assertEqual(filenames, ["tmp1"]) 2413 seen_testfn = True 2414 elif path == self.sub1_path: 2415 self.assertFalse(seen_testfn) 2416 self.assertFalse(seen_sub1) 2417 self.assertTrue(seen_sub11) 2418 self.assertEqual(dirnames, ["SUB11"]) 2419 self.assertEqual(filenames, ["tmp2"]) 2420 seen_sub1 = True 2421 elif path == self.sub11_path: 2422 self.assertFalse(seen_sub1) 2423 self.assertFalse(seen_sub11) 2424 self.assertEqual(dirnames, []) 2425 self.assertEqual(filenames, []) 2426 seen_sub11 = True 2427 elif path == self.sub2_path: 2428 self.assertFalse(seen_testfn) 2429 self.assertFalse(seen_sub2) 2430 self.assertEqual(sorted(dirnames), sorted(self.sub2_tree[1])) 2431 self.assertEqual(sorted(filenames), sorted(self.sub2_tree[2])) 2432 seen_sub2 = True 2433 else: 2434 raise AssertionError(f"Unexpected path: {path}") 2435 self.assertTrue(seen_testfn) 2436 2437 @needs_symlinks 2438 def test_walk_follow_symlinks(self): 2439 self.setUpWalk() 2440 walk_it = self.walk_path.walk(follow_symlinks=True) 2441 for root, dirs, files in walk_it: 2442 if root == self.link_path: 2443 self.assertEqual(dirs, []) 2444 self.assertEqual(files, ["tmp4"]) 2445 break 2446 else: 2447 self.fail("Didn't follow symlink with follow_symlinks=True") 2448 2449 @needs_symlinks 2450 def test_walk_symlink_location(self): 2451 self.setUpWalk() 2452 # Tests whether symlinks end up in filenames or dirnames depending 2453 # on the `follow_symlinks` argument. 2454 walk_it = self.walk_path.walk(follow_symlinks=False) 2455 for root, dirs, files in walk_it: 2456 if root == self.sub2_path: 2457 self.assertIn("link", files) 2458 break 2459 else: 2460 self.fail("symlink not found") 2461 2462 walk_it = self.walk_path.walk(follow_symlinks=True) 2463 for root, dirs, files in walk_it: 2464 if root == self.sub2_path: 2465 self.assertIn("link", dirs) 2466 break 2467 else: 2468 self.fail("symlink not found") 2469 2470 2471class DummyPathWithSymlinks(DummyPath): 2472 __slots__ = () 2473 2474 # Reduce symlink traversal limit to make tests run faster. 2475 _max_symlinks = 20 2476 2477 def readlink(self): 2478 path = str(self.parent.resolve() / self.name) 2479 if path in self._symlinks: 2480 return self.with_segments(self._symlinks[path]) 2481 elif path in self._files or path in self._directories: 2482 raise OSError(errno.EINVAL, "Not a symlink", path) 2483 else: 2484 raise FileNotFoundError(errno.ENOENT, "File not found", path) 2485 2486 def symlink_to(self, target, target_is_directory=False): 2487 self._directories[str(self.parent)].add(self.name) 2488 self._symlinks[str(self)] = str(target) 2489 2490 2491class DummyPathWithSymlinksTest(DummyPathTest): 2492 cls = DummyPathWithSymlinks 2493 can_symlink = True 2494 2495 2496if __name__ == "__main__": 2497 unittest.main() 2498