From 594bd8f246947574799d870fabd6f1d8020b14a5 Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Thu, 30 Jun 2022 23:34:21 +0100
Subject: [PATCH 1/7] gh-78707: deprecate passing >1 argument to
 `PurePath.[is_]relative_to()`

This brings `relative_to()` and `is_relative_to()` more in line with other
pathlib methods like `rename()` and `symlink_to()`.
---
 Doc/library/pathlib.rst                       |  4 ++--
 Lib/pathlib.py                                | 21 +++++++++++++------
 Lib/test/test_pathlib.py                      |  6 ++++--
 ...2-07-01-00-01-22.gh-issue-78707.fHGSuM.rst |  3 +++
 4 files changed, 24 insertions(+), 10 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst

diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index 2b798698385fd1..aef4eaec9d2f61 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -490,7 +490,7 @@ Pure paths provide the following methods and properties:
       True
 
 
-.. method:: PurePath.is_relative_to(*other)
+.. method:: PurePath.is_relative_to(other)
 
    Return whether or not this path is relative to the *other* path.
 
@@ -564,7 +564,7 @@ Pure paths provide the following methods and properties:
       True
 
 
-.. method:: PurePath.relative_to(*other)
+.. method:: PurePath.relative_to(other)
 
    Compute a version of this path relative to the path represented by
    *other*.  If it's impossible, ValueError is raised::
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index bb440c9d57216a..5f34ae51cf2100 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -640,7 +640,7 @@ def with_suffix(self, suffix):
         return self._from_parsed_parts(self._drv, self._root,
                                        self._parts[:-1] + [name])
 
-    def relative_to(self, *other):
+    def relative_to(self, other, *args):
         """Return the relative path to another path identified by the passed
         arguments.  If the operation is not possible (because this is not
         a subpath of the other path), raise ValueError.
@@ -649,8 +649,11 @@ def relative_to(self, *other):
         # separate parts, i.e.:
         #   Path('c:/').relative_to('c:')  gives Path('/')
         #   Path('c:/').relative_to('/')   raise ValueError
-        if not other:
-            raise TypeError("need at least one argument")
+        if args:
+            warnings.warn("support for supplying more than one argument to "
+                          "pathlib.PurePath.relative_to() is deprecated and "
+                          "scheduled for removal in Python 3.14.",
+                          DeprecationWarning, stacklevel=2)
         parts = self._parts
         drv = self._drv
         root = self._root
@@ -658,7 +661,7 @@ def relative_to(self, *other):
             abs_parts = [drv, root] + parts[1:]
         else:
             abs_parts = parts
-        to_drv, to_root, to_parts = self._parse_args(other)
+        to_drv, to_root, to_parts = self._parse_args((other,) + args)
         if to_root:
             to_abs_parts = [to_drv, to_root] + to_parts[1:]
         else:
@@ -673,11 +676,17 @@ def relative_to(self, *other):
         return self._from_parsed_parts('', root if n == 1 else '',
                                        abs_parts[n:])
 
-    def is_relative_to(self, *other):
+    def is_relative_to(self, other, *args):
         """Return True if the path is relative to another path or False.
         """
+        if args:
+            warnings.warn("support for supplying more than one argument to "
+                          "pathlib.PurePath.is_relative_to() is deprecated "
+                          "and scheduled for removal in Python 3.14.",
+                          DeprecationWarning, stacklevel=2)
+            other = self._from_parts((other,) + args)
         try:
-            self.relative_to(*other)
+            self.relative_to(other)
             return True
         except ValueError:
             return False
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index a42619853399f2..fee75677f0e465 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -637,7 +637,8 @@ def test_relative_to_common(self):
         self.assertEqual(p.relative_to(P('a/b')), P())
         self.assertEqual(p.relative_to('a/b'), P())
         # With several args.
-        self.assertEqual(p.relative_to('a', 'b'), P())
+        with self.assertWarns(DeprecationWarning):
+            p.relative_to('a', 'b')
         # Unrelated paths.
         self.assertRaises(ValueError, p.relative_to, P('c'))
         self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
@@ -671,7 +672,8 @@ def test_is_relative_to_common(self):
         self.assertTrue(p.is_relative_to(P('a/b')))
         self.assertTrue(p.is_relative_to('a/b'))
         # With several args.
-        self.assertTrue(p.is_relative_to('a', 'b'))
+        with self.assertWarns(DeprecationWarning):
+            p.is_relative_to('a', 'b')
         # Unrelated paths.
         self.assertFalse(p.is_relative_to(P('c')))
         self.assertFalse(p.is_relative_to(P('a/b/c')))
diff --git a/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst b/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst
new file mode 100644
index 00000000000000..25013f476559df
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst
@@ -0,0 +1,3 @@
+Deprecate passing more than one argument to
+:meth:`pathlib.PurePath.relative_to` and
+:meth:`~pathlib.PurePath.is_relative_to`.

From 3268a10a84d9fad25cd001f8e37c0d070a66b65a Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Sat, 9 Jul 2022 02:10:11 +0100
Subject: [PATCH 2/7] Address review feedback

---
 Doc/library/pathlib.rst | 13 ++++++++++++-
 Lib/pathlib.py          | 12 ++++++------
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index aef4eaec9d2f61..fb41d7d9a1f25e 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -502,6 +502,10 @@ Pure paths provide the following methods and properties:
 
    .. versionadded:: 3.9
 
+   .. deprecated:: 3.12
+
+      Support for supplying additional arguments is deprecated; if supplied,
+      they are joined with *other*.
 
 .. method:: PurePath.is_reserved()
 
@@ -581,8 +585,15 @@ Pure paths provide the following methods and properties:
           .format(str(self), str(formatted)))
       ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other absolute.
 
-   NOTE: This function is part of :class:`PurePath` and works with strings. It does not check or access the underlying file structure.
+   .. note:
+
+      This function is part of :class:`PurePath` and works with strings. It
+      does not access the filesystem.
+
+   .. deprecated:: 3.12
 
+      Passing additional arguments is deprecated; if supplied, they are joined
+      with *other*.
 
 .. method:: PurePath.with_name(name)
 
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 5f34ae51cf2100..da8d9a9eca873f 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -640,7 +640,7 @@ def with_suffix(self, suffix):
         return self._from_parsed_parts(self._drv, self._root,
                                        self._parts[:-1] + [name])
 
-    def relative_to(self, other, *args):
+    def relative_to(self, other, /, *_deprecated):
         """Return the relative path to another path identified by the passed
         arguments.  If the operation is not possible (because this is not
         a subpath of the other path), raise ValueError.
@@ -649,7 +649,7 @@ def relative_to(self, other, *args):
         # separate parts, i.e.:
         #   Path('c:/').relative_to('c:')  gives Path('/')
         #   Path('c:/').relative_to('/')   raise ValueError
-        if args:
+        if _deprecated:
             warnings.warn("support for supplying more than one argument to "
                           "pathlib.PurePath.relative_to() is deprecated and "
                           "scheduled for removal in Python 3.14.",
@@ -661,7 +661,7 @@ def relative_to(self, other, *args):
             abs_parts = [drv, root] + parts[1:]
         else:
             abs_parts = parts
-        to_drv, to_root, to_parts = self._parse_args((other,) + args)
+        to_drv, to_root, to_parts = self._parse_args((other,) + _deprecated)
         if to_root:
             to_abs_parts = [to_drv, to_root] + to_parts[1:]
         else:
@@ -676,15 +676,15 @@ def relative_to(self, other, *args):
         return self._from_parsed_parts('', root if n == 1 else '',
                                        abs_parts[n:])
 
-    def is_relative_to(self, other, *args):
+    def is_relative_to(self, other, /, *_deprecated):
         """Return True if the path is relative to another path or False.
         """
-        if args:
+        if _deprecated:
             warnings.warn("support for supplying more than one argument to "
                           "pathlib.PurePath.is_relative_to() is deprecated "
                           "and scheduled for removal in Python 3.14.",
                           DeprecationWarning, stacklevel=2)
-            other = self._from_parts((other,) + args)
+            other = self._from_parts((other,) + _deprecated)
         try:
             self.relative_to(other)
             return True

From 7e8e5537341ec474c79921d8e5aee9c7de4667fa Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Fri, 25 Nov 2022 20:33:19 +0000
Subject: [PATCH 3/7] Use new deprecation mechanism

---
 Lib/pathlib.py | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 78f720401d340f..7890fdade42056 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -633,11 +633,11 @@ def relative_to(self, other, /, *_deprecated, walk_up=False):
         the path.
         """
         if _deprecated:
-            warnings.warn("support for supplying more than one positional "
-                          "argument to pathlib.PurePath.relative_to() is "
-                          "deprecated and scheduled for removal in Python "
-                          "3.14.",
-                          DeprecationWarning, stacklevel=2)
+            msg = ("support for supplying more than one positional argument "
+                   "to pathlib.PurePath.relative_to() is deprecated and "
+                   "scheduled for removal in Python {remove}")
+            warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg,
+                                 remove=(3, 14))
         path_cls = type(self)
         other = path_cls(other, *_deprecated)
         for step, path in enumerate([other] + list(other.parents)):
@@ -654,11 +654,11 @@ def is_relative_to(self, other, /, *_deprecated):
         """Return True if the path is relative to another path or False.
         """
         if _deprecated:
-            warnings.warn("support for supplying more than one argument to "
-                          "pathlib.PurePath.is_relative_to() is deprecated "
-                          "and scheduled for removal in Python 3.14.",
-                          DeprecationWarning, stacklevel=2)
-            other = type(self)(other, *_deprecated)
+            msg = ("support for supplying more than one argument to "
+                   "pathlib.PurePath.is_relative_to() is deprecated and "
+                   "scheduled for removal in Python {remove}")
+            warnings._deprecated("pathlib.PurePath.is_relative_to(*args)",
+                                 msg, remove=(3, 14))
         other = type(self)(other, *_deprecated)
         return other == self or other in self.parents
 

From 6ac36fc1a8ab08c983c472027ec25ba7926e6ce9 Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Fri, 25 Nov 2022 20:38:06 +0000
Subject: [PATCH 4/7] Fix dodgy merge

---
 Lib/test/test_pathlib.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 7beb50e8fba93e..fa6ea0ac63d8da 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -656,8 +656,7 @@ def test_relative_to_common(self):
         # With several args.
         with self.assertWarns(DeprecationWarning):
             p.relative_to('a', 'b')
-        self.assertEqual(p.relative_to('a', 'b'), P())
-        self.assertEqual(p.relative_to('a', 'b', walk_up=True), P())
+            p.relative_to('a', 'b', walk_up=True)
         # Unrelated paths.
         self.assertRaises(ValueError, p.relative_to, P('c'))
         self.assertRaises(ValueError, p.relative_to, P('a/b/c'))

From 00e667768443e34d4bd7561867c1f002bda3b05d Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Fri, 25 Nov 2022 20:39:04 +0000
Subject: [PATCH 5/7] Tweak NEWS now we have `walk_up`.

---
 .../next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst b/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst
index 25013f476559df..c490a3c1bd7ecc 100644
--- a/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst
+++ b/Misc/NEWS.d/next/Library/2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst
@@ -1,3 +1,3 @@
-Deprecate passing more than one argument to
+Deprecate passing more than one positional argument to
 :meth:`pathlib.PurePath.relative_to` and
 :meth:`~pathlib.PurePath.is_relative_to`.

From 6e966baa484594ab6199aab3de9f0622635ba239 Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Fri, 25 Nov 2022 20:42:02 +0000
Subject: [PATCH 6/7] Make deprecation notices uniform.

---
 Doc/library/pathlib.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index a76a76485cfe8a..be3b848c7b0e63 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -504,8 +504,8 @@ Pure paths provide the following methods and properties:
 
    .. deprecated:: 3.12
 
-      Support for supplying additional arguments is deprecated; if supplied,
-      they are joined with *other*.
+      Passing additional arguments is deprecated; if supplied, they are joined
+      with *other*.
 
 .. method:: PurePath.is_reserved()
 
@@ -611,8 +611,8 @@ Pure paths provide the following methods and properties:
 
    .. deprecated:: 3.12
 
-      Passing additional arguments is deprecated; if supplied, they are joined
-      with *other*.
+      Passing additional positional arguments is deprecated; if supplied,
+      they are joined with *other*.
 
 .. method:: PurePath.with_name(name)
 

From 0374a357f71fd85a6e1162550dabca5706b7907b Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Tue, 6 Dec 2022 22:20:36 +0000
Subject: [PATCH 7/7] Apply suggestions from code review

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
---
 Doc/library/pathlib.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index be3b848c7b0e63..47687400c14e3a 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -502,7 +502,7 @@ Pure paths provide the following methods and properties:
 
    .. versionadded:: 3.9
 
-   .. deprecated:: 3.12
+   .. deprecated-removed:: 3.12 3.14
 
       Passing additional arguments is deprecated; if supplied, they are joined
       with *other*.
@@ -609,7 +609,7 @@ Pure paths provide the following methods and properties:
    .. versionadded:: 3.12
       The *walk_up* argument (old behavior is the same as ``walk_up=False``).
 
-   .. deprecated:: 3.12
+   .. deprecated-removed:: 3.12 3.14
 
       Passing additional positional arguments is deprecated; if supplied,
       they are joined with *other*.