mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
GH-113528: Deoptimise pathlib._abc.PurePathBase
(#113559)
Apply pathlib's normalization and performance tuning in `pathlib.PurePath`, but not `pathlib._abc.PurePathBase`. With this change, the pathlib ABCs do not normalize away alternate path separators, empty segments, or dot segments. A single string given to the initialiser will round-trip by default, i.e. `str(PurePathBase(my_string)) == my_string`. Implementors can set their own path domain-specific normalization scheme by overriding `__str__()` Eliminating path normalization makes maintaining and caching the path's parts and string representation both optional and not very useful, so this commit moves the `_drv`, `_root`, `_tail_cached` and `_str` slots from `PurePathBase` to `PurePath`. Only `_raw_paths` and `_resolving` slots remain in `PurePathBase`. This frees the ABCs from the burden of some of pathlib's hardest-to-understand code.
This commit is contained in:
parent
57bdc6c30d
commit
beb80d11ec
4 changed files with 195 additions and 140 deletions
|
@ -153,8 +153,6 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
# Canonicalized paths roundtrip.
|
||||
for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
|
||||
self._check_str(pathstr, (pathstr,))
|
||||
# Special case for the empty path.
|
||||
self._check_str('.', ('',))
|
||||
# Other tests for str() are in test_equivalences().
|
||||
|
||||
def test_as_posix_common(self):
|
||||
|
@ -166,7 +164,6 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
def test_match_empty(self):
|
||||
P = self.cls
|
||||
self.assertRaises(ValueError, P('a').match, '')
|
||||
self.assertRaises(ValueError, P('a').match, '.')
|
||||
|
||||
def test_match_common(self):
|
||||
P = self.cls
|
||||
|
@ -206,7 +203,6 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
self.assertTrue(P('a/b/c.py').match('**'))
|
||||
self.assertTrue(P('/a/b/c.py').match('**'))
|
||||
self.assertTrue(P('/a/b/c.py').match('/**'))
|
||||
self.assertTrue(P('/a/b/c.py').match('**/'))
|
||||
self.assertTrue(P('/a/b/c.py').match('/a/**'))
|
||||
self.assertTrue(P('/a/b/c.py').match('**/*.py'))
|
||||
self.assertTrue(P('/a/b/c.py').match('/**/*.py'))
|
||||
|
@ -270,17 +266,17 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
self.assertEqual(len(par), 3)
|
||||
self.assertEqual(par[0], P('a/b'))
|
||||
self.assertEqual(par[1], P('a'))
|
||||
self.assertEqual(par[2], P('.'))
|
||||
self.assertEqual(par[-1], P('.'))
|
||||
self.assertEqual(par[2], P(''))
|
||||
self.assertEqual(par[-1], P(''))
|
||||
self.assertEqual(par[-2], P('a'))
|
||||
self.assertEqual(par[-3], P('a/b'))
|
||||
self.assertEqual(par[0:1], (P('a/b'),))
|
||||
self.assertEqual(par[:2], (P('a/b'), P('a')))
|
||||
self.assertEqual(par[:-1], (P('a/b'), P('a')))
|
||||
self.assertEqual(par[1:], (P('a'), P('.')))
|
||||
self.assertEqual(par[::2], (P('a/b'), P('.')))
|
||||
self.assertEqual(par[::-1], (P('.'), P('a'), P('a/b')))
|
||||
self.assertEqual(list(par), [P('a/b'), P('a'), P('.')])
|
||||
self.assertEqual(par[1:], (P('a'), P('')))
|
||||
self.assertEqual(par[::2], (P('a/b'), P('')))
|
||||
self.assertEqual(par[::-1], (P(''), P('a'), P('a/b')))
|
||||
self.assertEqual(list(par), [P('a/b'), P('a'), P('')])
|
||||
with self.assertRaises(IndexError):
|
||||
par[-4]
|
||||
with self.assertRaises(IndexError):
|
||||
|
@ -334,8 +330,8 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
def test_name_empty(self):
|
||||
P = self.cls
|
||||
self.assertEqual(P('').name, '')
|
||||
self.assertEqual(P('.').name, '')
|
||||
self.assertEqual(P('/a/b/.').name, 'b')
|
||||
self.assertEqual(P('.').name, '.')
|
||||
self.assertEqual(P('/a/b/.').name, '.')
|
||||
|
||||
def test_name_common(self):
|
||||
P = self.cls
|
||||
|
@ -387,7 +383,7 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
def test_stem_empty(self):
|
||||
P = self.cls
|
||||
self.assertEqual(P('').stem, '')
|
||||
self.assertEqual(P('.').stem, '')
|
||||
self.assertEqual(P('.').stem, '.')
|
||||
|
||||
def test_stem_common(self):
|
||||
P = self.cls
|
||||
|
@ -412,11 +408,11 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
|
||||
def test_with_name_empty(self):
|
||||
P = self.cls
|
||||
self.assertRaises(ValueError, P('').with_name, 'd.xml')
|
||||
self.assertRaises(ValueError, P('.').with_name, 'd.xml')
|
||||
self.assertRaises(ValueError, P('/').with_name, 'd.xml')
|
||||
self.assertRaises(ValueError, P('a/b').with_name, '')
|
||||
self.assertRaises(ValueError, P('a/b').with_name, '.')
|
||||
self.assertEqual(P('').with_name('d.xml'), P('d.xml'))
|
||||
self.assertEqual(P('.').with_name('d.xml'), P('d.xml'))
|
||||
self.assertEqual(P('/').with_name('d.xml'), P('/d.xml'))
|
||||
self.assertEqual(P('a/b').with_name(''), P('a/'))
|
||||
self.assertEqual(P('a/b').with_name('.'), P('a/.'))
|
||||
|
||||
def test_with_name_seps(self):
|
||||
P = self.cls
|
||||
|
@ -436,11 +432,11 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
|
||||
def test_with_stem_empty(self):
|
||||
P = self.cls
|
||||
self.assertRaises(ValueError, P('').with_stem, 'd')
|
||||
self.assertRaises(ValueError, P('.').with_stem, 'd')
|
||||
self.assertRaises(ValueError, P('/').with_stem, 'd')
|
||||
self.assertRaises(ValueError, P('a/b').with_stem, '')
|
||||
self.assertRaises(ValueError, P('a/b').with_stem, '.')
|
||||
self.assertEqual(P('').with_stem('d'), P('d'))
|
||||
self.assertEqual(P('.').with_stem('d'), P('d'))
|
||||
self.assertEqual(P('/').with_stem('d'), P('/d'))
|
||||
self.assertEqual(P('a/b').with_stem(''), P('a/'))
|
||||
self.assertEqual(P('a/b').with_stem('.'), P('a/.'))
|
||||
|
||||
def test_with_stem_seps(self):
|
||||
P = self.cls
|
||||
|
@ -461,9 +457,9 @@ class DummyPurePathTest(unittest.TestCase):
|
|||
def test_with_suffix_empty(self):
|
||||
P = self.cls
|
||||
# Path doesn't have a "filename" component.
|
||||
self.assertRaises(ValueError, P('').with_suffix, '.gz')
|
||||
self.assertRaises(ValueError, P('.').with_suffix, '.gz')
|
||||
self.assertRaises(ValueError, P('/').with_suffix, '.gz')
|
||||
self.assertEqual(P('').with_suffix('.gz'), P('.gz'))
|
||||
self.assertEqual(P('.').with_suffix('.gz'), P('..gz'))
|
||||
self.assertEqual(P('/').with_suffix('.gz'), P('/.gz'))
|
||||
|
||||
def test_with_suffix_seps(self):
|
||||
P = self.cls
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue