mirror of
https://github.com/python/cpython.git
synced 2025-07-23 11:15:24 +00:00
gh-84538: add strict argument to pathlib.PurePath.relative_to (GH-19813)
By default, :meth:`pathlib.PurePath.relative_to` doesn't deal with paths that are not a direct prefix of the other, raising an exception in that instance. This change adds a *walk_up* parameter that can be set to allow for using ``..`` to calculate the relative path. example: ``` >>> p = PurePosixPath('/etc/passwd') >>> p.relative_to('/etc') PurePosixPath('passwd') >>> p.relative_to('/usr') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "pathlib.py", line 940, in relative_to raise ValueError(error_message.format(str(self), str(formatted))) ValueError: '/etc/passwd' does not start with '/usr' >>> p.relative_to('/usr', strict=False) PurePosixPath('../etc/passwd') ``` https://bugs.python.org/issue40358 Automerge-Triggered-By: GH:brettcannon
This commit is contained in:
parent
72fa57a8fe
commit
e089f23bbb
6 changed files with 150 additions and 21 deletions
|
@ -564,10 +564,10 @@ Pure paths provide the following methods and properties:
|
||||||
True
|
True
|
||||||
|
|
||||||
|
|
||||||
.. method:: PurePath.relative_to(*other)
|
.. method:: PurePath.relative_to(*other, walk_up=False)
|
||||||
|
|
||||||
Compute a version of this path relative to the path represented by
|
Compute a version of this path relative to the path represented by
|
||||||
*other*. If it's impossible, ValueError is raised::
|
*other*. If it's impossible, :exc:`ValueError` is raised::
|
||||||
|
|
||||||
>>> p = PurePosixPath('/etc/passwd')
|
>>> p = PurePosixPath('/etc/passwd')
|
||||||
>>> p.relative_to('/')
|
>>> p.relative_to('/')
|
||||||
|
@ -577,11 +577,33 @@ Pure paths provide the following methods and properties:
|
||||||
>>> p.relative_to('/usr')
|
>>> p.relative_to('/usr')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
File "pathlib.py", line 694, in relative_to
|
File "pathlib.py", line 941, in relative_to
|
||||||
.format(str(self), str(formatted)))
|
raise ValueError(error_message.format(str(self), str(formatted)))
|
||||||
ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other absolute.
|
ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other is absolute.
|
||||||
|
|
||||||
NOTE: This function is part of :class:`PurePath` and works with strings. It does not check or access the underlying file structure.
|
When *walk_up* is False (the default), the path must start with *other*.
|
||||||
|
When the argument is True, ``..`` entries may be added to form the
|
||||||
|
relative path. In all other cases, such as the paths referencing
|
||||||
|
different drives, :exc:`ValueError` is raised.::
|
||||||
|
|
||||||
|
>>> p.relative_to('/usr', walk_up=True)
|
||||||
|
PurePosixPath('../etc/passwd')
|
||||||
|
>>> p.relative_to('foo', walk_up=True)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
File "pathlib.py", line 941, in relative_to
|
||||||
|
raise ValueError(error_message.format(str(self), str(formatted)))
|
||||||
|
ValueError: '/etc/passwd' is not on the same drive as 'foo' OR one path is relative and the other is absolute.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
This function is part of :class:`PurePath` and works with strings.
|
||||||
|
It does not check or access the underlying file structure.
|
||||||
|
This can impact the *walk_up* option as it assumes that no symlinks
|
||||||
|
are present in the path; call :meth:`~Path.resolve` first if
|
||||||
|
necessary to resolve symlinks.
|
||||||
|
|
||||||
|
.. versionadded:: 3.12
|
||||||
|
The *walk_up* argument (old behavior is the same as ``walk_up=False``).
|
||||||
|
|
||||||
|
|
||||||
.. method:: PurePath.with_name(name)
|
.. method:: PurePath.with_name(name)
|
||||||
|
|
|
@ -149,6 +149,11 @@ pathlib
|
||||||
all file or directory names within them, similar to :func:`os.walk`.
|
all file or directory names within them, similar to :func:`os.walk`.
|
||||||
(Contributed by Stanislav Zmiev in :gh:`90385`.)
|
(Contributed by Stanislav Zmiev in :gh:`90385`.)
|
||||||
|
|
||||||
|
* Add *walk_up* optional parameter to :meth:`pathlib.PurePath.relative_to`
|
||||||
|
to allow the insertion of ``..`` entries in the result; this behavior is
|
||||||
|
more consistent with :func:`os.path.relpath`.
|
||||||
|
(Contributed by Domenico Ragusa in :issue:`40358`.)
|
||||||
|
|
||||||
dis
|
dis
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -626,10 +626,13 @@ class PurePath(object):
|
||||||
return self._from_parsed_parts(self._drv, self._root,
|
return self._from_parsed_parts(self._drv, self._root,
|
||||||
self._parts[:-1] + [name])
|
self._parts[:-1] + [name])
|
||||||
|
|
||||||
def relative_to(self, *other):
|
def relative_to(self, *other, walk_up=False):
|
||||||
"""Return the relative path to another path identified by the passed
|
"""Return the relative path to another path identified by the passed
|
||||||
arguments. If the operation is not possible (because this is not
|
arguments. If the operation is not possible (because this is not
|
||||||
a subpath of the other path), raise ValueError.
|
related to the other path), raise ValueError.
|
||||||
|
|
||||||
|
The *walk_up* parameter controls whether `..` may be used to resolve
|
||||||
|
the path.
|
||||||
"""
|
"""
|
||||||
# For the purpose of this method, drive and root are considered
|
# For the purpose of this method, drive and root are considered
|
||||||
# separate parts, i.e.:
|
# separate parts, i.e.:
|
||||||
|
@ -644,20 +647,35 @@ class PurePath(object):
|
||||||
abs_parts = [drv, root] + parts[1:]
|
abs_parts = [drv, root] + parts[1:]
|
||||||
else:
|
else:
|
||||||
abs_parts = parts
|
abs_parts = parts
|
||||||
to_drv, to_root, to_parts = self._parse_args(other)
|
other_drv, other_root, other_parts = self._parse_args(other)
|
||||||
if to_root:
|
if other_root:
|
||||||
to_abs_parts = [to_drv, to_root] + to_parts[1:]
|
other_abs_parts = [other_drv, other_root] + other_parts[1:]
|
||||||
else:
|
else:
|
||||||
to_abs_parts = to_parts
|
other_abs_parts = other_parts
|
||||||
n = len(to_abs_parts)
|
num_parts = len(other_abs_parts)
|
||||||
cf = self._flavour.casefold_parts
|
casefold = self._flavour.casefold_parts
|
||||||
if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
|
num_common_parts = 0
|
||||||
formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
|
for part, other_part in zip(casefold(abs_parts), casefold(other_abs_parts)):
|
||||||
raise ValueError("{!r} is not in the subpath of {!r}"
|
if part != other_part:
|
||||||
" OR one path is relative and the other is absolute."
|
break
|
||||||
.format(str(self), str(formatted)))
|
num_common_parts += 1
|
||||||
return self._from_parsed_parts('', root if n == 1 else '',
|
if walk_up:
|
||||||
abs_parts[n:])
|
failure = root != other_root
|
||||||
|
if drv or other_drv:
|
||||||
|
failure = casefold([drv]) != casefold([other_drv]) or (failure and num_parts > 1)
|
||||||
|
error_message = "{!r} is not on the same drive as {!r}"
|
||||||
|
up_parts = (num_parts-num_common_parts)*['..']
|
||||||
|
else:
|
||||||
|
failure = (root or drv) if num_parts == 0 else num_common_parts != num_parts
|
||||||
|
error_message = "{!r} is not in the subpath of {!r}"
|
||||||
|
up_parts = []
|
||||||
|
error_message += " OR one path is relative and the other is absolute."
|
||||||
|
if failure:
|
||||||
|
formatted = self._format_parsed_parts(other_drv, other_root, other_parts)
|
||||||
|
raise ValueError(error_message.format(str(self), str(formatted)))
|
||||||
|
path_parts = up_parts + abs_parts[num_common_parts:]
|
||||||
|
new_root = root if num_common_parts == 1 else ''
|
||||||
|
return self._from_parsed_parts('', new_root, path_parts)
|
||||||
|
|
||||||
def is_relative_to(self, *other):
|
def is_relative_to(self, *other):
|
||||||
"""Return True if the path is relative to another path or False.
|
"""Return True if the path is relative to another path or False.
|
||||||
|
|
|
@ -640,13 +640,29 @@ class _BasePurePathTest(object):
|
||||||
self.assertEqual(p.relative_to('a/'), P('b'))
|
self.assertEqual(p.relative_to('a/'), P('b'))
|
||||||
self.assertEqual(p.relative_to(P('a/b')), P())
|
self.assertEqual(p.relative_to(P('a/b')), P())
|
||||||
self.assertEqual(p.relative_to('a/b'), P())
|
self.assertEqual(p.relative_to('a/b'), P())
|
||||||
|
self.assertEqual(p.relative_to(P(), walk_up=True), P('a/b'))
|
||||||
|
self.assertEqual(p.relative_to('', walk_up=True), P('a/b'))
|
||||||
|
self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b'))
|
||||||
|
self.assertEqual(p.relative_to('a', walk_up=True), P('b'))
|
||||||
|
self.assertEqual(p.relative_to('a/', walk_up=True), P('b'))
|
||||||
|
self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to('a/b', walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b'))
|
||||||
|
self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b'))
|
||||||
|
self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..'))
|
||||||
|
self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..'))
|
||||||
|
self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b'))
|
||||||
|
self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b'))
|
||||||
# With several args.
|
# With several args.
|
||||||
self.assertEqual(p.relative_to('a', 'b'), P())
|
self.assertEqual(p.relative_to('a', 'b'), P())
|
||||||
|
self.assertEqual(p.relative_to('a', 'b', walk_up=True), P())
|
||||||
# Unrelated paths.
|
# Unrelated paths.
|
||||||
self.assertRaises(ValueError, p.relative_to, P('c'))
|
self.assertRaises(ValueError, p.relative_to, P('c'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
|
self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('a/c'))
|
self.assertRaises(ValueError, p.relative_to, P('a/c'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('/a'))
|
self.assertRaises(ValueError, p.relative_to, P('/a'))
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True)
|
||||||
p = P('/a/b')
|
p = P('/a/b')
|
||||||
self.assertEqual(p.relative_to(P('/')), P('a/b'))
|
self.assertEqual(p.relative_to(P('/')), P('a/b'))
|
||||||
self.assertEqual(p.relative_to('/'), P('a/b'))
|
self.assertEqual(p.relative_to('/'), P('a/b'))
|
||||||
|
@ -655,6 +671,19 @@ class _BasePurePathTest(object):
|
||||||
self.assertEqual(p.relative_to('/a/'), P('b'))
|
self.assertEqual(p.relative_to('/a/'), P('b'))
|
||||||
self.assertEqual(p.relative_to(P('/a/b')), P())
|
self.assertEqual(p.relative_to(P('/a/b')), P())
|
||||||
self.assertEqual(p.relative_to('/a/b'), P())
|
self.assertEqual(p.relative_to('/a/b'), P())
|
||||||
|
self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b'))
|
||||||
|
self.assertEqual(p.relative_to('/', walk_up=True), P('a/b'))
|
||||||
|
self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b'))
|
||||||
|
self.assertEqual(p.relative_to('/a', walk_up=True), P('b'))
|
||||||
|
self.assertEqual(p.relative_to('/a/', walk_up=True), P('b'))
|
||||||
|
self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to('/a/b', walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b'))
|
||||||
|
self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b'))
|
||||||
|
self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..'))
|
||||||
|
self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..'))
|
||||||
|
self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b'))
|
||||||
|
self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b'))
|
||||||
# Unrelated paths.
|
# Unrelated paths.
|
||||||
self.assertRaises(ValueError, p.relative_to, P('/c'))
|
self.assertRaises(ValueError, p.relative_to, P('/c'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('/a/b/c'))
|
self.assertRaises(ValueError, p.relative_to, P('/a/b/c'))
|
||||||
|
@ -662,6 +691,8 @@ class _BasePurePathTest(object):
|
||||||
self.assertRaises(ValueError, p.relative_to, P())
|
self.assertRaises(ValueError, p.relative_to, P())
|
||||||
self.assertRaises(ValueError, p.relative_to, '')
|
self.assertRaises(ValueError, p.relative_to, '')
|
||||||
self.assertRaises(ValueError, p.relative_to, P('a'))
|
self.assertRaises(ValueError, p.relative_to, P('a'))
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True)
|
||||||
|
|
||||||
def test_is_relative_to_common(self):
|
def test_is_relative_to_common(self):
|
||||||
P = self.cls
|
P = self.cls
|
||||||
|
@ -1124,6 +1155,16 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
|
||||||
self.assertEqual(p.relative_to('c:foO/'), P('Bar'))
|
self.assertEqual(p.relative_to('c:foO/'), P('Bar'))
|
||||||
self.assertEqual(p.relative_to(P('c:foO/baR')), P())
|
self.assertEqual(p.relative_to(P('c:foO/baR')), P())
|
||||||
self.assertEqual(p.relative_to('c:foO/baR'), P())
|
self.assertEqual(p.relative_to('c:foO/baR'), P())
|
||||||
|
self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..'))
|
||||||
|
self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar'))
|
||||||
# Unrelated paths.
|
# Unrelated paths.
|
||||||
self.assertRaises(ValueError, p.relative_to, P())
|
self.assertRaises(ValueError, p.relative_to, P())
|
||||||
self.assertRaises(ValueError, p.relative_to, '')
|
self.assertRaises(ValueError, p.relative_to, '')
|
||||||
|
@ -1134,6 +1175,13 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
|
||||||
self.assertRaises(ValueError, p.relative_to, P('C:/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('C:/Foo'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz'))
|
self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz'))
|
self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz'))
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P(), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, '', walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True)
|
||||||
p = P('C:/Foo/Bar')
|
p = P('C:/Foo/Bar')
|
||||||
self.assertEqual(p.relative_to(P('c:')), P('/Foo/Bar'))
|
self.assertEqual(p.relative_to(P('c:')), P('/Foo/Bar'))
|
||||||
self.assertEqual(p.relative_to('c:'), P('/Foo/Bar'))
|
self.assertEqual(p.relative_to('c:'), P('/Foo/Bar'))
|
||||||
|
@ -1146,6 +1194,20 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
|
||||||
self.assertEqual(p.relative_to('c:/foO/'), P('Bar'))
|
self.assertEqual(p.relative_to('c:/foO/'), P('Bar'))
|
||||||
self.assertEqual(p.relative_to(P('c:/foO/baR')), P())
|
self.assertEqual(p.relative_to(P('c:/foO/baR')), P())
|
||||||
self.assertEqual(p.relative_to('c:/foO/baR'), P())
|
self.assertEqual(p.relative_to('c:/foO/baR'), P())
|
||||||
|
self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('/Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:', walk_up=True), P('/Foo/Bar'))
|
||||||
|
self.assertEqual(str(p.relative_to(P('c:'), walk_up=True)), '\\Foo\\Bar')
|
||||||
|
self.assertEqual(str(p.relative_to('c:', walk_up=True)), '\\Foo\\Bar')
|
||||||
|
self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..'))
|
||||||
|
self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar'))
|
||||||
# Unrelated paths.
|
# Unrelated paths.
|
||||||
self.assertRaises(ValueError, p.relative_to, P('C:/Baz'))
|
self.assertRaises(ValueError, p.relative_to, P('C:/Baz'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz'))
|
self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz'))
|
||||||
|
@ -1156,6 +1218,12 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
|
||||||
self.assertRaises(ValueError, p.relative_to, P('/'))
|
self.assertRaises(ValueError, p.relative_to, P('/'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('/Foo'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('//C/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('//C/Foo'))
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True)
|
||||||
# UNC paths.
|
# UNC paths.
|
||||||
p = P('//Server/Share/Foo/Bar')
|
p = P('//Server/Share/Foo/Bar')
|
||||||
self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar'))
|
self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar'))
|
||||||
|
@ -1166,11 +1234,25 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
|
||||||
self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar'))
|
self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar'))
|
||||||
self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P())
|
self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P())
|
||||||
self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P())
|
self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P())
|
||||||
|
self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar'))
|
||||||
|
self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P())
|
||||||
|
self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar'))
|
||||||
|
self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar'))
|
||||||
# Unrelated paths.
|
# Unrelated paths.
|
||||||
self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'))
|
||||||
self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'))
|
self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'))
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True)
|
||||||
|
self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True)
|
||||||
|
|
||||||
def test_is_relative_to(self):
|
def test_is_relative_to(self):
|
||||||
P = self.cls
|
P = self.cls
|
||||||
|
|
|
@ -1440,6 +1440,7 @@ Pierre Quentel
|
||||||
Brian Quinlan
|
Brian Quinlan
|
||||||
Anders Qvist
|
Anders Qvist
|
||||||
Thomas Rachel
|
Thomas Rachel
|
||||||
|
Domenico Ragusa
|
||||||
Ram Rachum
|
Ram Rachum
|
||||||
Jeffrey Rackauckas
|
Jeffrey Rackauckas
|
||||||
Jérôme Radix
|
Jérôme Radix
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add walk_up argument in :meth:`pathlib.PurePath.relative_to`.
|
Loading…
Add table
Add a link
Reference in a new issue