From 5a991da32961ef5780996d58b8816d5f2085f540 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 17 Dec 2022 00:14:27 +0000 Subject: 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. --- Doc/library/pathlib.rst | 14 ++++++++++--- Lib/pathlib.py | 24 ++++++++++++++-------- Lib/test/test_pathlib.py | 8 +++++--- .../2022-07-01-00-01-22.gh-issue-78707.fHGSuM.rst | 3 +++ 4 files changed, 35 insertions(+), 14 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 6537637..4768740 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. @@ -502,6 +502,10 @@ Pure paths provide the following methods and properties: .. versionadded:: 3.9 + .. deprecated-removed:: 3.12 3.14 + + Passing additional arguments is deprecated; if supplied, they are joined + with *other*. .. method:: PurePath.is_reserved() @@ -564,7 +568,7 @@ Pure paths provide the following methods and properties: True -.. method:: PurePath.relative_to(*other, walk_up=False) +.. method:: PurePath.relative_to(other, walk_up=False) Compute a version of this path relative to the path represented by *other*. If it's impossible, :exc:`ValueError` is raised:: @@ -581,7 +585,7 @@ Pure paths provide the following methods and properties: 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 is absolute. -When *walk_up* is False (the default), the path must start with *other*. + 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.:: @@ -605,6 +609,10 @@ When *walk_up* is False (the default), the path must start with *other*. .. versionadded:: 3.12 The *walk_up* argument (old behavior is the same as ``walk_up=False``). + .. deprecated-removed:: 3.12 3.14 + + Passing additional positional 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 f31eb30..7890fda 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -624,7 +624,7 @@ class PurePath(object): return self._from_parsed_parts(self._drv, self._root, self._parts[:-1] + [name]) - def relative_to(self, *other, walk_up=False): + def relative_to(self, other, /, *_deprecated, walk_up=False): """Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError. @@ -632,10 +632,14 @@ class PurePath(object): The *walk_up* parameter controls whether `..` may be used to resolve the path. """ - if not other: - raise TypeError("need at least one argument") + if _deprecated: + 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) + other = path_cls(other, *_deprecated) for step, path in enumerate([other] + list(other.parents)): if self.is_relative_to(path): break @@ -646,12 +650,16 @@ class PurePath(object): parts = ('..',) * step + self.parts[len(path.parts):] return path_cls(*parts) - def is_relative_to(self, *other): + def is_relative_to(self, other, /, *_deprecated): """Return True if the path is relative to another path or False. """ - if not other: - raise TypeError("need at least one argument") - other = type(self)(*other) + if _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 @property diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 1d01d3c..fa6ea0a 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -654,8 +654,9 @@ class _BasePurePathTest(object): 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()) + with self.assertWarns(DeprecationWarning): + p.relative_to('a', 'b') + 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')) @@ -706,7 +707,8 @@ class _BasePurePathTest(object): 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 0000000..c490a3c --- /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 positional argument to +:meth:`pathlib.PurePath.relative_to` and +:meth:`~pathlib.PurePath.is_relative_to`. -- cgit v0.12