summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_pathlib/test_pathlib_abc.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_pathlib/test_pathlib_abc.py')
-rw-r--r--Lib/test/test_pathlib/test_pathlib_abc.py680
1 files changed, 14 insertions, 666 deletions
diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py
index 00153e3..bf9ae6c 100644
--- a/Lib/test/test_pathlib/test_pathlib_abc.py
+++ b/Lib/test/test_pathlib/test_pathlib_abc.py
@@ -8,13 +8,11 @@ import unittest
from pathlib._abc import UnsupportedOperation, ParserBase, PurePathBase, PathBase
import posixpath
-from test.support import is_wasi, is_emscripten
from test.support.os_helper import TESTFN
_tests_needing_posix = set()
_tests_needing_windows = set()
-_tests_needing_symlinks = set()
def needs_posix(fn):
@@ -27,11 +25,6 @@ def needs_windows(fn):
_tests_needing_windows.add(fn.__name__)
return fn
-def needs_symlinks(fn):
- """Decorator that marks a test as requiring a path class that supports symlinks."""
- _tests_needing_symlinks.add(fn.__name__)
- return fn
-
class UnsupportedOperationTest(unittest.TestCase):
def test_is_notimplemented(self):
@@ -1369,7 +1362,6 @@ class PathBaseTest(PurePathBaseTest):
self.assertRaises(e, p.glob, '*')
self.assertRaises(e, p.rglob, '*')
self.assertRaises(e, lambda: list(p.walk()))
- self.assertRaises(e, p.absolute)
self.assertRaises(e, p.expanduser)
self.assertRaises(e, p.readlink)
self.assertRaises(e, p.symlink_to, 'foo')
@@ -1425,7 +1417,6 @@ class DummyPath(PathBase):
_files = {}
_directories = {}
- _symlinks = {}
def __eq__(self, other):
if not isinstance(other, DummyPath):
@@ -1439,16 +1430,11 @@ class DummyPath(PathBase):
return "{}({!r})".format(self.__class__.__name__, self.as_posix())
def stat(self, *, follow_symlinks=True):
- if follow_symlinks or self.name in ('', '.', '..'):
- path = str(self.resolve(strict=True))
- else:
- path = str(self.parent.resolve(strict=True) / self.name)
+ path = str(self).rstrip('/')
if path in self._files:
st_mode = stat.S_IFREG
elif path in self._directories:
st_mode = stat.S_IFDIR
- elif path in self._symlinks:
- st_mode = stat.S_IFLNK
else:
raise FileNotFoundError(errno.ENOENT, "Not found", str(self))
return DummyPathStatResult(st_mode, hash(str(self)), 0, 0, 0, 0, 0, 0, 0, 0)
@@ -1457,10 +1443,7 @@ class DummyPath(PathBase):
errors=None, newline=None):
if buffering != -1 and not (buffering == 0 and 'b' in mode):
raise NotImplementedError
- path_obj = self.resolve()
- path = str(path_obj)
- name = path_obj.name
- parent = str(path_obj.parent)
+ path = str(self)
if path in self._directories:
raise IsADirectoryError(errno.EISDIR, "Is a directory", path)
@@ -1471,6 +1454,7 @@ class DummyPath(PathBase):
raise FileNotFoundError(errno.ENOENT, "File not found", path)
stream = io.BytesIO(self._files[path])
elif mode == 'w':
+ parent, name = posixpath.split(path)
if parent not in self._directories:
raise FileNotFoundError(errno.ENOENT, "File not found", parent)
stream = DummyPathIO(self._files, path)
@@ -1483,7 +1467,7 @@ class DummyPath(PathBase):
return stream
def iterdir(self):
- path = str(self.resolve())
+ path = str(self).rstrip('/')
if path in self._files:
raise NotADirectoryError(errno.ENOTDIR, "Not a directory", path)
elif path in self._directories:
@@ -1492,9 +1476,9 @@ class DummyPath(PathBase):
raise FileNotFoundError(errno.ENOENT, "File not found", path)
def mkdir(self, mode=0o777, parents=False, exist_ok=False):
- path = str(self.parent.resolve() / self.name)
- parent = str(self.parent.resolve())
- if path in self._directories or path in self._symlinks:
+ path = str(self)
+ parent = str(self.parent)
+ if path in self._directories:
if exist_ok:
return
else:
@@ -1510,33 +1494,28 @@ class DummyPath(PathBase):
self.mkdir(mode, parents=False, exist_ok=exist_ok)
def unlink(self, missing_ok=False):
- path_obj = self.parent.resolve(strict=True) / self.name
- path = str(path_obj)
- name = path_obj.name
- parent = str(path_obj.parent)
+ path = str(self)
+ name = self.name
+ parent = str(self.parent)
if path in self._directories:
raise IsADirectoryError(errno.EISDIR, "Is a directory", path)
elif path in self._files:
self._directories[parent].remove(name)
del self._files[path]
- elif path in self._symlinks:
- self._directories[parent].remove(name)
- del self._symlinks[path]
elif not missing_ok:
raise FileNotFoundError(errno.ENOENT, "File not found", path)
def rmdir(self):
- path_obj = self.parent.resolve(strict=True) / self.name
- path = str(path_obj)
- if path in self._files or path in self._symlinks:
+ path = str(self)
+ if path in self._files:
raise NotADirectoryError(errno.ENOTDIR, "Not a directory", path)
elif path not in self._directories:
raise FileNotFoundError(errno.ENOENT, "File not found", path)
elif self._directories[path]:
raise OSError(errno.ENOTEMPTY, "Directory not empty", path)
else:
- name = path_obj.name
- parent = str(path_obj.parent)
+ name = self.name
+ parent = str(self.parent)
self._directories[parent].remove(name)
del self._directories[path]
@@ -1569,9 +1548,6 @@ class DummyPathTest(DummyPurePathTest):
def setUp(self):
super().setUp()
- name = self.id().split('.')[-1]
- if name in _tests_needing_symlinks and not self.can_symlink:
- self.skipTest('requires symlinks')
parser = self.cls.parser
p = self.cls(self.base)
p.mkdir(parents=True)
@@ -1604,7 +1580,6 @@ class DummyPathTest(DummyPurePathTest):
cls = self.cls
cls._files.clear()
cls._directories.clear()
- cls._symlinks.clear()
def tempdir(self):
path = self.cls(self.base).with_name('tmp-dirD')
@@ -1730,101 +1705,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertTrue(target.exists())
self.assertEqual(source.read_text(), target.read_text())
- @needs_symlinks
- def test_copy_symlink_follow_symlinks_true(self):
- base = self.cls(self.base)
- source = base / 'linkA'
- target = base / 'copyA'
- result = source.copy(target)
- self.assertEqual(result, target)
- self.assertTrue(target.exists())
- self.assertFalse(target.is_symlink())
- self.assertEqual(source.read_text(), target.read_text())
-
- @needs_symlinks
- def test_copy_symlink_follow_symlinks_false(self):
- base = self.cls(self.base)
- source = base / 'linkA'
- target = base / 'copyA'
- result = source.copy(target, follow_symlinks=False)
- self.assertEqual(result, target)
- self.assertTrue(target.exists())
- self.assertTrue(target.is_symlink())
- self.assertEqual(source.readlink(), target.readlink())
-
- @needs_symlinks
- def test_copy_symlink_to_itself(self):
- base = self.cls(self.base)
- source = base / 'linkA'
- self.assertRaises(OSError, source.copy, source)
-
- @needs_symlinks
- def test_copy_symlink_to_existing_symlink(self):
- base = self.cls(self.base)
- source = base / 'copySource'
- target = base / 'copyTarget'
- source.symlink_to(base / 'fileA')
- target.symlink_to(base / 'dirC')
- self.assertRaises(OSError, source.copy, target)
- self.assertRaises(OSError, source.copy, target, follow_symlinks=False)
-
- @needs_symlinks
- def test_copy_symlink_to_existing_directory_symlink(self):
- base = self.cls(self.base)
- source = base / 'copySource'
- target = base / 'copyTarget'
- source.symlink_to(base / 'fileA')
- target.symlink_to(base / 'dirC')
- self.assertRaises(OSError, source.copy, target)
- self.assertRaises(OSError, source.copy, target, follow_symlinks=False)
-
- @needs_symlinks
- def test_copy_directory_symlink_follow_symlinks_false(self):
- base = self.cls(self.base)
- source = base / 'linkB'
- target = base / 'copyA'
- result = source.copy(target, follow_symlinks=False)
- self.assertEqual(result, target)
- self.assertTrue(target.exists())
- self.assertTrue(target.is_symlink())
- self.assertEqual(source.readlink(), target.readlink())
-
- @needs_symlinks
- def test_copy_directory_symlink_to_itself(self):
- base = self.cls(self.base)
- source = base / 'linkB'
- self.assertRaises(OSError, source.copy, source)
- self.assertRaises(OSError, source.copy, source, follow_symlinks=False)
-
- @needs_symlinks
- def test_copy_directory_symlink_into_itself(self):
- base = self.cls(self.base)
- source = base / 'linkB'
- target = base / 'linkB' / 'copyB'
- self.assertRaises(OSError, source.copy, target)
- self.assertRaises(OSError, source.copy, target, follow_symlinks=False)
- self.assertFalse(target.exists())
-
- @needs_symlinks
- def test_copy_directory_symlink_to_existing_symlink(self):
- base = self.cls(self.base)
- source = base / 'copySource'
- target = base / 'copyTarget'
- source.symlink_to(base / 'dirC')
- target.symlink_to(base / 'fileA')
- self.assertRaises(FileExistsError, source.copy, target)
- self.assertRaises(FileExistsError, source.copy, target, follow_symlinks=False)
-
- @needs_symlinks
- def test_copy_directory_symlink_to_existing_directory_symlink(self):
- base = self.cls(self.base)
- source = base / 'copySource'
- target = base / 'copyTarget'
- source.symlink_to(base / 'dirC' / 'dirD')
- target.symlink_to(base / 'dirC')
- self.assertRaises(FileExistsError, source.copy, target)
- self.assertRaises(FileExistsError, source.copy, target, follow_symlinks=False)
-
def test_copy_file_to_existing_file(self):
base = self.cls(self.base)
source = base / 'fileA'
@@ -1840,34 +1720,6 @@ class DummyPathTest(DummyPurePathTest):
target = base / 'dirA'
self.assertRaises(OSError, source.copy, target)
- @needs_symlinks
- def test_copy_file_to_existing_symlink(self):
- base = self.cls(self.base)
- source = base / 'dirB' / 'fileB'
- target = base / 'linkA'
- real_target = base / 'fileA'
- result = source.copy(target)
- self.assertEqual(result, target)
- self.assertTrue(target.exists())
- self.assertTrue(target.is_symlink())
- self.assertTrue(real_target.exists())
- self.assertFalse(real_target.is_symlink())
- self.assertEqual(source.read_text(), real_target.read_text())
-
- @needs_symlinks
- def test_copy_file_to_existing_symlink_follow_symlinks_false(self):
- base = self.cls(self.base)
- source = base / 'dirB' / 'fileB'
- target = base / 'linkA'
- real_target = base / 'fileA'
- result = source.copy(target, follow_symlinks=False)
- self.assertEqual(result, target)
- self.assertTrue(target.exists())
- self.assertTrue(target.is_symlink())
- self.assertTrue(real_target.exists())
- self.assertFalse(real_target.is_symlink())
- self.assertEqual(source.read_text(), real_target.read_text())
-
def test_copy_file_empty(self):
base = self.cls(self.base)
source = base / 'empty'
@@ -1985,23 +1837,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertRaises(OSError, source.copy, target, follow_symlinks=False)
self.assertFalse(target.exists())
- @needs_symlinks
- def test_copy_dangling_symlink(self):
- base = self.cls(self.base)
- source = base / 'source'
- target = base / 'target'
-
- source.mkdir()
- source.joinpath('link').symlink_to('nonexistent')
-
- self.assertRaises(FileNotFoundError, source.copy, target)
-
- target2 = base / 'target2'
- result = source.copy(target2, follow_symlinks=False)
- self.assertEqual(result, target2)
- self.assertTrue(target2.joinpath('link').is_symlink())
- self.assertEqual(target2.joinpath('link').readlink(), self.cls('nonexistent'))
-
def test_copy_into(self):
base = self.cls(self.base)
source = base / 'fileA'
@@ -2087,54 +1922,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertTrue(source.exists())
self.assertFalse(target.exists())
- @needs_symlinks
- def test_move_file_symlink(self):
- base = self.cls(self.base)
- source = base / 'linkA'
- source_readlink = source.readlink()
- target = base / 'linkA_moved'
- result = source.move(target)
- self.assertEqual(result, target)
- self.assertFalse(source.exists())
- self.assertTrue(target.is_symlink())
- self.assertEqual(source_readlink, target.readlink())
-
- @needs_symlinks
- def test_move_file_symlink_to_itself(self):
- base = self.cls(self.base)
- source = base / 'linkA'
- self.assertRaises(OSError, source.move, source)
-
- @needs_symlinks
- def test_move_dir_symlink(self):
- base = self.cls(self.base)
- source = base / 'linkB'
- source_readlink = source.readlink()
- target = base / 'linkB_moved'
- result = source.move(target)
- self.assertEqual(result, target)
- self.assertFalse(source.exists())
- self.assertTrue(target.is_symlink())
- self.assertEqual(source_readlink, target.readlink())
-
- @needs_symlinks
- def test_move_dir_symlink_to_itself(self):
- base = self.cls(self.base)
- source = base / 'linkB'
- self.assertRaises(OSError, source.move, source)
-
- @needs_symlinks
- def test_move_dangling_symlink(self):
- base = self.cls(self.base)
- source = base / 'brokenLink'
- source_readlink = source.readlink()
- target = base / 'brokenLink_moved'
- result = source.move(target)
- self.assertEqual(result, target)
- self.assertFalse(source.exists())
- self.assertTrue(target.is_symlink())
- self.assertEqual(source_readlink, target.readlink())
-
def test_move_into(self):
base = self.cls(self.base)
source = base / 'fileA'
@@ -2161,15 +1948,6 @@ class DummyPathTest(DummyPurePathTest):
expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop']
self.assertEqual(paths, { P(self.base, q) for q in expected })
- @needs_symlinks
- def test_iterdir_symlink(self):
- # __iter__ on a symlink to a directory.
- P = self.cls
- p = P(self.base, 'linkB')
- paths = set(p.iterdir())
- expected = { P(self.base, 'linkB', q) for q in ['fileB', 'linkD'] }
- self.assertEqual(paths, expected)
-
def test_iterdir_nodir(self):
# __iter__ on something that is not a directory.
p = self.cls(self.base, 'fileA')
@@ -2196,7 +1974,6 @@ class DummyPathTest(DummyPurePathTest):
if entry.name != 'brokenLinkLoop':
self.assertEqual(entry.is_dir(), child.is_dir())
-
def test_glob_common(self):
def _check(glob, expected):
self.assertEqual(set(glob), { P(self.base, q) for q in expected })
@@ -2250,8 +2027,6 @@ class DummyPathTest(DummyPurePathTest):
P = self.cls
p = P(self.base)
self.assertEqual(list(p.glob("")), [p])
- self.assertEqual(list(p.glob(".")), [p / "."])
- self.assertEqual(list(p.glob("./")), [p / "./"])
def test_glob_case_sensitive(self):
P = self.cls
@@ -2265,44 +2040,6 @@ class DummyPathTest(DummyPurePathTest):
_check(path, "dirb/file*", True, [])
_check(path, "dirb/file*", False, ["dirB/fileB"])
- @needs_symlinks
- @unittest.skipIf(is_emscripten, "Hangs")
- def test_glob_recurse_symlinks_common(self):
- def _check(path, glob, expected):
- actual = {path for path in path.glob(glob, recurse_symlinks=True)
- if path.parts.count("linkD") <= 1} # exclude symlink loop.
- self.assertEqual(actual, { P(self.base, q) for q in expected })
- P = self.cls
- p = P(self.base)
- _check(p, "fileB", [])
- _check(p, "dir*/file*", ["dirB/fileB", "dirC/fileC"])
- _check(p, "*A", ["dirA", "fileA", "linkA"])
- _check(p, "*B/*", ["dirB/fileB", "dirB/linkD", "linkB/fileB", "linkB/linkD"])
- _check(p, "*/fileB", ["dirB/fileB", "linkB/fileB"])
- _check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"])
- _check(p, "dir*/*/..", ["dirC/dirD/..", "dirA/linkC/..", "dirB/linkD/.."])
- _check(p, "dir*/**", [
- "dirA/", "dirA/linkC", "dirA/linkC/fileB", "dirA/linkC/linkD", "dirA/linkC/linkD/fileB",
- "dirB/", "dirB/fileB", "dirB/linkD", "dirB/linkD/fileB",
- "dirC/", "dirC/fileC", "dirC/dirD", "dirC/dirD/fileD", "dirC/novel.txt",
- "dirE/"])
- _check(p, "dir*/**/", ["dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/",
- "dirC/", "dirC/dirD/", "dirE/"])
- _check(p, "dir*/**/..", ["dirA/..", "dirA/linkC/..", "dirB/..",
- "dirB/linkD/..", "dirA/linkC/linkD/..",
- "dirC/..", "dirC/dirD/..", "dirE/.."])
- _check(p, "dir*/*/**", [
- "dirA/linkC/", "dirA/linkC/linkD", "dirA/linkC/fileB", "dirA/linkC/linkD/fileB",
- "dirB/linkD/", "dirB/linkD/fileB",
- "dirC/dirD/", "dirC/dirD/fileD"])
- _check(p, "dir*/*/**/", ["dirA/linkC/", "dirA/linkC/linkD/", "dirB/linkD/", "dirC/dirD/"])
- _check(p, "dir*/*/**/..", ["dirA/linkC/..", "dirA/linkC/linkD/..",
- "dirB/linkD/..", "dirC/dirD/.."])
- _check(p, "dir*/**/fileC", ["dirC/fileC"])
- _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD/"])
- _check(p, "*/dirD/**", ["dirC/dirD/", "dirC/dirD/fileD"])
- _check(p, "*/dirD/**/", ["dirC/dirD/"])
-
def test_rglob_recurse_symlinks_false(self):
def _check(path, glob, expected):
actual = set(path.rglob(glob, recurse_symlinks=False))
@@ -2361,252 +2098,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertEqual(set(p.rglob("FILEd")), { P(self.base, "dirC/dirD/fileD") })
self.assertEqual(set(p.rglob("*\\")), { P(self.base, "dirC/dirD/") })
- @needs_symlinks
- @unittest.skipIf(is_emscripten, "Hangs")
- def test_rglob_recurse_symlinks_common(self):
- def _check(path, glob, expected):
- actual = {path for path in path.rglob(glob, recurse_symlinks=True)
- if path.parts.count("linkD") <= 1} # exclude symlink loop.
- self.assertEqual(actual, { P(self.base, q) for q in expected })
- P = self.cls
- p = P(self.base)
- _check(p, "fileB", ["dirB/fileB", "dirA/linkC/fileB", "linkB/fileB",
- "dirA/linkC/linkD/fileB", "dirB/linkD/fileB", "linkB/linkD/fileB"])
- _check(p, "*/fileA", [])
- _check(p, "*/fileB", ["dirB/fileB", "dirA/linkC/fileB", "linkB/fileB",
- "dirA/linkC/linkD/fileB", "dirB/linkD/fileB", "linkB/linkD/fileB"])
- _check(p, "file*", ["fileA", "dirA/linkC/fileB", "dirB/fileB",
- "dirA/linkC/linkD/fileB", "dirB/linkD/fileB", "linkB/linkD/fileB",
- "dirC/fileC", "dirC/dirD/fileD", "linkB/fileB"])
- _check(p, "*/", ["dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/",
- "dirC/", "dirC/dirD/", "dirE/", "linkB/", "linkB/linkD/"])
- _check(p, "", ["", "dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/",
- "dirC/", "dirE/", "dirC/dirD/", "linkB/", "linkB/linkD/"])
-
- p = P(self.base, "dirC")
- _check(p, "*", ["dirC/fileC", "dirC/novel.txt",
- "dirC/dirD", "dirC/dirD/fileD"])
- _check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"])
- _check(p, "*/*", ["dirC/dirD/fileD"])
- _check(p, "*/", ["dirC/dirD/"])
- _check(p, "", ["dirC/", "dirC/dirD/"])
- # gh-91616, a re module regression
- _check(p, "*.txt", ["dirC/novel.txt"])
- _check(p, "*.*", ["dirC/novel.txt"])
-
- @needs_symlinks
- def test_rglob_symlink_loop(self):
- # Don't get fooled by symlink loops (Issue #26012).
- P = self.cls
- p = P(self.base)
- given = set(p.rglob('*', recurse_symlinks=False))
- expect = {'brokenLink',
- 'dirA', 'dirA/linkC',
- 'dirB', 'dirB/fileB', 'dirB/linkD',
- 'dirC', 'dirC/dirD', 'dirC/dirD/fileD',
- 'dirC/fileC', 'dirC/novel.txt',
- 'dirE',
- 'fileA',
- 'linkA',
- 'linkB',
- 'brokenLinkLoop',
- }
- self.assertEqual(given, {p / x for x in expect})
-
- # See https://github.com/WebAssembly/wasi-filesystem/issues/26
- @unittest.skipIf(is_wasi, "WASI resolution of '..' parts doesn't match POSIX")
- def test_glob_dotdot(self):
- # ".." is not special in globs.
- P = self.cls
- p = P(self.base)
- self.assertEqual(set(p.glob("..")), { P(self.base, "..") })
- self.assertEqual(set(p.glob("../..")), { P(self.base, "..", "..") })
- self.assertEqual(set(p.glob("dirA/..")), { P(self.base, "dirA", "..") })
- self.assertEqual(set(p.glob("dirA/../file*")), { P(self.base, "dirA/../fileA") })
- self.assertEqual(set(p.glob("dirA/../file*/..")), set())
- self.assertEqual(set(p.glob("../xyzzy")), set())
- if self.cls.parser is posixpath:
- self.assertEqual(set(p.glob("xyzzy/..")), set())
- else:
- # ".." segments are normalized first on Windows, so this path is stat()able.
- self.assertEqual(set(p.glob("xyzzy/..")), { P(self.base, "xyzzy", "..") })
- self.assertEqual(set(p.glob("/".join([".."] * 50))), { P(self.base, *[".."] * 50)})
-
- @needs_symlinks
- def test_glob_permissions(self):
- # See bpo-38894
- P = self.cls
- base = P(self.base) / 'permissions'
- base.mkdir()
-
- for i in range(100):
- link = base / f"link{i}"
- if i % 2:
- link.symlink_to(P(self.base, "dirE", "nonexistent"))
- else:
- link.symlink_to(P(self.base, "dirC"), target_is_directory=True)
-
- self.assertEqual(len(set(base.glob("*"))), 100)
- self.assertEqual(len(set(base.glob("*/"))), 50)
- self.assertEqual(len(set(base.glob("*/fileC"))), 50)
- self.assertEqual(len(set(base.glob("*/file*"))), 50)
-
- @needs_symlinks
- def test_glob_long_symlink(self):
- # See gh-87695
- base = self.cls(self.base) / 'long_symlink'
- base.mkdir()
- bad_link = base / 'bad_link'
- bad_link.symlink_to("bad" * 200)
- self.assertEqual(sorted(base.glob('**/*')), [bad_link])
-
- @needs_posix
- def test_absolute_posix(self):
- P = self.cls
- # The default implementation uses '/' as the current directory
- self.assertEqual(str(P('').absolute()), '/')
- self.assertEqual(str(P('a').absolute()), '/a')
- self.assertEqual(str(P('a/b').absolute()), '/a/b')
-
- self.assertEqual(str(P('/').absolute()), '/')
- self.assertEqual(str(P('/a').absolute()), '/a')
- self.assertEqual(str(P('/a/b').absolute()), '/a/b')
-
- # '//'-prefixed absolute path (supported by POSIX).
- self.assertEqual(str(P('//').absolute()), '//')
- self.assertEqual(str(P('//a').absolute()), '//a')
- self.assertEqual(str(P('//a/b').absolute()), '//a/b')
-
- @needs_symlinks
- def test_readlink(self):
- P = self.cls(self.base)
- self.assertEqual((P / 'linkA').readlink(), self.cls('fileA'))
- self.assertEqual((P / 'brokenLink').readlink(),
- self.cls('non-existing'))
- self.assertEqual((P / 'linkB').readlink(), self.cls('dirB'))
- self.assertEqual((P / 'linkB' / 'linkD').readlink(), self.cls('../dirB'))
- with self.assertRaises(OSError):
- (P / 'fileA').readlink()
-
- @unittest.skipIf(hasattr(os, "readlink"), "os.readlink() is present")
- def test_readlink_unsupported(self):
- P = self.cls(self.base)
- p = P / 'fileA'
- with self.assertRaises(UnsupportedOperation):
- q.readlink(p)
-
- def _check_resolve(self, p, expected, strict=True):
- q = p.resolve(strict)
- self.assertEqual(q, expected)
-
- # This can be used to check both relative and absolute resolutions.
- _check_resolve_relative = _check_resolve_absolute = _check_resolve
-
- @needs_symlinks
- def test_resolve_common(self):
- P = self.cls
- p = P(self.base, 'foo')
- with self.assertRaises(OSError) as cm:
- p.resolve(strict=True)
- self.assertEqual(cm.exception.errno, errno.ENOENT)
- # Non-strict
- parser = self.parser
- self.assertEqualNormCase(str(p.resolve(strict=False)),
- parser.join(self.base, 'foo'))
- p = P(self.base, 'foo', 'in', 'spam')
- self.assertEqualNormCase(str(p.resolve(strict=False)),
- parser.join(self.base, 'foo', 'in', 'spam'))
- p = P(self.base, '..', 'foo', 'in', 'spam')
- self.assertEqualNormCase(str(p.resolve(strict=False)),
- parser.join(parser.dirname(self.base), 'foo', 'in', 'spam'))
- # These are all relative symlinks.
- p = P(self.base, 'dirB', 'fileB')
- self._check_resolve_relative(p, p)
- p = P(self.base, 'linkA')
- self._check_resolve_relative(p, P(self.base, 'fileA'))
- p = P(self.base, 'dirA', 'linkC', 'fileB')
- self._check_resolve_relative(p, P(self.base, 'dirB', 'fileB'))
- p = P(self.base, 'dirB', 'linkD', 'fileB')
- self._check_resolve_relative(p, P(self.base, 'dirB', 'fileB'))
- # Non-strict
- p = P(self.base, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam')
- self._check_resolve_relative(p, P(self.base, 'dirB', 'fileB', 'foo', 'in',
- 'spam'), False)
- p = P(self.base, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
- if self.cls.parser is not posixpath:
- # In Windows, if linkY points to dirB, 'dirA\linkY\..'
- # resolves to 'dirA' without resolving linkY first.
- self._check_resolve_relative(p, P(self.base, 'dirA', 'foo', 'in',
- 'spam'), False)
- else:
- # In Posix, if linkY points to dirB, 'dirA/linkY/..'
- # resolves to 'dirB/..' first before resolving to parent of dirB.
- self._check_resolve_relative(p, P(self.base, 'foo', 'in', 'spam'), False)
- # Now create absolute symlinks.
- d = self.tempdir()
- P(self.base, 'dirA', 'linkX').symlink_to(d)
- P(self.base, str(d), 'linkY').symlink_to(self.parser.join(self.base, 'dirB'))
- p = P(self.base, 'dirA', 'linkX', 'linkY', 'fileB')
- self._check_resolve_absolute(p, P(self.base, 'dirB', 'fileB'))
- # Non-strict
- p = P(self.base, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam')
- self._check_resolve_relative(p, P(self.base, 'dirB', 'foo', 'in', 'spam'),
- False)
- p = P(self.base, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
- if self.cls.parser is not posixpath:
- # In Windows, if linkY points to dirB, 'dirA\linkY\..'
- # resolves to 'dirA' without resolving linkY first.
- self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False)
- else:
- # In Posix, if linkY points to dirB, 'dirA/linkY/..'
- # resolves to 'dirB/..' first before resolving to parent of dirB.
- self._check_resolve_relative(p, P(self.base, 'foo', 'in', 'spam'), False)
-
- @needs_symlinks
- def test_resolve_dot(self):
- # See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/
- parser = self.parser
- p = self.cls(self.base)
- p.joinpath('0').symlink_to('.', target_is_directory=True)
- p.joinpath('1').symlink_to(parser.join('0', '0'), target_is_directory=True)
- p.joinpath('2').symlink_to(parser.join('1', '1'), target_is_directory=True)
- q = p / '2'
- self.assertEqual(q.resolve(strict=True), p)
- r = q / '3' / '4'
- self.assertRaises(FileNotFoundError, r.resolve, strict=True)
- # Non-strict
- self.assertEqual(r.resolve(strict=False), p / '3' / '4')
-
- def _check_symlink_loop(self, *args):
- path = self.cls(*args)
- with self.assertRaises(OSError) as cm:
- path.resolve(strict=True)
- self.assertEqual(cm.exception.errno, errno.ELOOP)
-
- @needs_posix
- @needs_symlinks
- def test_resolve_loop(self):
- # Loops with relative symlinks.
- self.cls(self.base, 'linkX').symlink_to('linkX/inside')
- self._check_symlink_loop(self.base, 'linkX')
- self.cls(self.base, 'linkY').symlink_to('linkY')
- self._check_symlink_loop(self.base, 'linkY')
- self.cls(self.base, 'linkZ').symlink_to('linkZ/../linkZ')
- self._check_symlink_loop(self.base, 'linkZ')
- # Non-strict
- p = self.cls(self.base, 'linkZ', 'foo')
- self.assertEqual(p.resolve(strict=False), p)
- # Loops with absolute symlinks.
- self.cls(self.base, 'linkU').symlink_to(self.parser.join(self.base, 'linkU/inside'))
- self._check_symlink_loop(self.base, 'linkU')
- self.cls(self.base, 'linkV').symlink_to(self.parser.join(self.base, 'linkV'))
- self._check_symlink_loop(self.base, 'linkV')
- self.cls(self.base, 'linkW').symlink_to(self.parser.join(self.base, 'linkW/../linkW'))
- self._check_symlink_loop(self.base, 'linkW')
- # Non-strict
- q = self.cls(self.base, 'linkW', 'foo')
- self.assertEqual(q.resolve(strict=False), q)
-
def test_stat(self):
statA = self.cls(self.base).joinpath('fileA').stat()
statB = self.cls(self.base).joinpath('dirB', 'fileB').stat()
@@ -2627,12 +2118,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertEqual(statA.st_dev, statC.st_dev)
# other attributes not used by pathlib.
- @needs_symlinks
- def test_stat_no_follow_symlinks(self):
- p = self.cls(self.base) / 'linkA'
- st = p.stat()
- self.assertNotEqual(st, p.stat(follow_symlinks=False))
-
def test_stat_no_follow_symlinks_nosymlink(self):
p = self.cls(self.base) / 'fileA'
st = p.stat()
@@ -2760,41 +2245,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertIs((P / 'fileA\udfff').is_char_device(), False)
self.assertIs((P / 'fileA\x00').is_char_device(), False)
- def _check_complex_symlinks(self, link0_target):
- # Test solving a non-looping chain of symlinks (issue #19887).
- parser = self.parser
- P = self.cls(self.base)
- P.joinpath('link1').symlink_to(parser.join('link0', 'link0'), target_is_directory=True)
- P.joinpath('link2').symlink_to(parser.join('link1', 'link1'), target_is_directory=True)
- P.joinpath('link3').symlink_to(parser.join('link2', 'link2'), target_is_directory=True)
- P.joinpath('link0').symlink_to(link0_target, target_is_directory=True)
-
- # Resolve absolute paths.
- p = (P / 'link0').resolve()
- self.assertEqual(p, P)
- self.assertEqualNormCase(str(p), self.base)
- p = (P / 'link1').resolve()
- self.assertEqual(p, P)
- self.assertEqualNormCase(str(p), self.base)
- p = (P / 'link2').resolve()
- self.assertEqual(p, P)
- self.assertEqualNormCase(str(p), self.base)
- p = (P / 'link3').resolve()
- self.assertEqual(p, P)
- self.assertEqualNormCase(str(p), self.base)
-
- @needs_symlinks
- def test_complex_symlinks_absolute(self):
- self._check_complex_symlinks(self.base)
-
- @needs_symlinks
- def test_complex_symlinks_relative(self):
- self._check_complex_symlinks('.')
-
- @needs_symlinks
- def test_complex_symlinks_relative_dot_dot(self):
- self._check_complex_symlinks(self.parser.join('dirA', '..'))
-
def test_unlink(self):
p = self.cls(self.base) / 'fileA'
p.unlink()
@@ -2838,41 +2288,6 @@ class DummyPathTest(DummyPurePathTest):
self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'fileC').stat)
self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'novel.txt').stat)
- @needs_symlinks
- def test_delete_symlink(self):
- tmp = self.cls(self.base, 'delete')
- tmp.mkdir()
- dir_ = tmp / 'dir'
- dir_.mkdir()
- link = tmp / 'link'
- link.symlink_to(dir_)
- link._delete()
- self.assertTrue(dir_.exists())
- self.assertFalse(link.exists(follow_symlinks=False))
-
- @needs_symlinks
- def test_delete_inner_symlink(self):
- tmp = self.cls(self.base, 'delete')
- tmp.mkdir()
- dir1 = tmp / 'dir1'
- dir2 = dir1 / 'dir2'
- dir3 = tmp / 'dir3'
- for d in dir1, dir2, dir3:
- d.mkdir()
- file1 = tmp / 'file1'
- file1.write_text('foo')
- link1 = dir1 / 'link1'
- link1.symlink_to(dir2)
- link2 = dir1 / 'link2'
- link2.symlink_to(dir3)
- link3 = dir1 / 'link3'
- link3.symlink_to(file1)
- # make sure symlinks are removed but not followed
- dir1._delete()
- self.assertFalse(dir1.exists())
- self.assertTrue(dir3.exists())
- self.assertTrue(file1.exists())
-
def test_delete_missing(self):
tmp = self.cls(self.base, 'delete')
tmp.mkdir()
@@ -2887,9 +2302,6 @@ class DummyPathWalkTest(unittest.TestCase):
can_symlink = False
def setUp(self):
- name = self.id().split('.')[-1]
- if name in _tests_needing_symlinks and not self.can_symlink:
- self.skipTest('requires symlinks')
# Build:
# TESTFN/
# TEST1/ a file kid and two directory kids
@@ -3002,70 +2414,6 @@ class DummyPathWalkTest(unittest.TestCase):
raise AssertionError(f"Unexpected path: {path}")
self.assertTrue(seen_testfn)
- @needs_symlinks
- def test_walk_follow_symlinks(self):
- walk_it = self.walk_path.walk(follow_symlinks=True)
- for root, dirs, files in walk_it:
- if root == self.link_path:
- self.assertEqual(dirs, [])
- self.assertEqual(files, ["tmp4"])
- break
- else:
- self.fail("Didn't follow symlink with follow_symlinks=True")
-
- @needs_symlinks
- def test_walk_symlink_location(self):
- # Tests whether symlinks end up in filenames or dirnames depending
- # on the `follow_symlinks` argument.
- walk_it = self.walk_path.walk(follow_symlinks=False)
- for root, dirs, files in walk_it:
- if root == self.sub2_path:
- self.assertIn("link", files)
- break
- else:
- self.fail("symlink not found")
-
- walk_it = self.walk_path.walk(follow_symlinks=True)
- for root, dirs, files in walk_it:
- if root == self.sub2_path:
- self.assertIn("link", dirs)
- break
- else:
- self.fail("symlink not found")
-
-
-class DummyPathWithSymlinks(DummyPath):
- __slots__ = ()
-
- # Reduce symlink traversal limit to make tests run faster.
- _max_symlinks = 20
-
- def readlink(self):
- path = str(self.parent.resolve() / self.name)
- if path in self._symlinks:
- return self.with_segments(self._symlinks[path][0])
- elif path in self._files or path in self._directories:
- raise OSError(errno.EINVAL, "Not a symlink", path)
- else:
- raise FileNotFoundError(errno.ENOENT, "File not found", path)
-
- def symlink_to(self, target, target_is_directory=False):
- path = str(self.parent.resolve() / self.name)
- parent = str(self.parent.resolve())
- if path in self._symlinks:
- raise FileExistsError(errno.EEXIST, "File exists", path)
- self._directories[parent].add(self.name)
- self._symlinks[path] = str(target), target_is_directory
-
-
-class DummyPathWithSymlinksTest(DummyPathTest):
- cls = DummyPathWithSymlinks
- can_symlink = True
-
-
-class DummyPathWithSymlinksWalkTest(DummyPathWalkTest):
- cls = DummyPathWithSymlinks
- can_symlink = True
if __name__ == "__main__":