mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	GH-128520: Subclass abc.ABC in pathlib._abc (#128745)
				
					
				
			Convert `JoinablePath`, `ReadablePath` and `WritablePath` to real ABCs derived from `abc.ABC`. Make `JoinablePath.parser` abstract, rather than defaulting to `posixpath`. Register `PurePath` and `Path` as virtual subclasses of the ABCs rather than deriving. This avoids a hit to path object instantiation performance. No change of behaviour in the public (non-abstract) classes.
This commit is contained in:
		
							parent
							
								
									359c7dde3b
								
							
						
					
					
						commit
						a7d41a8947
					
				
					 4 changed files with 125 additions and 49 deletions
				
			
		|  | @ -31,29 +31,11 @@ def needs_windows(fn): | |||
| # | ||||
| 
 | ||||
| 
 | ||||
| class JoinablePathTest(unittest.TestCase): | ||||
|     cls = JoinablePath | ||||
| 
 | ||||
|     def test_magic_methods(self): | ||||
|         P = self.cls | ||||
|         self.assertFalse(hasattr(P, '__fspath__')) | ||||
|         self.assertFalse(hasattr(P, '__bytes__')) | ||||
|         self.assertIs(P.__reduce__, object.__reduce__) | ||||
|         self.assertIs(P.__repr__, object.__repr__) | ||||
|         self.assertIs(P.__hash__, object.__hash__) | ||||
|         self.assertIs(P.__eq__, object.__eq__) | ||||
|         self.assertIs(P.__lt__, object.__lt__) | ||||
|         self.assertIs(P.__le__, object.__le__) | ||||
|         self.assertIs(P.__gt__, object.__gt__) | ||||
|         self.assertIs(P.__ge__, object.__ge__) | ||||
| 
 | ||||
|     def test_parser(self): | ||||
|         self.assertIs(self.cls.parser, posixpath) | ||||
| 
 | ||||
| 
 | ||||
| class DummyJoinablePath(JoinablePath): | ||||
|     __slots__ = ('_segments',) | ||||
| 
 | ||||
|     parser = posixpath | ||||
| 
 | ||||
|     def __init__(self, *segments): | ||||
|         self._segments = segments | ||||
| 
 | ||||
|  | @ -77,7 +59,7 @@ def with_segments(self, *pathsegments): | |||
|         return type(self)(*pathsegments) | ||||
| 
 | ||||
| 
 | ||||
| class DummyJoinablePathTest(unittest.TestCase): | ||||
| class JoinablePathTest(unittest.TestCase): | ||||
|     cls = DummyJoinablePath | ||||
| 
 | ||||
|     # Use a base path that's unrelated to any real filesystem path. | ||||
|  | @ -94,6 +76,10 @@ def setUp(self): | |||
|         self.sep = self.parser.sep | ||||
|         self.altsep = self.parser.altsep | ||||
| 
 | ||||
|     def test_is_joinable(self): | ||||
|         p = self.cls(self.base) | ||||
|         self.assertIsInstance(p, JoinablePath) | ||||
| 
 | ||||
|     def test_parser(self): | ||||
|         self.assertIsInstance(self.cls.parser, _PathParser) | ||||
| 
 | ||||
|  | @ -878,6 +864,7 @@ class DummyReadablePath(ReadablePath, DummyJoinablePath): | |||
| 
 | ||||
|     _files = {} | ||||
|     _directories = {} | ||||
|     parser = posixpath | ||||
| 
 | ||||
|     def __init__(self, *segments): | ||||
|         super().__init__(*segments) | ||||
|  | @ -909,6 +896,9 @@ def iterdir(self): | |||
|         else: | ||||
|             raise FileNotFoundError(errno.ENOENT, "File not found", path) | ||||
| 
 | ||||
|     def readlink(self): | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
| 
 | ||||
| class DummyWritablePath(WritablePath, DummyJoinablePath): | ||||
|     __slots__ = () | ||||
|  | @ -942,8 +932,11 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False): | |||
|             self.parent.mkdir(parents=True, exist_ok=True) | ||||
|             self.mkdir(mode, parents=False, exist_ok=exist_ok) | ||||
| 
 | ||||
|     def symlink_to(self, target, target_is_directory=False): | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
| class DummyReadablePathTest(DummyJoinablePathTest): | ||||
| 
 | ||||
| class ReadablePathTest(JoinablePathTest): | ||||
|     """Tests for ReadablePathTest methods that use stat(), open() and iterdir().""" | ||||
| 
 | ||||
|     cls = DummyReadablePath | ||||
|  | @ -1010,6 +1003,10 @@ def assertEqualNormCase(self, path_a, path_b): | |||
|         normcase = self.parser.normcase | ||||
|         self.assertEqual(normcase(path_a), normcase(path_b)) | ||||
| 
 | ||||
|     def test_is_readable(self): | ||||
|         p = self.cls(self.base) | ||||
|         self.assertIsInstance(p, ReadablePath) | ||||
| 
 | ||||
|     def test_exists(self): | ||||
|         P = self.cls | ||||
|         p = P(self.base) | ||||
|  | @ -1378,15 +1375,19 @@ def test_is_symlink(self): | |||
|             self.assertIs((P / 'linkA\x00').is_file(), False) | ||||
| 
 | ||||
| 
 | ||||
| class DummyWritablePathTest(DummyJoinablePathTest): | ||||
| class WritablePathTest(JoinablePathTest): | ||||
|     cls = DummyWritablePath | ||||
| 
 | ||||
|     def test_is_writable(self): | ||||
|         p = self.cls(self.base) | ||||
|         self.assertIsInstance(p, WritablePath) | ||||
| 
 | ||||
| 
 | ||||
| class DummyRWPath(DummyWritablePath, DummyReadablePath): | ||||
|     __slots__ = () | ||||
| 
 | ||||
| 
 | ||||
| class DummyRWPathTest(DummyWritablePathTest, DummyReadablePathTest): | ||||
| class RWPathTest(WritablePathTest, ReadablePathTest): | ||||
|     cls = DummyRWPath | ||||
|     can_symlink = False | ||||
| 
 | ||||
|  | @ -1598,9 +1599,9 @@ def test_copy_into_empty_name(self): | |||
|         self.assertRaises(ValueError, source.copy_into, target_dir) | ||||
| 
 | ||||
| 
 | ||||
| class DummyReadablePathWalkTest(unittest.TestCase): | ||||
| class ReadablePathWalkTest(unittest.TestCase): | ||||
|     cls = DummyReadablePath | ||||
|     base = DummyReadablePathTest.base | ||||
|     base = ReadablePathTest.base | ||||
|     can_symlink = False | ||||
| 
 | ||||
|     def setUp(self): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Barney Gale
						Barney Gale