mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +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
|
@ -640,13 +640,29 @@ class _BasePurePathTest(object):
|
|||
self.assertEqual(p.relative_to('a/'), P('b'))
|
||||
self.assertEqual(p.relative_to(P('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.
|
||||
self.assertEqual(p.relative_to('a', 'b'), P())
|
||||
self.assertEqual(p.relative_to('a', 'b', walk_up=True), P())
|
||||
# Unrelated paths.
|
||||
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/c'))
|
||||
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')
|
||||
self.assertEqual(p.relative_to(P('/')), 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(P('/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.
|
||||
self.assertRaises(ValueError, p.relative_to, P('/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, '')
|
||||
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):
|
||||
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(P('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.
|
||||
self.assertRaises(ValueError, p.relative_to, P())
|
||||
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/Bar/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')
|
||||
self.assertEqual(p.relative_to(P('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(P('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.
|
||||
self.assertRaises(ValueError, p.relative_to, P('C:/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('/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.
|
||||
p = P('//Server/Share/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(P('//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.
|
||||
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('//z/Share/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):
|
||||
P = self.cls
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue