Skip to content

Commit 032e3ef

Browse files
committed
GH-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 032e3ef

File tree

5 files changed

+52
-44
lines changed

5 files changed

+52
-44
lines changed

Lib/pathlib/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
operating systems.
66
"""
77

8-
from pathlib._abc import *
98
from pathlib._local import *
109

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

Lib/pathlib/_abc.py

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +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-
31-
3223
@functools.cache
3324
def _is_case_sensitive(parser):
3425
return parser.normcase('Aa') == 'Aa'
@@ -353,8 +344,8 @@ class PathBase(PurePathBase):
353344
354345
This class provides dummy implementations for many methods that derived
355346
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
347+
NotImplementedError. The most basic methods, such as stat() and open(),
348+
directly raise NotImplementedError; these basic methods are called by
358349
other methods such as is_dir() and read_text().
359350
360351
The Path class derives this class to implement local filesystem paths.
@@ -363,16 +354,12 @@ class PathBase(PurePathBase):
363354
"""
364355
__slots__ = ()
365356

366-
@classmethod
367-
def _unsupported_msg(cls, attribute):
368-
return f"{cls.__name__}.{attribute} is unsupported"
369-
370357
def stat(self, *, follow_symlinks=True):
371358
"""
372359
Return the result of the stat() system call on this path, like
373360
os.stat() does.
374361
"""
375-
raise UnsupportedOperation(self._unsupported_msg('stat()'))
362+
raise NotImplementedError
376363

377364
# Convenience functions for querying the stat results
378365

@@ -448,7 +435,7 @@ def open(self, mode='r', buffering=-1, encoding=None,
448435
Open the file pointed to by this path and return a file object, as
449436
the built-in open() function does.
450437
"""
451-
raise UnsupportedOperation(self._unsupported_msg('open()'))
438+
raise NotImplementedError
452439

453440
def read_bytes(self):
454441
"""
@@ -498,7 +485,7 @@ def iterdir(self):
498485
The children are yielded in arbitrary order, and the
499486
special entries '.' and '..' are not included.
500487
"""
501-
raise UnsupportedOperation(self._unsupported_msg('iterdir()'))
488+
raise NotImplementedError
502489

503490
def _glob_selector(self, parts, case_sensitive, recurse_symlinks):
504491
if case_sensitive is None:
@@ -575,14 +562,14 @@ def readlink(self):
575562
"""
576563
Return the path to which the symbolic link points.
577564
"""
578-
raise UnsupportedOperation(self._unsupported_msg('readlink()'))
565+
raise NotImplementedError
579566

580567
def symlink_to(self, target, target_is_directory=False):
581568
"""
582569
Make this path a symlink pointing to the target path.
583570
Note the order of arguments (link, target) is the reverse of os.symlink.
584571
"""
585-
raise UnsupportedOperation(self._unsupported_msg('symlink_to()'))
572+
raise NotImplementedError
586573

587574
def _symlink_to_target_of(self, link):
588575
"""
@@ -595,7 +582,7 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False):
595582
"""
596583
Create a new directory at this given path.
597584
"""
598-
raise UnsupportedOperation(self._unsupported_msg('mkdir()'))
585+
raise NotImplementedError
599586

600587
# Metadata keys supported by this path type.
601588
_readable_metadata = _writable_metadata = frozenset()
@@ -604,13 +591,13 @@ def _read_metadata(self, keys=None, *, follow_symlinks=True):
604591
"""
605592
Returns path metadata as a dict with string keys.
606593
"""
607-
raise UnsupportedOperation(self._unsupported_msg('_read_metadata()'))
594+
raise NotImplementedError
608595

609596
def _write_metadata(self, metadata, *, follow_symlinks=True):
610597
"""
611598
Sets path metadata from the given dict with string keys.
612599
"""
613-
raise UnsupportedOperation(self._unsupported_msg('_write_metadata()'))
600+
raise NotImplementedError
614601

615602
def _copy_metadata(self, target, *, follow_symlinks=True):
616603
"""
@@ -687,7 +674,7 @@ def _delete(self):
687674
"""
688675
Delete this file or directory (including all sub-directories).
689676
"""
690-
raise UnsupportedOperation(self._unsupported_msg('_delete()'))
677+
raise NotImplementedError
691678

692679
def move(self, target):
693680
"""

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)