Skip to content

Commit 5a991da

Browse files
authored
gh-78707: deprecate passing >1 argument to PurePath.[is_]relative_to() (GH-94469)
This brings `relative_to()` and `is_relative_to()` more in line with other pathlib methods like `rename()` and `symlink_to()`. Resolves #78707.
1 parent 432117c commit 5a991da

File tree

4 files changed

+35
-14
lines changed

4 files changed

+35
-14
lines changed

Doc/library/pathlib.rst

+11-3
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ Pure paths provide the following methods and properties:
490490
True
491491

492492

493-
.. method:: PurePath.is_relative_to(*other)
493+
.. method:: PurePath.is_relative_to(other)
494494

495495
Return whether or not this path is relative to the *other* path.
496496

@@ -502,6 +502,10 @@ Pure paths provide the following methods and properties:
502502

503503
.. versionadded:: 3.9
504504

505+
.. deprecated-removed:: 3.12 3.14
506+
507+
Passing additional arguments is deprecated; if supplied, they are joined
508+
with *other*.
505509

506510
.. method:: PurePath.is_reserved()
507511

@@ -564,7 +568,7 @@ Pure paths provide the following methods and properties:
564568
True
565569

566570

567-
.. method:: PurePath.relative_to(*other, walk_up=False)
571+
.. method:: PurePath.relative_to(other, walk_up=False)
568572

569573
Compute a version of this path relative to the path represented by
570574
*other*. If it's impossible, :exc:`ValueError` is raised::
@@ -581,7 +585,7 @@ Pure paths provide the following methods and properties:
581585
raise ValueError(error_message.format(str(self), str(formatted)))
582586
ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other is absolute.
583587

584-
When *walk_up* is False (the default), the path must start with *other*.
588+
When *walk_up* is False (the default), the path must start with *other*.
585589
When the argument is True, ``..`` entries may be added to form the
586590
relative path. In all other cases, such as the paths referencing
587591
different drives, :exc:`ValueError` is raised.::
@@ -605,6 +609,10 @@ When *walk_up* is False (the default), the path must start with *other*.
605609
.. versionadded:: 3.12
606610
The *walk_up* argument (old behavior is the same as ``walk_up=False``).
607611

612+
.. deprecated-removed:: 3.12 3.14
613+
614+
Passing additional positional arguments is deprecated; if supplied,
615+
they are joined with *other*.
608616

609617
.. method:: PurePath.with_name(name)
610618

Lib/pathlib.py

+16-8
Original file line numberDiff line numberDiff line change
@@ -624,18 +624,22 @@ def with_suffix(self, suffix):
624624
return self._from_parsed_parts(self._drv, self._root,
625625
self._parts[:-1] + [name])
626626

627-
def relative_to(self, *other, walk_up=False):
627+
def relative_to(self, other, /, *_deprecated, walk_up=False):
628628
"""Return the relative path to another path identified by the passed
629629
arguments. If the operation is not possible (because this is not
630630
related to the other path), raise ValueError.
631631
632632
The *walk_up* parameter controls whether `..` may be used to resolve
633633
the path.
634634
"""
635-
if not other:
636-
raise TypeError("need at least one argument")
635+
if _deprecated:
636+
msg = ("support for supplying more than one positional argument "
637+
"to pathlib.PurePath.relative_to() is deprecated and "
638+
"scheduled for removal in Python {remove}")
639+
warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg,
640+
remove=(3, 14))
637641
path_cls = type(self)
638-
other = path_cls(*other)
642+
other = path_cls(other, *_deprecated)
639643
for step, path in enumerate([other] + list(other.parents)):
640644
if self.is_relative_to(path):
641645
break
@@ -646,12 +650,16 @@ def relative_to(self, *other, walk_up=False):
646650
parts = ('..',) * step + self.parts[len(path.parts):]
647651
return path_cls(*parts)
648652

649-
def is_relative_to(self, *other):
653+
def is_relative_to(self, other, /, *_deprecated):
650654
"""Return True if the path is relative to another path or False.
651655
"""
652-
if not other:
653-
raise TypeError("need at least one argument")
654-
other = type(self)(*other)
656+
if _deprecated:
657+
msg = ("support for supplying more than one argument to "
658+
"pathlib.PurePath.is_relative_to() is deprecated and "
659+
"scheduled for removal in Python {remove}")
660+
warnings._deprecated("pathlib.PurePath.is_relative_to(*args)",
661+
msg, remove=(3, 14))
662+
other = type(self)(other, *_deprecated)
655663
return other == self or other in self.parents
656664

657665
@property

Lib/test/test_pathlib.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -654,8 +654,9 @@ def test_relative_to_common(self):
654654
self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b'))
655655
self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b'))
656656
# With several args.
657-
self.assertEqual(p.relative_to('a', 'b'), P())
658-
self.assertEqual(p.relative_to('a', 'b', walk_up=True), P())
657+
with self.assertWarns(DeprecationWarning):
658+
p.relative_to('a', 'b')
659+
p.relative_to('a', 'b', walk_up=True)
659660
# Unrelated paths.
660661
self.assertRaises(ValueError, p.relative_to, P('c'))
661662
self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
@@ -706,7 +707,8 @@ def test_is_relative_to_common(self):
706707
self.assertTrue(p.is_relative_to(P('a/b')))
707708
self.assertTrue(p.is_relative_to('a/b'))
708709
# With several args.
709-
self.assertTrue(p.is_relative_to('a', 'b'))
710+
with self.assertWarns(DeprecationWarning):
711+
p.is_relative_to('a', 'b')
710712
# Unrelated paths.
711713
self.assertFalse(p.is_relative_to(P('c')))
712714
self.assertFalse(p.is_relative_to(P('a/b/c')))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Deprecate passing more than one positional argument to
2+
:meth:`pathlib.PurePath.relative_to` and
3+
:meth:`~pathlib.PurePath.is_relative_to`.

0 commit comments

Comments
 (0)