]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-127807: pathlib ABCs: remove `PathBase._unsupported_msg()` (#127855)
authorBarney Gale <barney.gale@gmail.com>
Thu, 12 Dec 2024 17:39:24 +0000 (17:39 +0000)
committerGitHub <noreply@github.com>
Thu, 12 Dec 2024 17:39:24 +0000 (17:39 +0000)
This method helped us customise the `UnsupportedOperation` message
depending on the type. But we're aiming to make `PathBase` a proper ABC
soon, so `NotImplementedError` is the right exception to raise there.

Lib/pathlib/__init__.py
Lib/pathlib/_abc.py
Lib/pathlib/_local.py
Lib/test/test_pathlib/test_pathlib.py
Lib/test/test_pathlib/test_pathlib_abc.py

index 5da3acd31997e5dc6f250567c92caecbc14a6a84..ec1bac9ef493505f994161d6f598b4efc5b73b2b 100644 (file)
@@ -5,8 +5,6 @@ paths with operations that have semantics appropriate for different
 operating systems.
 """
 
-from pathlib._abc import *
 from pathlib._local import *
 
-__all__ = (_abc.__all__ +
-           _local.__all__)
+__all__ = _local.__all__
index b10aba85132332b770c938135e9f067faaa6421e..b4560295300c283796606f48c9653900d6e69808 100644 (file)
@@ -20,15 +20,6 @@ from stat import S_ISDIR, S_ISLNK, S_ISREG
 from pathlib._os import copyfileobj
 
 
-__all__ = ["UnsupportedOperation"]
-
-
-class UnsupportedOperation(NotImplementedError):
-    """An exception that is raised when an unsupported operation is attempted.
-    """
-    pass
-
-
 @functools.cache
 def _is_case_sensitive(parser):
     return parser.normcase('Aa') == 'Aa'
@@ -353,8 +344,8 @@ class PathBase(PurePathBase):
 
     This class provides dummy implementations for many methods that derived
     classes can override selectively; the default implementations raise
-    UnsupportedOperation. The most basic methods, such as stat() and open(),
-    directly raise UnsupportedOperation; these basic methods are called by
+    NotImplementedError. The most basic methods, such as stat() and open(),
+    directly raise NotImplementedError; these basic methods are called by
     other methods such as is_dir() and read_text().
 
     The Path class derives this class to implement local filesystem paths.
@@ -363,16 +354,12 @@ class PathBase(PurePathBase):
     """
     __slots__ = ()
 
-    @classmethod
-    def _unsupported_msg(cls, attribute):
-        return f"{cls.__name__}.{attribute} is unsupported"
-
     def stat(self, *, follow_symlinks=True):
         """
         Return the result of the stat() system call on this path, like
         os.stat() does.
         """
-        raise UnsupportedOperation(self._unsupported_msg('stat()'))
+        raise NotImplementedError
 
     # Convenience functions for querying the stat results
 
@@ -448,7 +435,7 @@ class PathBase(PurePathBase):
         Open the file pointed to by this path and return a file object, as
         the built-in open() function does.
         """
-        raise UnsupportedOperation(self._unsupported_msg('open()'))
+        raise NotImplementedError
 
     def read_bytes(self):
         """
@@ -498,7 +485,7 @@ class PathBase(PurePathBase):
         The children are yielded in arbitrary order, and the
         special entries '.' and '..' are not included.
         """
-        raise UnsupportedOperation(self._unsupported_msg('iterdir()'))
+        raise NotImplementedError
 
     def _glob_selector(self, parts, case_sensitive, recurse_symlinks):
         if case_sensitive is None:
@@ -575,14 +562,14 @@ class PathBase(PurePathBase):
         """
         Return the path to which the symbolic link points.
         """
-        raise UnsupportedOperation(self._unsupported_msg('readlink()'))
+        raise NotImplementedError
 
     def symlink_to(self, target, target_is_directory=False):
         """
         Make this path a symlink pointing to the target path.
         Note the order of arguments (link, target) is the reverse of os.symlink.
         """
-        raise UnsupportedOperation(self._unsupported_msg('symlink_to()'))
+        raise NotImplementedError
 
     def _symlink_to_target_of(self, link):
         """
@@ -595,7 +582,7 @@ class PathBase(PurePathBase):
         """
         Create a new directory at this given path.
         """
-        raise UnsupportedOperation(self._unsupported_msg('mkdir()'))
+        raise NotImplementedError
 
     # Metadata keys supported by this path type.
     _readable_metadata = _writable_metadata = frozenset()
@@ -604,13 +591,13 @@ class PathBase(PurePathBase):
         """
         Returns path metadata as a dict with string keys.
         """
-        raise UnsupportedOperation(self._unsupported_msg('_read_metadata()'))
+        raise NotImplementedError
 
     def _write_metadata(self, metadata, *, follow_symlinks=True):
         """
         Sets path metadata from the given dict with string keys.
         """
-        raise UnsupportedOperation(self._unsupported_msg('_write_metadata()'))
+        raise NotImplementedError
 
     def _copy_metadata(self, target, *, follow_symlinks=True):
         """
@@ -687,7 +674,7 @@ class PathBase(PurePathBase):
         """
         Delete this file or directory (including all sub-directories).
         """
-        raise UnsupportedOperation(self._unsupported_msg('_delete()'))
+        raise NotImplementedError
 
     def move(self, target):
         """
index 0dfe9d2390ecffb4d54ad40b6033534660650b14..b933dd512eeb28ae0bd7276524883ed4648a6ec1 100644 (file)
@@ -21,15 +21,22 @@ except ImportError:
 
 from pathlib._os import (copyfile, file_metadata_keys, read_file_metadata,
                          write_file_metadata)
-from pathlib._abc import UnsupportedOperation, PurePathBase, PathBase
+from pathlib._abc import PurePathBase, PathBase
 
 
 __all__ = [
+    "UnsupportedOperation",
     "PurePath", "PurePosixPath", "PureWindowsPath",
     "Path", "PosixPath", "WindowsPath",
     ]
 
 
+class UnsupportedOperation(NotImplementedError):
+    """An exception that is raised when an unsupported operation is attempted.
+    """
+    pass
+
+
 class _PathParents(Sequence):
     """This object provides sequence-like access to the logical ancestors
     of a path.  Don't try to construct it yourself."""
@@ -527,10 +534,6 @@ class Path(PathBase, PurePath):
     """
     __slots__ = ()
 
-    @classmethod
-    def _unsupported_msg(cls, attribute):
-        return f"{cls.__name__}.{attribute} is unsupported on this system"
-
     def __new__(cls, *args, **kwargs):
         if cls is Path:
             cls = WindowsPath if os.name == 'nt' else PosixPath
@@ -817,7 +820,8 @@ class Path(PathBase, PurePath):
             """
             Return the login name of the file owner.
             """
-            raise UnsupportedOperation(self._unsupported_msg('owner()'))
+            f = f"{type(self).__name__}.owner()"
+            raise UnsupportedOperation(f"{f} is unsupported on this system")
 
     if grp:
         def group(self, *, follow_symlinks=True):
@@ -831,7 +835,8 @@ class Path(PathBase, PurePath):
             """
             Return the group name of the file gid.
             """
-            raise UnsupportedOperation(self._unsupported_msg('group()'))
+            f = f"{type(self).__name__}.group()"
+            raise UnsupportedOperation(f"{f} is unsupported on this system")
 
     if hasattr(os, "readlink"):
         def readlink(self):
@@ -839,6 +844,13 @@ class Path(PathBase, PurePath):
             Return the path to which the symbolic link points.
             """
             return self.with_segments(os.readlink(self))
+    else:
+        def readlink(self):
+            """
+            Return the path to which the symbolic link points.
+            """
+            f = f"{type(self).__name__}.readlink()"
+            raise UnsupportedOperation(f"{f} is unsupported on this system")
 
     def touch(self, mode=0o666, exist_ok=True):
         """
@@ -989,6 +1001,14 @@ class Path(PathBase, PurePath):
             Note the order of arguments (link, target) is the reverse of os.symlink.
             """
             os.symlink(target, self, target_is_directory)
+    else:
+        def symlink_to(self, target, target_is_directory=False):
+            """
+            Make this path a symlink pointing to the target path.
+            Note the order of arguments (link, target) is the reverse of os.symlink.
+            """
+            f = f"{type(self).__name__}.symlink_to()"
+            raise UnsupportedOperation(f"{f} is unsupported on this system")
 
     if os.name == 'nt':
         def _symlink_to_target_of(self, link):
@@ -1013,7 +1033,8 @@ class Path(PathBase, PurePath):
 
             Note the order of arguments (self, target) is the reverse of os.link's.
             """
-            raise UnsupportedOperation(self._unsupported_msg('hardlink_to()'))
+            f = f"{type(self).__name__}.hardlink_to()"
+            raise UnsupportedOperation(f"{f} is unsupported on this system")
 
     def expanduser(self):
         """ Return a new path with expanded ~ and ~user constructs
index b57ef420bfcbcd3abe28280c461bf0fdd69a5152..68bff2cf0d511e294a640d7a8269500cb0d3d375 100644 (file)
@@ -63,6 +63,14 @@ def needs_symlinks(fn):
     _tests_needing_symlinks.add(fn.__name__)
     return fn
 
+
+
+class UnsupportedOperationTest(unittest.TestCase):
+    def test_is_notimplemented(self):
+        self.assertTrue(issubclass(pathlib.UnsupportedOperation, NotImplementedError))
+        self.assertTrue(isinstance(pathlib.UnsupportedOperation(), NotImplementedError))
+
+
 #
 # Tests for the pure classes.
 #
index d770b87dc6a104cb22b12357162321dcd567cf41..e230dd188799a577155ed40d358f743d79a1d0a7 100644 (file)
@@ -5,7 +5,7 @@ import errno
 import stat
 import unittest
 
-from pathlib._abc import UnsupportedOperation, PurePathBase, PathBase
+from pathlib._abc import PurePathBase, PathBase
 from pathlib._types import Parser
 import posixpath
 
@@ -27,11 +27,6 @@ def needs_windows(fn):
     return fn
 
 
-class UnsupportedOperationTest(unittest.TestCase):
-    def test_is_notimplemented(self):
-        self.assertTrue(issubclass(UnsupportedOperation, NotImplementedError))
-        self.assertTrue(isinstance(UnsupportedOperation(), NotImplementedError))
-
 #
 # Tests for the pure classes.
 #
@@ -1294,10 +1289,9 @@ class DummyPurePathTest(unittest.TestCase):
 class PathBaseTest(PurePathBaseTest):
     cls = PathBase
 
-    def test_unsupported_operation(self):
-        P = self.cls
+    def test_not_implemented_error(self):
         p = self.cls('')
-        e = UnsupportedOperation
+        e = NotImplementedError
         self.assertRaises(e, p.stat)
         self.assertRaises(e, p.exists)
         self.assertRaises(e, p.is_dir)