https://github.com/python/cpython/commit/f141e8ec2a2e8d21fc08c1f56ef40104c7a7fad2 commit: f141e8ec2a2e8d21fc08c1f56ef40104c7a7fad2 branch: main author: Barney Gale <barney.g...@gmail.com> committer: barneygale <barney.g...@gmail.com> date: 2025-03-20T00:54:36Z summary:
GH-123599: Deprecate duplicate `pathname2url()` implementation (#127380) Call `urllib.request.pathname2url()` from `pathlib.Path.as_uri()`, and deprecate the duplicate implementation in `PurePath`. Co-authored-by: Adam Turner <9087854+aa-tur...@users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2024-11-29-00-53-28.gh-issue-123599.vyUh2S.rst M Doc/library/pathlib.rst M Doc/whatsnew/3.14.rst M Lib/pathlib/__init__.py M Lib/test/test_pathlib/test_pathlib.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index a2955d28d2dd9e..708a16e6bc8c94 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -886,9 +886,11 @@ conforming to :rfc:`8089`. >>> p.as_uri() 'file:///c:/Windows' - For historical reasons, this method is also available from - :class:`PurePath` objects. However, its use of :func:`os.fsencode` makes - it strictly impure. + .. deprecated-removed:: 3.14 3.19 + + Calling this method from :class:`PurePath` rather than :class:`Path` is + possible but deprecated. The method's use of :func:`os.fsencode` makes + it strictly impure. Expanding and resolving paths diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 04b6eb1099b4fd..767cf9a1f08dc2 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1159,6 +1159,11 @@ Deprecated write new code. The :mod:`subprocess` module is recommended instead. (Contributed by Victor Stinner in :gh:`120743`.) +* :mod:`pathlib`: + :meth:`!pathlib.PurePath.as_uri` is deprecated and will be removed in Python + 3.19. Use :meth:`pathlib.Path.as_uri` instead. + (Contributed by Barney Gale in :gh:`123599`.) + * :mod:`pdb`: The undocumented ``pdb.Pdb.curframe_locals`` attribute is now a deprecated read-only property. The low overhead dynamic frame locals access added in diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index f44283a53e5704..a8111cc4f305fa 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -525,13 +525,17 @@ def is_reserved(self): msg = ("pathlib.PurePath.is_reserved() is deprecated and scheduled " "for removal in Python 3.15. Use os.path.isreserved() to " "detect reserved paths on Windows.") - warnings.warn(msg, DeprecationWarning, stacklevel=2) + warnings._deprecated("pathlib.PurePath.is_reserved", msg, remove=(3, 15)) if self.parser is ntpath: return self.parser.isreserved(self) return False def as_uri(self): """Return the path as a URI.""" + import warnings + msg = ("pathlib.PurePath.as_uri() is deprecated and scheduled " + "for removal in Python 3.19. Use pathlib.Path.as_uri().") + warnings._deprecated("pathlib.PurePath.as_uri", msg, remove=(3, 19)) if not self.is_absolute(): raise ValueError("relative path can't be expressed as a file URI") @@ -1266,6 +1270,13 @@ def home(cls): raise RuntimeError("Could not determine home directory.") return cls(homedir) + def as_uri(self): + """Return the path as a URI.""" + if not self.is_absolute(): + raise ValueError("relative paths can't be expressed as file URIs") + from urllib.request import pathname2url + return f'file:{pathname2url(str(self))}' + @classmethod def from_uri(cls, uri): """Return a new path from the given 'file' URI.""" diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index bda94f51968cb2..b1fcc5f6f0538e 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -412,12 +412,18 @@ def assertLess(a, b): with self.assertRaises(TypeError): P() < {} + def make_uri(self, path): + if isinstance(path, pathlib.Path): + return path.as_uri() + with self.assertWarns(DeprecationWarning): + return path.as_uri() + def test_as_uri_common(self): P = self.cls with self.assertRaises(ValueError): - P('a').as_uri() + self.make_uri(P('a')) with self.assertRaises(ValueError): - P().as_uri() + self.make_uri(P()) def test_repr_roundtrips(self): for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): @@ -645,9 +651,9 @@ def test_eq_posix(self): @needs_posix def test_as_uri_posix(self): P = self.cls - self.assertEqual(P('/').as_uri(), 'file:///') - self.assertEqual(P('/a/b.c').as_uri(), 'file:///a/b.c') - self.assertEqual(P('/a/b%#c').as_uri(), 'file:///a/b%25%23c') + self.assertEqual(self.make_uri(P('/')), 'file:///') + self.assertEqual(self.make_uri(P('/a/b.c')), 'file:///a/b.c') + self.assertEqual(self.make_uri(P('/a/b%#c')), 'file:///a/b%25%23c') @needs_posix def test_as_uri_non_ascii(self): @@ -657,7 +663,7 @@ def test_as_uri_non_ascii(self): os.fsencode('\xe9') except UnicodeEncodeError: self.skipTest("\\xe9 cannot be encoded to the filesystem encoding") - self.assertEqual(P('/a/b\xe9').as_uri(), + self.assertEqual(self.make_uri(P('/a/b\xe9')), 'file:///a/b' + quote_from_bytes(os.fsencode('\xe9'))) @needs_posix @@ -751,17 +757,17 @@ def test_eq_windows(self): def test_as_uri_windows(self): P = self.cls with self.assertRaises(ValueError): - P('/a/b').as_uri() + self.make_uri(P('/a/b')) with self.assertRaises(ValueError): - P('c:a/b').as_uri() - self.assertEqual(P('c:/').as_uri(), 'file:///c:/') - self.assertEqual(P('c:/a/b.c').as_uri(), 'file:///c:/a/b.c') - self.assertEqual(P('c:/a/b%#c').as_uri(), 'file:///c:/a/b%25%23c') - self.assertEqual(P('c:/a/b\xe9').as_uri(), 'file:///c:/a/b%C3%A9') - self.assertEqual(P('//some/share/').as_uri(), 'file://some/share/') - self.assertEqual(P('//some/share/a/b.c').as_uri(), + self.make_uri(P('c:a/b')) + self.assertEqual(self.make_uri(P('c:/')), 'file:///c:/') + self.assertEqual(self.make_uri(P('c:/a/b.c')), 'file:///c:/a/b.c') + self.assertEqual(self.make_uri(P('c:/a/b%#c')), 'file:///c:/a/b%25%23c') + self.assertEqual(self.make_uri(P('c:/a/b\xe9')), 'file:///c:/a/b%C3%A9') + self.assertEqual(self.make_uri(P('//some/share/')), 'file://some/share/') + self.assertEqual(self.make_uri(P('//some/share/a/b.c')), 'file://some/share/a/b.c') - self.assertEqual(P('//some/share/a/b%#c\xe9').as_uri(), + self.assertEqual(self.make_uri(P('//some/share/a/b%#c\xe9')), 'file://some/share/a/b%25%23c%C3%A9') @needs_windows diff --git a/Misc/NEWS.d/next/Library/2024-11-29-00-53-28.gh-issue-123599.vyUh2S.rst b/Misc/NEWS.d/next/Library/2024-11-29-00-53-28.gh-issue-123599.vyUh2S.rst new file mode 100644 index 00000000000000..68b63bc085aafb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-29-00-53-28.gh-issue-123599.vyUh2S.rst @@ -0,0 +1,2 @@ +Deprecate :meth:`!pathlib.PurePath.as_uri`; use :meth:`pathlib.Path.as_uri` +instead. _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com