Skip to content

Commit a90839a

Browse files
committed
pythonGH-127807: pathlib ABCs: remove PathBase._unsupported_msg()
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.
1 parent 292afd1 commit a90839a

5 files changed

Lines changed: 52 additions & 42 deletions

File tree

‎Lib/pathlib/__init__.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@
88
from pathlib._abc import *
99
from pathlib._local import *
1010

11-
__all__ = (_abc.__all__ +
12-
_local.__all__)
11+
__all__ = _local.__all__

‎Lib/pathlib/_abc.py‎

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,6 @@
2020
from pathlib._os import copyfileobj
2121

2222

23-
__all__ = ["UnsupportedOperation"]
24-
25-
26-
class UnsupportedOperation(NotImplementedError):
27-
"""An exception that is raised when an unsupported operation is attempted.
28-
"""
29-
pass
30-
3123

3224
@functools.cache
3325
def _is_case_sensitive(parser):
@@ -353,8 +345,8 @@ class PathBase(PurePathBase):
353345
354346
This class provides dummy implementations for many methods that derived
355347
classes can override selectively; the default implementations raise
356-
UnsupportedOperation. The most basic methods, such as stat() and open(),
357-
directly raise UnsupportedOperation; these basic methods are called by
348+
NotImplementedError. The most basic methods, such as stat() and open(),
349+
directly raise NotImplementedError; these basic methods are called by
358350
other methods such as is_dir() and read_text().
359351
360352
The Path class derives this class to implement local filesystem paths.
@@ -363,16 +355,12 @@ class PathBase(PurePathBase):
363355
"""
364356
__slots__ = ()
365357

366-
@classmethod
367-
def _unsupported_msg(cls, attribute):
368-
return f"{cls.__name__}.{attribute} is unsupported"
369-
370358
def stat(self, *, follow_symlinks=True):
371359
"""
372360
Return the result of the stat() system call on this path, like
373361
os.stat() does.
374362
"""
375-
raise UnsupportedOperation(self._unsupported_msg('stat()'))
363+
raise NotImplementedError
376364

377365
# Convenience functions for querying the stat results
378366

@@ -448,7 +436,7 @@ def open(self, mode='r', buffering=-1, encoding=None,
448436
Open the file pointed to by this path and return a file object, as
449437
the built-in open() function does.
450438
"""
451-
raise UnsupportedOperation(self._unsupported_msg('open()'))
439+
raise NotImplementedError
452440

453441
def read_bytes(self):
454442
"""
@@ -498,7 +486,7 @@ def iterdir(self):
498486
The children are yielded in arbitrary order, and the
499487
special entries '.' and '..' are not included.
500488
"""
501-
raise UnsupportedOperation(self._unsupported_msg('iterdir()'))
489+
raise NotImplementedError
502490

503491
def _glob_selector(self, parts, case_sensitive, recurse_symlinks):
504492
if case_sensitive is None:
@@ -575,14 +563,14 @@ def readlink(self):
575563
"""
576564
Return the path to which the symbolic link points.
577565
"""
578-
raise UnsupportedOperation(self._unsupported_msg('readlink()'))
566+
raise NotImplementedError
579567

580568
def symlink_to(self, target, target_is_directory=False):
581569
"""
582570
Make this path a symlink pointing to the target path.
583571
Note the order of arguments (link, target) is the reverse of os.symlink.
584572
"""
585-
raise UnsupportedOperation(self._unsupported_msg('symlink_to()'))
573+
raise NotImplementedError
586574

587575
def _symlink_to_target_of(self, link):
588576
"""
@@ -595,7 +583,7 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False):
595583
"""
596584
Create a new directory at this given path.
597585
"""
598-
raise UnsupportedOperation(self._unsupported_msg('mkdir()'))
586+
raise NotImplementedError
599587

600588
# Metadata keys supported by this path type.
601589
_readable_metadata = _writable_metadata = frozenset()
@@ -604,13 +592,13 @@ def _read_metadata(self, keys=None, *, follow_symlinks=True):
604592
"""
605593
Returns path metadata as a dict with string keys.
606594
"""
607-
raise UnsupportedOperation(self._unsupported_msg('_read_metadata()'))
595+
raise NotImplementedError
608596

609597
def _write_metadata(self, metadata, *, follow_symlinks=True):
610598
"""
611599
Sets path metadata from the given dict with string keys.
612600
"""
613-
raise UnsupportedOperation(self._unsupported_msg('_write_metadata()'))
601+
raise NotImplementedError
614602

615603
def _copy_metadata(self, target, *, follow_symlinks=True):
616604
"""
@@ -687,7 +675,7 @@ def _delete(self):
687675
"""
688676
Delete this file or directory (including all sub-directories).
689677
"""
690-
raise UnsupportedOperation(self._unsupported_msg('_delete()'))
678+
raise NotImplementedError
691679

692680
def move(self, target):
693681
"""

‎Lib/pathlib/_local.py‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,22 @@
2121

2222
from pathlib._os import (copyfile, file_metadata_keys, read_file_metadata,
2323
write_file_metadata)
24-
from pathlib._abc import UnsupportedOperation, PurePathBase, PathBase
24+
from pathlib._abc import PurePathBase, PathBase
2525

2626

2727
__all__ = [
28+
"UnsupportedOperation",
2829
"PurePath", "PurePosixPath", "PureWindowsPath",
2930
"Path", "PosixPath", "WindowsPath",
3031
]
3132

3233

34+
class UnsupportedOperation(NotImplementedError):
35+
"""An exception that is raised when an unsupported operation is attempted.
36+
"""
37+
pass
38+
39+
3340
class _PathParents(Sequence):
3441
"""This object provides sequence-like access to the logical ancestors
3542
of a path. Don't try to construct it yourself."""
@@ -527,10 +534,6 @@ class Path(PathBase, PurePath):
527534
"""
528535
__slots__ = ()
529536

530-
@classmethod
531-
def _unsupported_msg(cls, attribute):
532-
return f"{cls.__name__}.{attribute} is unsupported on this system"
533-
534537
def __new__(cls, *args, **kwargs):
535538
if cls is Path:
536539
cls = WindowsPath if os.name == 'nt' else PosixPath
@@ -817,7 +820,8 @@ def owner(self, *, follow_symlinks=True):
817820
"""
818821
Return the login name of the file owner.
819822
"""
820-
raise UnsupportedOperation(self._unsupported_msg('owner()'))
823+
f = f"{type(self).__name__}.owner()"
824+
raise UnsupportedOperation(f"{f} is unsupported on this system")
821825

822826
if grp:
823827
def group(self, *, follow_symlinks=True):
@@ -831,14 +835,22 @@ def group(self, *, follow_symlinks=True):
831835
"""
832836
Return the group name of the file gid.
833837
"""
834-
raise UnsupportedOperation(self._unsupported_msg('group()'))
838+
f = f"{type(self).__name__}.group()"
839+
raise UnsupportedOperation(f"{f} is unsupported on this system")
835840

836841
if hasattr(os, "readlink"):
837842
def readlink(self):
838843
"""
839844
Return the path to which the symbolic link points.
840845
"""
841846
return self.with_segments(os.readlink(self))
847+
else:
848+
def readlink(self):
849+
"""
850+
Return the path to which the symbolic link points.
851+
"""
852+
f = f"{type(self).__name__}.readlink()"
853+
raise UnsupportedOperation(f"{f} is unsupported on this system")
842854

843855
def touch(self, mode=0o666, exist_ok=True):
844856
"""
@@ -989,6 +1001,14 @@ def symlink_to(self, target, target_is_directory=False):
9891001
Note the order of arguments (link, target) is the reverse of os.symlink.
9901002
"""
9911003
os.symlink(target, self, target_is_directory)
1004+
else:
1005+
def symlink_to(self, target, target_is_directory=False):
1006+
"""
1007+
Make this path a symlink pointing to the target path.
1008+
Note the order of arguments (link, target) is the reverse of os.symlink.
1009+
"""
1010+
f = f"{type(self).__name__}.symlink_to()"
1011+
raise UnsupportedOperation(f"{f} is unsupported on this system")
9921012

9931013
if os.name == 'nt':
9941014
def _symlink_to_target_of(self, link):
@@ -1013,7 +1033,8 @@ def hardlink_to(self, target):
10131033
10141034
Note the order of arguments (self, target) is the reverse of os.link's.
10151035
"""
1016-
raise UnsupportedOperation(self._unsupported_msg('hardlink_to()'))
1036+
f = f"{type(self).__name__}.hardlink_to()"
1037+
raise UnsupportedOperation(f"{f} is unsupported on this system")
10171038

10181039
def expanduser(self):
10191040
""" Return a new path with expanded ~ and ~user constructs

‎Lib/test/test_pathlib/test_pathlib.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ def needs_symlinks(fn):
6363
_tests_needing_symlinks.add(fn.__name__)
6464
return fn
6565

66+
67+
68+
class UnsupportedOperationTest(unittest.TestCase):
69+
def test_is_notimplemented(self):
70+
self.assertTrue(issubclass(pathlib.UnsupportedOperation, NotImplementedError))
71+
self.assertTrue(isinstance(pathlib.UnsupportedOperation(), NotImplementedError))
72+
73+
6674
#
6775
# Tests for the pure classes.
6876
#

‎Lib/test/test_pathlib/test_pathlib_abc.py‎

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import stat
66
import unittest
77

8-
from pathlib._abc import UnsupportedOperation, PurePathBase, PathBase
8+
from pathlib._abc import PurePathBase, PathBase
99
from pathlib._types import Parser
1010
import posixpath
1111

@@ -27,11 +27,6 @@ def needs_windows(fn):
2727
return fn
2828

2929

30-
class UnsupportedOperationTest(unittest.TestCase):
31-
def test_is_notimplemented(self):
32-
self.assertTrue(issubclass(UnsupportedOperation, NotImplementedError))
33-
self.assertTrue(isinstance(UnsupportedOperation(), NotImplementedError))
34-
3530
#
3631
# Tests for the pure classes.
3732
#
@@ -1294,10 +1289,9 @@ def test_is_absolute_windows(self):
12941289
class PathBaseTest(PurePathBaseTest):
12951290
cls = PathBase
12961291

1297-
def test_unsupported_operation(self):
1298-
P = self.cls
1292+
def test_not_implemented_error(self):
12991293
p = self.cls('')
1300-
e = UnsupportedOperation
1294+
e = NotImplementedError
13011295
self.assertRaises(e, p.stat)
13021296
self.assertRaises(e, p.exists)
13031297
self.assertRaises(e, p.is_dir)

0 commit comments

Comments
 (0)