https://github.com/python/cpython/commit/475f933ed8b1c9546f1b5497a2241140c7065b5f
commit: 475f933ed8b1c9546f1b5497a2241140c7065b5f
branch: main
author: Barney Gale <barney.g...@gmail.com>
committer: barneygale <barney.g...@gmail.com>
date: 2025-03-09T17:02:37Z
summary:

GH-130614: pathlib ABCs: revise test suite for path joining (#130988)

Test `pathlib.types._JoinablePath` in a dedicated test module. These tests
cover `LexicalPath`, `PurePath` and `Path`, where `LexicalPath` is defined
in a new `test.test_pathlib.support` package.

files:
A Lib/test/test_pathlib/support/__init__.py
A Lib/test/test_pathlib/support/lexical_path.py
A Lib/test/test_pathlib/test_join.py
M Lib/test/test_pathlib/test_pathlib_abc.py
M Makefile.pre.in

diff --git a/Lib/test/test_pathlib/support/__init__.py 
b/Lib/test/test_pathlib/support/__init__.py
new file mode 100644
index 00000000000000..e69de29bb2d1d6
diff --git a/Lib/test/test_pathlib/support/lexical_path.py 
b/Lib/test/test_pathlib/support/lexical_path.py
new file mode 100644
index 00000000000000..687d76f64532f2
--- /dev/null
+++ b/Lib/test/test_pathlib/support/lexical_path.py
@@ -0,0 +1,33 @@
+"""
+Simple implementation of JoinablePath, for use in pathlib tests.
+"""
+
+import os.path
+import pathlib.types
+
+
+class LexicalPath(pathlib.types._JoinablePath):
+    __slots__ = ('_segments',)
+    parser = os.path
+
+    def __init__(self, *pathsegments):
+        self._segments = pathsegments
+
+    def __hash__(self):
+        return hash(str(self))
+
+    def __eq__(self, other):
+        if not isinstance(other, LexicalPath):
+            return NotImplemented
+        return str(self) == str(other)
+
+    def __str__(self):
+        if not self._segments:
+            return ''
+        return self.parser.join(*self._segments)
+
+    def __repr__(self):
+        return f'{type(self).__name__}({str(self)!r})'
+
+    def with_segments(self, *pathsegments):
+        return type(self)(*pathsegments)
diff --git a/Lib/test/test_pathlib/test_join.py 
b/Lib/test/test_pathlib/test_join.py
new file mode 100644
index 00000000000000..93fd1e6488c31d
--- /dev/null
+++ b/Lib/test/test_pathlib/test_join.py
@@ -0,0 +1,372 @@
+"""
+Tests for pathlib.types._JoinablePath
+"""
+
+import unittest
+
+from pathlib import PurePath, Path
+from pathlib.types import _PathParser, _JoinablePath
+from test.test_pathlib.support.lexical_path import LexicalPath
+
+
+class JoinTestBase:
+    def test_is_joinable(self):
+        p = self.cls()
+        self.assertIsInstance(p, _JoinablePath)
+
+    def test_parser(self):
+        self.assertIsInstance(self.cls.parser, _PathParser)
+
+    def test_constructor(self):
+        P = self.cls
+        p = P('a')
+        self.assertIsInstance(p, P)
+        P()
+        P('a', 'b', 'c')
+        P('/a', 'b', 'c')
+        P('a/b/c')
+        P('/a/b/c')
+
+    def test_with_segments(self):
+        class P(self.cls):
+            def __init__(self, *pathsegments, session_id):
+                super().__init__(*pathsegments)
+                self.session_id = session_id
+
+            def with_segments(self, *pathsegments):
+                return type(self)(*pathsegments, session_id=self.session_id)
+        p = P('foo', 'bar', session_id=42)
+        self.assertEqual(42, (p / 'foo').session_id)
+        self.assertEqual(42, ('foo' / p).session_id)
+        self.assertEqual(42, p.joinpath('foo').session_id)
+        self.assertEqual(42, p.with_name('foo').session_id)
+        self.assertEqual(42, p.with_stem('foo').session_id)
+        self.assertEqual(42, p.with_suffix('.foo').session_id)
+        self.assertEqual(42, p.with_segments('foo').session_id)
+        self.assertEqual(42, p.parent.session_id)
+        for parent in p.parents:
+            self.assertEqual(42, parent.session_id)
+
+    def test_join(self):
+        P = self.cls
+        sep = self.cls.parser.sep
+        p = P(f'a{sep}b')
+        pp = p.joinpath('c')
+        self.assertEqual(pp, P(f'a{sep}b{sep}c'))
+        self.assertIs(type(pp), type(p))
+        pp = p.joinpath('c', 'd')
+        self.assertEqual(pp, P(f'a{sep}b{sep}c{sep}d'))
+        pp = p.joinpath(f'{sep}c')
+        self.assertEqual(pp, P(f'{sep}c'))
+
+    def test_div(self):
+        # Basically the same as joinpath().
+        P = self.cls
+        sep = self.cls.parser.sep
+        p = P(f'a{sep}b')
+        pp = p / 'c'
+        self.assertEqual(pp, P(f'a{sep}b{sep}c'))
+        self.assertIs(type(pp), type(p))
+        pp = p / f'c{sep}d'
+        self.assertEqual(pp, P(f'a{sep}b{sep}c{sep}d'))
+        pp = p / 'c' / 'd'
+        self.assertEqual(pp, P(f'a{sep}b{sep}c{sep}d'))
+        pp = 'c' / p / 'd'
+        self.assertEqual(pp, P(f'c{sep}a{sep}b{sep}d'))
+        pp = p/ f'{sep}c'
+        self.assertEqual(pp, P(f'{sep}c'))
+
+    def test_full_match(self):
+        P = self.cls
+        # Simple relative pattern.
+        self.assertTrue(P('b.py').full_match('b.py'))
+        self.assertFalse(P('a/b.py').full_match('b.py'))
+        self.assertFalse(P('/a/b.py').full_match('b.py'))
+        self.assertFalse(P('a.py').full_match('b.py'))
+        self.assertFalse(P('b/py').full_match('b.py'))
+        self.assertFalse(P('/a.py').full_match('b.py'))
+        self.assertFalse(P('b.py/c').full_match('b.py'))
+        # Wildcard relative pattern.
+        self.assertTrue(P('b.py').full_match('*.py'))
+        self.assertFalse(P('a/b.py').full_match('*.py'))
+        self.assertFalse(P('/a/b.py').full_match('*.py'))
+        self.assertFalse(P('b.pyc').full_match('*.py'))
+        self.assertFalse(P('b./py').full_match('*.py'))
+        self.assertFalse(P('b.py/c').full_match('*.py'))
+        # Multi-part relative pattern.
+        self.assertTrue(P('ab/c.py').full_match('a*/*.py'))
+        self.assertFalse(P('/d/ab/c.py').full_match('a*/*.py'))
+        self.assertFalse(P('a.py').full_match('a*/*.py'))
+        self.assertFalse(P('/dab/c.py').full_match('a*/*.py'))
+        self.assertFalse(P('ab/c.py/d').full_match('a*/*.py'))
+        # Absolute pattern.
+        self.assertTrue(P('/b.py').full_match('/*.py'))
+        self.assertFalse(P('b.py').full_match('/*.py'))
+        self.assertFalse(P('a/b.py').full_match('/*.py'))
+        self.assertFalse(P('/a/b.py').full_match('/*.py'))
+        # Multi-part absolute pattern.
+        self.assertTrue(P('/a/b.py').full_match('/a/*.py'))
+        self.assertFalse(P('/ab.py').full_match('/a/*.py'))
+        self.assertFalse(P('/a/b/c.py').full_match('/a/*.py'))
+        # Multi-part glob-style pattern.
+        self.assertTrue(P('a').full_match('**'))
+        self.assertTrue(P('c.py').full_match('**'))
+        self.assertTrue(P('a/b/c.py').full_match('**'))
+        self.assertTrue(P('/a/b/c.py').full_match('**'))
+        self.assertTrue(P('/a/b/c.py').full_match('/**'))
+        self.assertTrue(P('/a/b/c.py').full_match('/a/**'))
+        self.assertTrue(P('/a/b/c.py').full_match('**/*.py'))
+        self.assertTrue(P('/a/b/c.py').full_match('/**/*.py'))
+        self.assertTrue(P('/a/b/c.py').full_match('/a/**/*.py'))
+        self.assertTrue(P('/a/b/c.py').full_match('/a/b/**/*.py'))
+        self.assertTrue(P('/a/b/c.py').full_match('/**/**/**/**/*.py'))
+        self.assertFalse(P('c.py').full_match('**/a.py'))
+        self.assertFalse(P('c.py').full_match('c/**'))
+        self.assertFalse(P('a/b/c.py').full_match('**/a'))
+        self.assertFalse(P('a/b/c.py').full_match('**/a/b'))
+        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c'))
+        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c.'))
+        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**'))
+        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**'))
+        self.assertFalse(P('a/b/c.py').full_match('/a/b/c.py/**'))
+        self.assertFalse(P('a/b/c.py').full_match('/**/a/b/c.py'))
+        # Case-sensitive flag
+        self.assertFalse(P('A.py').full_match('a.PY', case_sensitive=True))
+        self.assertTrue(P('A.py').full_match('a.PY', case_sensitive=False))
+        self.assertFalse(P('c:/a/B.Py').full_match('C:/A/*.pY', 
case_sensitive=True))
+        self.assertTrue(P('/a/b/c.py').full_match('/A/*/*.Py', 
case_sensitive=False))
+        # Matching against empty path
+        self.assertFalse(P('').full_match('*'))
+        self.assertTrue(P('').full_match('**'))
+        self.assertFalse(P('').full_match('**/*'))
+        # Matching with empty pattern
+        self.assertTrue(P('').full_match(''))
+        self.assertTrue(P('.').full_match('.'))
+        self.assertFalse(P('/').full_match(''))
+        self.assertFalse(P('/').full_match('.'))
+        self.assertFalse(P('foo').full_match(''))
+        self.assertFalse(P('foo').full_match('.'))
+
+    def test_parts(self):
+        # `parts` returns a tuple.
+        sep = self.cls.parser.sep
+        P = self.cls
+        p = P(f'a{sep}b')
+        parts = p.parts
+        self.assertEqual(parts, ('a', 'b'))
+        # When the path is absolute, the anchor is a separate part.
+        p = P(f'{sep}a{sep}b')
+        parts = p.parts
+        self.assertEqual(parts, (sep, 'a', 'b'))
+
+    def test_parent(self):
+        # Relative
+        P = self.cls
+        p = P('a/b/c')
+        self.assertEqual(p.parent, P('a/b'))
+        self.assertEqual(p.parent.parent, P('a'))
+        self.assertEqual(p.parent.parent.parent, P(''))
+        self.assertEqual(p.parent.parent.parent.parent, P(''))
+        # Anchored
+        p = P('/a/b/c')
+        self.assertEqual(p.parent, P('/a/b'))
+        self.assertEqual(p.parent.parent, P('/a'))
+        self.assertEqual(p.parent.parent.parent, P('/'))
+        self.assertEqual(p.parent.parent.parent.parent, P('/'))
+
+    def test_parents(self):
+        # Relative
+        P = self.cls
+        p = P('a/b/c')
+        par = p.parents
+        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('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('')])
+        with self.assertRaises(IndexError):
+            par[-4]
+        with self.assertRaises(IndexError):
+            par[3]
+        with self.assertRaises(TypeError):
+            par[0] = p
+        # Anchored
+        p = P('/a/b/c')
+        par = p.parents
+        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('/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('/')])
+        with self.assertRaises(IndexError):
+            par[-4]
+        with self.assertRaises(IndexError):
+            par[3]
+
+    def test_anchor(self):
+        P = self.cls
+        sep = self.cls.parser.sep
+        self.assertEqual(P('').anchor, '')
+        self.assertEqual(P(f'a{sep}b').anchor, '')
+        self.assertEqual(P(sep).anchor, sep)
+        self.assertEqual(P(f'{sep}a{sep}b').anchor, sep)
+
+    def test_name(self):
+        P = self.cls
+        self.assertEqual(P('').name, '')
+        self.assertEqual(P('/').name, '')
+        self.assertEqual(P('a/b').name, 'b')
+        self.assertEqual(P('/a/b').name, 'b')
+        self.assertEqual(P('a/b.py').name, 'b.py')
+        self.assertEqual(P('/a/b.py').name, 'b.py')
+
+    def test_suffix(self):
+        P = self.cls
+        self.assertEqual(P('').suffix, '')
+        self.assertEqual(P('.').suffix, '')
+        self.assertEqual(P('..').suffix, '')
+        self.assertEqual(P('/').suffix, '')
+        self.assertEqual(P('a/b').suffix, '')
+        self.assertEqual(P('/a/b').suffix, '')
+        self.assertEqual(P('/a/b/.').suffix, '')
+        self.assertEqual(P('a/b.py').suffix, '.py')
+        self.assertEqual(P('/a/b.py').suffix, '.py')
+        self.assertEqual(P('a/.hgrc').suffix, '')
+        self.assertEqual(P('/a/.hgrc').suffix, '')
+        self.assertEqual(P('a/.hg.rc').suffix, '.rc')
+        self.assertEqual(P('/a/.hg.rc').suffix, '.rc')
+        self.assertEqual(P('a/b.tar.gz').suffix, '.gz')
+        self.assertEqual(P('/a/b.tar.gz').suffix, '.gz')
+        self.assertEqual(P('a/trailing.dot.').suffix, '.')
+        self.assertEqual(P('/a/trailing.dot.').suffix, '.')
+        self.assertEqual(P('a/..d.o.t..').suffix, '.')
+        self.assertEqual(P('a/inn.er..dots').suffix, '.dots')
+        self.assertEqual(P('photo').suffix, '')
+        self.assertEqual(P('photo.jpg').suffix, '.jpg')
+
+    def test_suffixes(self):
+        P = self.cls
+        self.assertEqual(P('').suffixes, [])
+        self.assertEqual(P('.').suffixes, [])
+        self.assertEqual(P('/').suffixes, [])
+        self.assertEqual(P('a/b').suffixes, [])
+        self.assertEqual(P('/a/b').suffixes, [])
+        self.assertEqual(P('/a/b/.').suffixes, [])
+        self.assertEqual(P('a/b.py').suffixes, ['.py'])
+        self.assertEqual(P('/a/b.py').suffixes, ['.py'])
+        self.assertEqual(P('a/.hgrc').suffixes, [])
+        self.assertEqual(P('/a/.hgrc').suffixes, [])
+        self.assertEqual(P('a/.hg.rc').suffixes, ['.rc'])
+        self.assertEqual(P('/a/.hg.rc').suffixes, ['.rc'])
+        self.assertEqual(P('a/b.tar.gz').suffixes, ['.tar', '.gz'])
+        self.assertEqual(P('/a/b.tar.gz').suffixes, ['.tar', '.gz'])
+        self.assertEqual(P('a/trailing.dot.').suffixes, ['.dot', '.'])
+        self.assertEqual(P('/a/trailing.dot.').suffixes, ['.dot', '.'])
+        self.assertEqual(P('a/..d.o.t..').suffixes, ['.o', '.t', '.', '.'])
+        self.assertEqual(P('a/inn.er..dots').suffixes, ['.er', '.', '.dots'])
+        self.assertEqual(P('photo').suffixes, [])
+        self.assertEqual(P('photo.jpg').suffixes, ['.jpg'])
+
+    def test_stem(self):
+        P = self.cls
+        self.assertEqual(P('..').stem, '..')
+        self.assertEqual(P('').stem, '')
+        self.assertEqual(P('/').stem, '')
+        self.assertEqual(P('a/b').stem, 'b')
+        self.assertEqual(P('a/b.py').stem, 'b')
+        self.assertEqual(P('a/.hgrc').stem, '.hgrc')
+        self.assertEqual(P('a/.hg.rc').stem, '.hg')
+        self.assertEqual(P('a/b.tar.gz').stem, 'b.tar')
+        self.assertEqual(P('a/trailing.dot.').stem, 'trailing.dot')
+        self.assertEqual(P('a/..d.o.t..').stem, '..d.o.t.')
+        self.assertEqual(P('a/inn.er..dots').stem, 'inn.er.')
+        self.assertEqual(P('photo').stem, 'photo')
+        self.assertEqual(P('photo.jpg').stem, 'photo')
+
+    def test_with_name(self):
+        P = self.cls
+        self.assertEqual(P('a/b').with_name('d.xml'), P('a/d.xml'))
+        self.assertEqual(P('/a/b').with_name('d.xml'), P('/a/d.xml'))
+        self.assertEqual(P('a/b.py').with_name('d.xml'), P('a/d.xml'))
+        self.assertEqual(P('/a/b.py').with_name('d.xml'), P('/a/d.xml'))
+        self.assertEqual(P('a/Dot ending.').with_name('d.xml'), P('a/d.xml'))
+        self.assertEqual(P('/a/Dot ending.').with_name('d.xml'), P('/a/d.xml'))
+        self.assertRaises(ValueError, P('a/b').with_name, '/c')
+        self.assertRaises(ValueError, P('a/b').with_name, 'c/')
+        self.assertRaises(ValueError, P('a/b').with_name, 'c/d')
+
+    def test_with_stem(self):
+        P = self.cls
+        self.assertEqual(P('a/b').with_stem('d'), P('a/d'))
+        self.assertEqual(P('/a/b').with_stem('d'), P('/a/d'))
+        self.assertEqual(P('a/b.py').with_stem('d'), P('a/d.py'))
+        self.assertEqual(P('/a/b.py').with_stem('d'), P('/a/d.py'))
+        self.assertEqual(P('/a/b.tar.gz').with_stem('d'), P('/a/d.gz'))
+        self.assertEqual(P('a/Dot ending.').with_stem('d'), P('a/d.'))
+        self.assertEqual(P('/a/Dot ending.').with_stem('d'), P('/a/d.'))
+        self.assertRaises(ValueError, P('foo.gz').with_stem, '')
+        self.assertRaises(ValueError, P('/a/b/foo.gz').with_stem, '')
+        self.assertRaises(ValueError, P('a/b').with_stem, '/c')
+        self.assertRaises(ValueError, P('a/b').with_stem, 'c/')
+        self.assertRaises(ValueError, P('a/b').with_stem, 'c/d')
+
+    def test_with_suffix(self):
+        P = self.cls
+        self.assertEqual(P('a/b').with_suffix('.gz'), P('a/b.gz'))
+        self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz'))
+        self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz'))
+        self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz'))
+        # Stripping suffix.
+        self.assertEqual(P('a/b.py').with_suffix(''), P('a/b'))
+        self.assertEqual(P('/a/b').with_suffix(''), P('/a/b'))
+        # Single dot
+        self.assertEqual(P('a/b').with_suffix('.'), P('a/b.'))
+        self.assertEqual(P('/a/b').with_suffix('.'), P('/a/b.'))
+        self.assertEqual(P('a/b.py').with_suffix('.'), P('a/b.'))
+        self.assertEqual(P('/a/b.py').with_suffix('.'), P('/a/b.'))
+        # Path doesn't have a "filename" component.
+        self.assertRaises(ValueError, P('').with_suffix, '.gz')
+        self.assertRaises(ValueError, P('/').with_suffix, '.gz')
+        # Invalid suffix.
+        self.assertRaises(ValueError, P('a/b').with_suffix, 'gz')
+        self.assertRaises(ValueError, P('a/b').with_suffix, '/')
+        self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz')
+        self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d')
+        self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d')
+        self.assertRaises(ValueError, P('a/b').with_suffix, './.d')
+        self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.')
+        self.assertRaises(TypeError, P('a/b').with_suffix, None)
+
+
+class LexicalPathJoinTest(JoinTestBase, unittest.TestCase):
+    cls = LexicalPath
+
+
+class PurePathJoinTest(JoinTestBase, unittest.TestCase):
+    cls = PurePath
+
+
+class PathJoinTest(JoinTestBase, unittest.TestCase):
+    cls = Path
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py 
b/Lib/test/test_pathlib/test_pathlib_abc.py
index dea16e6351265f..c6038d61b89506 100644
--- a/Lib/test/test_pathlib/test_pathlib_abc.py
+++ b/Lib/test/test_pathlib/test_pathlib_abc.py
@@ -76,23 +76,6 @@ 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)
-
-    def test_constructor_common(self):
-        P = self.cls
-        p = P('a')
-        self.assertIsInstance(p, P)
-        P()
-        P('a', 'b', 'c')
-        P('/a', 'b', 'c')
-        P('a/b/c')
-        P('/a/b/c')
-
     def _check_str_subclass(self, *args):
         # Issue #21127: it should be possible to construct a PurePath object
         # from a str subclass instance, and it then gets converted to
@@ -125,37 +108,6 @@ def test_str_subclass_windows(self):
         self._check_str_subclass('\\\\some\\share\\a')
         self._check_str_subclass('\\\\some\\share\\a\\b.txt')
 
-    def test_with_segments_common(self):
-        class P(self.cls):
-            def __init__(self, *pathsegments, session_id):
-                super().__init__(*pathsegments)
-                self.session_id = session_id
-
-            def with_segments(self, *pathsegments):
-                return type(self)(*pathsegments, session_id=self.session_id)
-        p = P('foo', 'bar', session_id=42)
-        self.assertEqual(42, (p / 'foo').session_id)
-        self.assertEqual(42, ('foo' / p).session_id)
-        self.assertEqual(42, p.joinpath('foo').session_id)
-        self.assertEqual(42, p.with_name('foo').session_id)
-        self.assertEqual(42, p.with_stem('foo').session_id)
-        self.assertEqual(42, p.with_suffix('.foo').session_id)
-        self.assertEqual(42, p.with_segments('foo').session_id)
-        self.assertEqual(42, p.parent.session_id)
-        for parent in p.parents:
-            self.assertEqual(42, parent.session_id)
-
-    def test_join_common(self):
-        P = self.cls
-        p = P('a/b')
-        pp = p.joinpath('c')
-        self.assertEqual(pp, P('a/b/c'))
-        self.assertIs(type(pp), type(p))
-        pp = p.joinpath('c', 'd')
-        self.assertEqual(pp, P('a/b/c/d'))
-        pp = p.joinpath('/c')
-        self.assertEqual(pp, P('/c'))
-
     @needs_posix
     def test_join_posix(self):
         P = self.cls
@@ -205,22 +157,6 @@ def test_join_windows(self):
         pp = P('//./BootPartition').joinpath('Windows')
         self.assertEqual(pp, P('//./BootPartition/Windows'))
 
-    def test_div_common(self):
-        # Basically the same as joinpath().
-        P = self.cls
-        p = P('a/b')
-        pp = p / 'c'
-        self.assertEqual(pp, P('a/b/c'))
-        self.assertIs(type(pp), type(p))
-        pp = p / 'c/d'
-        self.assertEqual(pp, P('a/b/c/d'))
-        pp = p / 'c' / 'd'
-        self.assertEqual(pp, P('a/b/c/d'))
-        pp = 'c' / p / 'd'
-        self.assertEqual(pp, P('c/a/b/d'))
-        pp = p/ '/c'
-        self.assertEqual(pp, P('/c'))
-
     @needs_posix
     def test_div_posix(self):
         # Basically the same as joinpath().
@@ -282,89 +218,6 @@ def test_str_windows(self):
         p = self.cls('//a/b/c/d')
         self.assertEqual(str(p), '\\\\a\\b\\c\\d')
 
-    def test_full_match_common(self):
-        P = self.cls
-        # Simple relative pattern.
-        self.assertTrue(P('b.py').full_match('b.py'))
-        self.assertFalse(P('a/b.py').full_match('b.py'))
-        self.assertFalse(P('/a/b.py').full_match('b.py'))
-        self.assertFalse(P('a.py').full_match('b.py'))
-        self.assertFalse(P('b/py').full_match('b.py'))
-        self.assertFalse(P('/a.py').full_match('b.py'))
-        self.assertFalse(P('b.py/c').full_match('b.py'))
-        # Wildcard relative pattern.
-        self.assertTrue(P('b.py').full_match('*.py'))
-        self.assertFalse(P('a/b.py').full_match('*.py'))
-        self.assertFalse(P('/a/b.py').full_match('*.py'))
-        self.assertFalse(P('b.pyc').full_match('*.py'))
-        self.assertFalse(P('b./py').full_match('*.py'))
-        self.assertFalse(P('b.py/c').full_match('*.py'))
-        # Multi-part relative pattern.
-        self.assertTrue(P('ab/c.py').full_match('a*/*.py'))
-        self.assertFalse(P('/d/ab/c.py').full_match('a*/*.py'))
-        self.assertFalse(P('a.py').full_match('a*/*.py'))
-        self.assertFalse(P('/dab/c.py').full_match('a*/*.py'))
-        self.assertFalse(P('ab/c.py/d').full_match('a*/*.py'))
-        # Absolute pattern.
-        self.assertTrue(P('/b.py').full_match('/*.py'))
-        self.assertFalse(P('b.py').full_match('/*.py'))
-        self.assertFalse(P('a/b.py').full_match('/*.py'))
-        self.assertFalse(P('/a/b.py').full_match('/*.py'))
-        # Multi-part absolute pattern.
-        self.assertTrue(P('/a/b.py').full_match('/a/*.py'))
-        self.assertFalse(P('/ab.py').full_match('/a/*.py'))
-        self.assertFalse(P('/a/b/c.py').full_match('/a/*.py'))
-        # Multi-part glob-style pattern.
-        self.assertTrue(P('a').full_match('**'))
-        self.assertTrue(P('c.py').full_match('**'))
-        self.assertTrue(P('a/b/c.py').full_match('**'))
-        self.assertTrue(P('/a/b/c.py').full_match('**'))
-        self.assertTrue(P('/a/b/c.py').full_match('/**'))
-        self.assertTrue(P('/a/b/c.py').full_match('/a/**'))
-        self.assertTrue(P('/a/b/c.py').full_match('**/*.py'))
-        self.assertTrue(P('/a/b/c.py').full_match('/**/*.py'))
-        self.assertTrue(P('/a/b/c.py').full_match('/a/**/*.py'))
-        self.assertTrue(P('/a/b/c.py').full_match('/a/b/**/*.py'))
-        self.assertTrue(P('/a/b/c.py').full_match('/**/**/**/**/*.py'))
-        self.assertFalse(P('c.py').full_match('**/a.py'))
-        self.assertFalse(P('c.py').full_match('c/**'))
-        self.assertFalse(P('a/b/c.py').full_match('**/a'))
-        self.assertFalse(P('a/b/c.py').full_match('**/a/b'))
-        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c'))
-        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c.'))
-        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**'))
-        self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**'))
-        self.assertFalse(P('a/b/c.py').full_match('/a/b/c.py/**'))
-        self.assertFalse(P('a/b/c.py').full_match('/**/a/b/c.py'))
-        # Case-sensitive flag
-        self.assertFalse(P('A.py').full_match('a.PY', case_sensitive=True))
-        self.assertTrue(P('A.py').full_match('a.PY', case_sensitive=False))
-        self.assertFalse(P('c:/a/B.Py').full_match('C:/A/*.pY', 
case_sensitive=True))
-        self.assertTrue(P('/a/b/c.py').full_match('/A/*/*.Py', 
case_sensitive=False))
-        # Matching against empty path
-        self.assertFalse(P('').full_match('*'))
-        self.assertTrue(P('').full_match('**'))
-        self.assertFalse(P('').full_match('**/*'))
-        # Matching with empty pattern
-        self.assertTrue(P('').full_match(''))
-        self.assertTrue(P('.').full_match('.'))
-        self.assertFalse(P('/').full_match(''))
-        self.assertFalse(P('/').full_match('.'))
-        self.assertFalse(P('foo').full_match(''))
-        self.assertFalse(P('foo').full_match('.'))
-
-    def test_parts_common(self):
-        # `parts` returns a tuple.
-        sep = self.sep
-        P = self.cls
-        p = P('a/b')
-        parts = p.parts
-        self.assertEqual(parts, ('a', 'b'))
-        # When the path is absolute, the anchor is a separate part.
-        p = P('/a/b')
-        parts = p.parts
-        self.assertEqual(parts, (sep, 'a', 'b'))
-
     @needs_windows
     def test_parts_windows(self):
         P = self.cls
@@ -378,21 +231,6 @@ def test_parts_windows(self):
         parts = p.parts
         self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd'))
 
-    def test_parent_common(self):
-        # Relative
-        P = self.cls
-        p = P('a/b/c')
-        self.assertEqual(p.parent, P('a/b'))
-        self.assertEqual(p.parent.parent, P('a'))
-        self.assertEqual(p.parent.parent.parent, P(''))
-        self.assertEqual(p.parent.parent.parent.parent, P(''))
-        # Anchored
-        p = P('/a/b/c')
-        self.assertEqual(p.parent, P('/a/b'))
-        self.assertEqual(p.parent.parent, P('/a'))
-        self.assertEqual(p.parent.parent.parent, P('/'))
-        self.assertEqual(p.parent.parent.parent.parent, P('/'))
-
     @needs_windows
     def test_parent_windows(self):
         # Anchored
@@ -412,53 +250,6 @@ def test_parent_windows(self):
         self.assertEqual(p.parent.parent, P('//a/b'))
         self.assertEqual(p.parent.parent.parent, P('//a/b'))
 
-    def test_parents_common(self):
-        # Relative
-        P = self.cls
-        p = P('a/b/c')
-        par = p.parents
-        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('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('')])
-        with self.assertRaises(IndexError):
-            par[-4]
-        with self.assertRaises(IndexError):
-            par[3]
-        with self.assertRaises(TypeError):
-            par[0] = p
-        # Anchored
-        p = P('/a/b/c')
-        par = p.parents
-        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('/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('/')])
-        with self.assertRaises(IndexError):
-            par[-4]
-        with self.assertRaises(IndexError):
-            par[3]
-
     @needs_windows
     def test_parents_windows(self):
         # Anchored
@@ -506,14 +297,6 @@ def test_parents_windows(self):
         with self.assertRaises(IndexError):
             par[2]
 
-    def test_anchor_common(self):
-        P = self.cls
-        sep = self.sep
-        self.assertEqual(P('').anchor, '')
-        self.assertEqual(P('a/b').anchor, '')
-        self.assertEqual(P('/').anchor, sep)
-        self.assertEqual(P('/a/b').anchor, sep)
-
     @needs_windows
     def test_anchor_windows(self):
         P = self.cls
@@ -525,20 +308,6 @@ def test_anchor_windows(self):
         self.assertEqual(P('//a/b/').anchor, '\\\\a\\b\\')
         self.assertEqual(P('//a/b/c/d').anchor, '\\\\a\\b\\')
 
-    def test_name_empty(self):
-        P = self.cls
-        self.assertEqual(P('').name, '')
-        self.assertEqual(P('.').name, '.')
-        self.assertEqual(P('/a/b/.').name, '.')
-
-    def test_name_common(self):
-        P = self.cls
-        self.assertEqual(P('/').name, '')
-        self.assertEqual(P('a/b').name, 'b')
-        self.assertEqual(P('/a/b').name, 'b')
-        self.assertEqual(P('a/b.py').name, 'b.py')
-        self.assertEqual(P('/a/b.py').name, 'b.py')
-
     @needs_windows
     def test_name_windows(self):
         P = self.cls
@@ -551,30 +320,6 @@ def test_name_windows(self):
         self.assertEqual(P('//My.py/Share.php').name, '')
         self.assertEqual(P('//My.py/Share.php/a/b').name, 'b')
 
-    def test_suffix_common(self):
-        P = self.cls
-        self.assertEqual(P('').suffix, '')
-        self.assertEqual(P('.').suffix, '')
-        self.assertEqual(P('..').suffix, '')
-        self.assertEqual(P('/').suffix, '')
-        self.assertEqual(P('a/b').suffix, '')
-        self.assertEqual(P('/a/b').suffix, '')
-        self.assertEqual(P('/a/b/.').suffix, '')
-        self.assertEqual(P('a/b.py').suffix, '.py')
-        self.assertEqual(P('/a/b.py').suffix, '.py')
-        self.assertEqual(P('a/.hgrc').suffix, '')
-        self.assertEqual(P('/a/.hgrc').suffix, '')
-        self.assertEqual(P('a/.hg.rc').suffix, '.rc')
-        self.assertEqual(P('/a/.hg.rc').suffix, '.rc')
-        self.assertEqual(P('a/b.tar.gz').suffix, '.gz')
-        self.assertEqual(P('/a/b.tar.gz').suffix, '.gz')
-        self.assertEqual(P('a/trailing.dot.').suffix, '.')
-        self.assertEqual(P('/a/trailing.dot.').suffix, '.')
-        self.assertEqual(P('a/..d.o.t..').suffix, '.')
-        self.assertEqual(P('a/inn.er..dots').suffix, '.dots')
-        self.assertEqual(P('photo').suffix, '')
-        self.assertEqual(P('photo.jpg').suffix, '.jpg')
-
     @needs_windows
     def test_suffix_windows(self):
         P = self.cls
@@ -595,29 +340,6 @@ def test_suffix_windows(self):
         self.assertEqual(P('//My.py/Share.php').suffix, '')
         self.assertEqual(P('//My.py/Share.php/a/b').suffix, '')
 
-    def test_suffixes_common(self):
-        P = self.cls
-        self.assertEqual(P('').suffixes, [])
-        self.assertEqual(P('.').suffixes, [])
-        self.assertEqual(P('/').suffixes, [])
-        self.assertEqual(P('a/b').suffixes, [])
-        self.assertEqual(P('/a/b').suffixes, [])
-        self.assertEqual(P('/a/b/.').suffixes, [])
-        self.assertEqual(P('a/b.py').suffixes, ['.py'])
-        self.assertEqual(P('/a/b.py').suffixes, ['.py'])
-        self.assertEqual(P('a/.hgrc').suffixes, [])
-        self.assertEqual(P('/a/.hgrc').suffixes, [])
-        self.assertEqual(P('a/.hg.rc').suffixes, ['.rc'])
-        self.assertEqual(P('/a/.hg.rc').suffixes, ['.rc'])
-        self.assertEqual(P('a/b.tar.gz').suffixes, ['.tar', '.gz'])
-        self.assertEqual(P('/a/b.tar.gz').suffixes, ['.tar', '.gz'])
-        self.assertEqual(P('a/trailing.dot.').suffixes, ['.dot', '.'])
-        self.assertEqual(P('/a/trailing.dot.').suffixes, ['.dot', '.'])
-        self.assertEqual(P('a/..d.o.t..').suffixes, ['.o', '.t', '.', '.'])
-        self.assertEqual(P('a/inn.er..dots').suffixes, ['.er', '.', '.dots'])
-        self.assertEqual(P('photo').suffixes, [])
-        self.assertEqual(P('photo.jpg').suffixes, ['.jpg'])
-
     @needs_windows
     def test_suffixes_windows(self):
         P = self.cls
@@ -638,26 +360,6 @@ def test_suffixes_windows(self):
         self.assertEqual(P('c:a/trailing.dot.').suffixes, ['.dot', '.'])
         self.assertEqual(P('c:/a/trailing.dot.').suffixes, ['.dot', '.'])
 
-    def test_stem_empty(self):
-        P = self.cls
-        self.assertEqual(P('').stem, '')
-        self.assertEqual(P('.').stem, '.')
-
-    def test_stem_common(self):
-        P = self.cls
-        self.assertEqual(P('..').stem, '..')
-        self.assertEqual(P('/').stem, '')
-        self.assertEqual(P('a/b').stem, 'b')
-        self.assertEqual(P('a/b.py').stem, 'b')
-        self.assertEqual(P('a/.hgrc').stem, '.hgrc')
-        self.assertEqual(P('a/.hg.rc').stem, '.hg')
-        self.assertEqual(P('a/b.tar.gz').stem, 'b.tar')
-        self.assertEqual(P('a/trailing.dot.').stem, 'trailing.dot')
-        self.assertEqual(P('a/..d.o.t..').stem, '..d.o.t.')
-        self.assertEqual(P('a/inn.er..dots').stem, 'inn.er.')
-        self.assertEqual(P('photo').stem, 'photo')
-        self.assertEqual(P('photo.jpg').stem, 'photo')
-
     @needs_windows
     def test_stem_windows(self):
         P = self.cls
@@ -672,15 +374,6 @@ def test_stem_windows(self):
         self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar')
         self.assertEqual(P('c:a/trailing.dot.').stem, 'trailing.dot')
 
-    def test_with_name_common(self):
-        P = self.cls
-        self.assertEqual(P('a/b').with_name('d.xml'), P('a/d.xml'))
-        self.assertEqual(P('/a/b').with_name('d.xml'), P('/a/d.xml'))
-        self.assertEqual(P('a/b.py').with_name('d.xml'), P('a/d.xml'))
-        self.assertEqual(P('/a/b.py').with_name('d.xml'), P('/a/d.xml'))
-        self.assertEqual(P('a/Dot ending.').with_name('d.xml'), P('a/d.xml'))
-        self.assertEqual(P('/a/Dot ending.').with_name('d.xml'), P('/a/d.xml'))
-
     @needs_windows
     def test_with_name_windows(self):
         P = self.cls
@@ -698,30 +391,6 @@ def test_with_name_windows(self):
         self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e')
         self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share')
 
-    def test_with_name_empty(self):
-        P = self.cls
-        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
-        self.assertRaises(ValueError, P('a/b').with_name, '/c')
-        self.assertRaises(ValueError, P('a/b').with_name, 'c/')
-        self.assertRaises(ValueError, P('a/b').with_name, 'c/d')
-
-    def test_with_stem_common(self):
-        P = self.cls
-        self.assertEqual(P('a/b').with_stem('d'), P('a/d'))
-        self.assertEqual(P('/a/b').with_stem('d'), P('/a/d'))
-        self.assertEqual(P('a/b.py').with_stem('d'), P('a/d.py'))
-        self.assertEqual(P('/a/b.py').with_stem('d'), P('/a/d.py'))
-        self.assertEqual(P('/a/b.tar.gz').with_stem('d'), P('/a/d.gz'))
-        self.assertEqual(P('a/Dot ending.').with_stem('d'), P('a/d.'))
-        self.assertEqual(P('/a/Dot ending.').with_stem('d'), P('/a/d.'))
-
     @needs_windows
     def test_with_stem_windows(self):
         P = self.cls
@@ -739,37 +408,6 @@ def test_with_stem_windows(self):
         self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:/e')
         self.assertRaises(ValueError, P('c:a/b').with_stem, '//My/Share')
 
-    def test_with_stem_empty(self):
-        P = self.cls
-        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/.'))
-        self.assertRaises(ValueError, P('foo.gz').with_stem, '')
-        self.assertRaises(ValueError, P('/a/b/foo.gz').with_stem, '')
-
-    def test_with_stem_seps(self):
-        P = self.cls
-        self.assertRaises(ValueError, P('a/b').with_stem, '/c')
-        self.assertRaises(ValueError, P('a/b').with_stem, 'c/')
-        self.assertRaises(ValueError, P('a/b').with_stem, 'c/d')
-
-    def test_with_suffix_common(self):
-        P = self.cls
-        self.assertEqual(P('a/b').with_suffix('.gz'), P('a/b.gz'))
-        self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz'))
-        self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz'))
-        self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz'))
-        # Stripping suffix.
-        self.assertEqual(P('a/b.py').with_suffix(''), P('a/b'))
-        self.assertEqual(P('/a/b').with_suffix(''), P('/a/b'))
-        # Single dot
-        self.assertEqual(P('a/b').with_suffix('.'), P('a/b.'))
-        self.assertEqual(P('/a/b').with_suffix('.'), P('/a/b.'))
-        self.assertEqual(P('a/b.py').with_suffix('.'), P('a/b.'))
-        self.assertEqual(P('/a/b.py').with_suffix('.'), P('/a/b.'))
-
     @needs_windows
     def test_with_suffix_windows(self):
         P = self.cls
@@ -796,25 +434,6 @@ def test_with_suffix_windows(self):
         self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d')
         self.assertRaises(TypeError, P('c:a/b').with_suffix, None)
 
-    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')
-
-    def test_with_suffix_invalid(self):
-        P = self.cls
-        # Invalid suffix.
-        self.assertRaises(ValueError, P('a/b').with_suffix, 'gz')
-        self.assertRaises(ValueError, P('a/b').with_suffix, '/')
-        self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz')
-        self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d')
-        self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d')
-        self.assertRaises(ValueError, P('a/b').with_suffix, './.d')
-        self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.')
-        self.assertRaises(TypeError, P('a/b').with_suffix, None)
-
-
 #
 # Tests for the virtual classes.
 #
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 7ac301c82678aa..5fdbfa1053c9ed 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2524,6 +2524,7 @@ TESTSUBDIRS=      idlelib/idle_test \
                test/test_multiprocessing_forkserver \
                test/test_multiprocessing_spawn \
                test/test_pathlib \
+               test/test_pathlib/support \
                test/test_peg_generator \
                test/test_pydoc \
                test/test_pyrepl \

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to