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*.