]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-123599: Deprecate duplicate `pathname2url()` implementation (#127380)
authorBarney Gale <barney.gale@gmail.com>
Thu, 20 Mar 2025 00:54:36 +0000 (00:54 +0000)
committerGitHub <noreply@github.com>
Thu, 20 Mar 2025 00:54:36 +0000 (00:54 +0000)
Call `urllib.request.pathname2url()` from `pathlib.Path.as_uri()`, and
deprecate the duplicate implementation in `PurePath`.

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Doc/library/pathlib.rst
Doc/whatsnew/3.14.rst
Lib/pathlib/__init__.py
Lib/test/test_pathlib/test_pathlib.py
Misc/NEWS.d/next/Library/2024-11-29-00-53-28.gh-issue-123599.vyUh2S.rst [new file with mode: 0644]

index a2955d28d2dd9e26970846544e8056e971d31f88..708a16e6bc8c94916aa89916a87802fa3f14fdd4 100644 (file)
@@ -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
index 04b6eb1099b4fd8635896f5f53c828ca7c797f29..767cf9a1f08dc2a9858dc1bc1454e1f532000f26 100644 (file)
@@ -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
index f44283a53e5704afb06c7171a8de8428f587ebdf..a8111cc4f305faa9e528bfa13ac5a7707bdb4bfd 100644 (file)
@@ -525,13 +525,17 @@ class PurePath:
         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 @@ class Path(PurePath):
             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."""
index bda94f51968cb271715f9cd8b19b2184cc927ad3..b1fcc5f6f0538e895a9993e0e6a9e5670d9e1490 100644 (file)
@@ -412,12 +412,18 @@ class PurePathTest(unittest.TestCase):
         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 @@ class PurePathTest(unittest.TestCase):
     @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 @@ class PurePathTest(unittest.TestCase):
             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 @@ class PurePathTest(unittest.TestCase):
     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 (file)
index 0000000..68b63bc
--- /dev/null
@@ -0,0 +1,2 @@
+Deprecate :meth:`!pathlib.PurePath.as_uri`; use :meth:`pathlib.Path.as_uri`
+instead.