https://github.com/python/cpython/commit/3569e4a670bc6a02f1bb1baf08ecfb85c63755fb
commit: 3569e4a670bc6a02f1bb1baf08ecfb85c63755fb
branch: main
author: Barney Gale <barney.g...@gmail.com>
committer: barneygale <barney.g...@gmail.com>
date: 2025-03-11T18:01:43Z
summary:

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

Test Windows-flavoured `pathlib.types._JoinablePath` in a dedicated test
module. These tests cover `LexicalWindowsPath`, `PureWindowsPath` and
`WindowsPath`, where `LexicalWindowsPath` is a simple implementation of
`_JoinablePath` for use in tests.

files:
A Lib/test/test_pathlib/test_join_windows.py
M Lib/test/test_pathlib/support/lexical_path.py
M Lib/test/test_pathlib/test_pathlib.py
M Lib/test/test_pathlib/test_pathlib_abc.py

diff --git a/Lib/test/test_pathlib/support/lexical_path.py 
b/Lib/test/test_pathlib/support/lexical_path.py
index 27dec30d0bdd5a..6298513de6cf83 100644
--- a/Lib/test/test_pathlib/support/lexical_path.py
+++ b/Lib/test/test_pathlib/support/lexical_path.py
@@ -2,6 +2,7 @@
 Simple implementation of JoinablePath, for use in pathlib tests.
 """
 
+import ntpath
 import os.path
 import pathlib.types
 import posixpath
@@ -37,3 +38,8 @@ def with_segments(self, *pathsegments):
 class LexicalPosixPath(LexicalPath):
     __slots__ = ()
     parser = posixpath
+
+
+class LexicalWindowsPath(LexicalPath):
+    __slots__ = ()
+    parser = ntpath
diff --git a/Lib/test/test_pathlib/test_join_windows.py 
b/Lib/test/test_pathlib/test_join_windows.py
new file mode 100644
index 00000000000000..783248d1697eef
--- /dev/null
+++ b/Lib/test/test_pathlib/test_join_windows.py
@@ -0,0 +1,290 @@
+"""
+Tests for Windows-flavoured pathlib.types._JoinablePath
+"""
+
+import os
+import unittest
+
+from pathlib import PureWindowsPath, WindowsPath
+from test.test_pathlib.support.lexical_path import LexicalWindowsPath
+
+
+class JoinTestBase:
+    def test_join(self):
+        P = self.cls
+        p = P('C:/a/b')
+        pp = p.joinpath('x/y')
+        self.assertEqual(pp, P(r'C:/a/b\x/y'))
+        pp = p.joinpath('/x/y')
+        self.assertEqual(pp, P('C:/x/y'))
+        # Joining with a different drive => the first path is ignored, even
+        # if the second path is relative.
+        pp = p.joinpath('D:x/y')
+        self.assertEqual(pp, P('D:x/y'))
+        pp = p.joinpath('D:/x/y')
+        self.assertEqual(pp, P('D:/x/y'))
+        pp = p.joinpath('//host/share/x/y')
+        self.assertEqual(pp, P('//host/share/x/y'))
+        # Joining with the same drive => the first path is appended to if
+        # the second path is relative.
+        pp = p.joinpath('c:x/y')
+        self.assertEqual(pp, P(r'c:/a/b\x/y'))
+        pp = p.joinpath('c:/x/y')
+        self.assertEqual(pp, P('c:/x/y'))
+        # Joining with files with NTFS data streams => the filename should
+        # not be parsed as a drive letter
+        pp = p.joinpath('./d:s')
+        self.assertEqual(pp, P(r'C:/a/b\./d:s'))
+        pp = p.joinpath('./dd:s')
+        self.assertEqual(pp, P(r'C:/a/b\./dd:s'))
+        pp = p.joinpath('E:d:s')
+        self.assertEqual(pp, P('E:d:s'))
+        # Joining onto a UNC path with no root
+        pp = P('//').joinpath('server')
+        self.assertEqual(pp, P('//server'))
+        pp = P('//server').joinpath('share')
+        self.assertEqual(pp, P(r'//server\share'))
+        pp = P('//./BootPartition').joinpath('Windows')
+        self.assertEqual(pp, P(r'//./BootPartition\Windows'))
+
+    def test_div(self):
+        # Basically the same as joinpath().
+        P = self.cls
+        p = P('C:/a/b')
+        self.assertEqual(p / 'x/y', P(r'C:/a/b\x/y'))
+        self.assertEqual(p / 'x' / 'y', P(r'C:/a/b\x\y'))
+        self.assertEqual(p / '/x/y', P('C:/x/y'))
+        self.assertEqual(p / '/x' / 'y', P('C:/x\y'))
+        # Joining with a different drive => the first path is ignored, even
+        # if the second path is relative.
+        self.assertEqual(p / 'D:x/y', P('D:x/y'))
+        self.assertEqual(p / 'D:' / 'x/y', P('D:x/y'))
+        self.assertEqual(p / 'D:/x/y', P('D:/x/y'))
+        self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y'))
+        self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y'))
+        # Joining with the same drive => the first path is appended to if
+        # the second path is relative.
+        self.assertEqual(p / 'c:x/y', P(r'c:/a/b\x/y'))
+        self.assertEqual(p / 'c:/x/y', P('c:/x/y'))
+        # Joining with files with NTFS data streams => the filename should
+        # not be parsed as a drive letter
+        self.assertEqual(p / './d:s', P(r'C:/a/b\./d:s'))
+        self.assertEqual(p / './dd:s', P(r'C:/a/b\./dd:s'))
+        self.assertEqual(p / 'E:d:s', P('E:d:s'))
+
+    def test_str(self):
+        p = self.cls(r'a\b\c')
+        self.assertEqual(str(p), 'a\\b\\c')
+        p = self.cls(r'c:\a\b\c')
+        self.assertEqual(str(p), 'c:\\a\\b\\c')
+        p = self.cls('\\\\a\\b\\')
+        self.assertEqual(str(p), '\\\\a\\b\\')
+        p = self.cls(r'\\a\b\c')
+        self.assertEqual(str(p), '\\\\a\\b\\c')
+        p = self.cls(r'\\a\b\c\d')
+        self.assertEqual(str(p), '\\\\a\\b\\c\\d')
+
+    def test_parts(self):
+        P = self.cls
+        p = P(r'c:a\b')
+        parts = p.parts
+        self.assertEqual(parts, ('c:', 'a', 'b'))
+        p = P(r'c:\a\b')
+        parts = p.parts
+        self.assertEqual(parts, ('c:\\', 'a', 'b'))
+        p = P(r'\\a\b\c\d')
+        parts = p.parts
+        self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd'))
+
+    def test_parent(self):
+        # Anchored
+        P = self.cls
+        p = P('z:a/b/c')
+        self.assertEqual(p.parent, P('z:a/b'))
+        self.assertEqual(p.parent.parent, P('z:a'))
+        self.assertEqual(p.parent.parent.parent, P('z:'))
+        self.assertEqual(p.parent.parent.parent.parent, P('z:'))
+        p = P('z:/a/b/c')
+        self.assertEqual(p.parent, P('z:/a/b'))
+        self.assertEqual(p.parent.parent, P('z:/a'))
+        self.assertEqual(p.parent.parent.parent, P('z:/'))
+        self.assertEqual(p.parent.parent.parent.parent, P('z:/'))
+        p = P('//a/b/c/d')
+        self.assertEqual(p.parent, P('//a/b/c'))
+        self.assertEqual(p.parent.parent, P('//a/b/'))
+        self.assertEqual(p.parent.parent.parent, P('//a/b/'))
+
+    def test_parents(self):
+        # Anchored
+        P = self.cls
+        p = P('z:a/b')
+        par = p.parents
+        self.assertEqual(len(par), 2)
+        self.assertEqual(par[0], P('z:a'))
+        self.assertEqual(par[1], P('z:'))
+        self.assertEqual(par[0:1], (P('z:a'),))
+        self.assertEqual(par[:-1], (P('z:a'),))
+        self.assertEqual(par[:2], (P('z:a'), P('z:')))
+        self.assertEqual(par[1:], (P('z:'),))
+        self.assertEqual(par[::2], (P('z:a'),))
+        self.assertEqual(par[::-1], (P('z:'), P('z:a')))
+        self.assertEqual(list(par), [P('z:a'), P('z:')])
+        with self.assertRaises(IndexError):
+            par[2]
+        p = P('z:/a/b')
+        par = p.parents
+        self.assertEqual(len(par), 2)
+        self.assertEqual(par[0], P('z:/a'))
+        self.assertEqual(par[1], P('z:/'))
+        self.assertEqual(par[0:1], (P('z:/a'),))
+        self.assertEqual(par[0:-1], (P('z:/a'),))
+        self.assertEqual(par[:2], (P('z:/a'), P('z:/')))
+        self.assertEqual(par[1:], (P('z:/'),))
+        self.assertEqual(par[::2], (P('z:/a'),))
+        self.assertEqual(par[::-1], (P('z:/'), P('z:/a'),))
+        self.assertEqual(list(par), [P('z:/a'), P('z:/')])
+        with self.assertRaises(IndexError):
+            par[2]
+        p = P('//a/b/c/d')
+        par = p.parents
+        self.assertEqual(len(par), 2)
+        self.assertEqual(par[0], P('//a/b/c'))
+        self.assertEqual(par[1], P('//a/b/'))
+        self.assertEqual(par[0:1], (P('//a/b/c'),))
+        self.assertEqual(par[0:-1], (P('//a/b/c'),))
+        self.assertEqual(par[:2], (P('//a/b/c'), P('//a/b/')))
+        self.assertEqual(par[1:], (P('//a/b/'),))
+        self.assertEqual(par[::2], (P('//a/b/c'),))
+        self.assertEqual(par[::-1], (P('//a/b/'), P('//a/b/c')))
+        self.assertEqual(list(par), [P('//a/b/c'), P('//a/b/')])
+        with self.assertRaises(IndexError):
+            par[2]
+
+    def test_anchor(self):
+        P = self.cls
+        self.assertEqual(P('c:').anchor, 'c:')
+        self.assertEqual(P('c:a/b').anchor, 'c:')
+        self.assertEqual(P('c:\\').anchor, 'c:\\')
+        self.assertEqual(P('c:\\a\\b\\').anchor, 'c:\\')
+        self.assertEqual(P('\\\\a\\b\\').anchor, '\\\\a\\b\\')
+        self.assertEqual(P('\\\\a\\b\\c\\d').anchor, '\\\\a\\b\\')
+
+    def test_name(self):
+        P = self.cls
+        self.assertEqual(P('c:').name, '')
+        self.assertEqual(P('c:/').name, '')
+        self.assertEqual(P('c:a/b').name, 'b')
+        self.assertEqual(P('c:/a/b').name, 'b')
+        self.assertEqual(P('c:a/b.py').name, 'b.py')
+        self.assertEqual(P('c:/a/b.py').name, 'b.py')
+        self.assertEqual(P('//My.py/Share.php').name, '')
+        self.assertEqual(P('//My.py/Share.php/a/b').name, 'b')
+
+    def test_stem(self):
+        P = self.cls
+        self.assertEqual(P('c:').stem, '')
+        self.assertEqual(P('c:..').stem, '..')
+        self.assertEqual(P('c:/').stem, '')
+        self.assertEqual(P('c:a/b').stem, 'b')
+        self.assertEqual(P('c:a/b.py').stem, 'b')
+        self.assertEqual(P('c:a/.hgrc').stem, '.hgrc')
+        self.assertEqual(P('c:a/.hg.rc').stem, '.hg')
+        self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar')
+        self.assertEqual(P('c:a/trailing.dot.').stem, 'trailing.dot')
+
+    def test_suffix(self):
+        P = self.cls
+        self.assertEqual(P('c:').suffix, '')
+        self.assertEqual(P('c:/').suffix, '')
+        self.assertEqual(P('c:a/b').suffix, '')
+        self.assertEqual(P('c:/a/b').suffix, '')
+        self.assertEqual(P('c:a/b.py').suffix, '.py')
+        self.assertEqual(P('c:/a/b.py').suffix, '.py')
+        self.assertEqual(P('c:a/.hgrc').suffix, '')
+        self.assertEqual(P('c:/a/.hgrc').suffix, '')
+        self.assertEqual(P('c:a/.hg.rc').suffix, '.rc')
+        self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc')
+        self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz')
+        self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz')
+        self.assertEqual(P('c:a/trailing.dot.').suffix, '.')
+        self.assertEqual(P('c:/a/trailing.dot.').suffix, '.')
+        self.assertEqual(P('//My.py/Share.php').suffix, '')
+        self.assertEqual(P('//My.py/Share.php/a/b').suffix, '')
+
+    def test_suffixes(self):
+        P = self.cls
+        self.assertEqual(P('c:').suffixes, [])
+        self.assertEqual(P('c:/').suffixes, [])
+        self.assertEqual(P('c:a/b').suffixes, [])
+        self.assertEqual(P('c:/a/b').suffixes, [])
+        self.assertEqual(P('c:a/b.py').suffixes, ['.py'])
+        self.assertEqual(P('c:/a/b.py').suffixes, ['.py'])
+        self.assertEqual(P('c:a/.hgrc').suffixes, [])
+        self.assertEqual(P('c:/a/.hgrc').suffixes, [])
+        self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc'])
+        self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc'])
+        self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz'])
+        self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz'])
+        self.assertEqual(P('//My.py/Share.php').suffixes, [])
+        self.assertEqual(P('//My.py/Share.php/a/b').suffixes, [])
+        self.assertEqual(P('c:a/trailing.dot.').suffixes, ['.dot', '.'])
+        self.assertEqual(P('c:/a/trailing.dot.').suffixes, ['.dot', '.'])
+
+    def test_with_name(self):
+        P = self.cls
+        self.assertEqual(P(r'c:a\b').with_name('d.xml'), P(r'c:a\d.xml'))
+        self.assertEqual(P(r'c:\a\b').with_name('d.xml'), P(r'c:\a\d.xml'))
+        self.assertEqual(P(r'c:a\Dot ending.').with_name('d.xml'), 
P(r'c:a\d.xml'))
+        self.assertEqual(P(r'c:\a\Dot ending.').with_name('d.xml'), 
P(r'c:\a\d.xml'))
+        self.assertRaises(ValueError, P(r'c:a\b').with_name, r'd:\e')
+        self.assertRaises(ValueError, P(r'c:a\b').with_name, r'\\My\Share')
+
+    def test_with_stem(self):
+        P = self.cls
+        self.assertEqual(P('c:a/b').with_stem('d'), P('c:a/d'))
+        self.assertEqual(P('c:/a/b').with_stem('d'), P('c:/a/d'))
+        self.assertEqual(P('c:a/Dot ending.').with_stem('d'), P('c:a/d.'))
+        self.assertEqual(P('c:/a/Dot ending.').with_stem('d'), P('c:/a/d.'))
+        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_suffix(self):
+        P = self.cls
+        self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz'))
+        self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz'))
+        self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz'))
+        self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz'))
+        # 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('//My/Share').with_suffix, '.gz')
+        # Invalid suffix.
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, '/')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d')
+        self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d')
+        self.assertRaises(TypeError, P('c:a/b').with_suffix, None)
+
+
+class LexicalWindowsPathJoinTest(JoinTestBase, unittest.TestCase):
+    cls = LexicalWindowsPath
+
+
+class PureWindowsPathJoinTest(JoinTestBase, unittest.TestCase):
+    cls = PureWindowsPath
+
+
+if os.name == 'nt':
+    class WindowsPathJoinTest(JoinTestBase, unittest.TestCase):
+        cls = WindowsPath
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Lib/test/test_pathlib/test_pathlib.py 
b/Lib/test/test_pathlib/test_pathlib.py
index 1996bbb65a304b..aff155cf1100bb 100644
--- a/Lib/test/test_pathlib/test_pathlib.py
+++ b/Lib/test/test_pathlib/test_pathlib.py
@@ -411,6 +411,18 @@ def test_stem_empty(self):
         self.assertEqual(P('').stem, '')
         self.assertEqual(P('.').stem, '')
 
+    @needs_windows
+    def test_with_name_windows(self):
+        P = self.cls
+        self.assertRaises(ValueError, P(r'c:').with_name, 'd.xml')
+        self.assertRaises(ValueError, P(r'c:\\').with_name, 'd.xml')
+        self.assertRaises(ValueError, P(r'\\My\Share').with_name, 'd.xml')
+        # NTFS alternate data streams
+        self.assertEqual(str(P('a').with_name('d:')), '.\\d:')
+        self.assertEqual(str(P('a').with_name('d:e')), '.\\d:e')
+        self.assertEqual(P(r'c:a\b').with_name('d:'), P(r'c:a\d:'))
+        self.assertEqual(P(r'c:a\b').with_name('d:e'), P(r'c:a\d:e'))
+
     def test_with_name_empty(self):
         P = self.cls
         self.assertRaises(ValueError, P('').with_name, 'd.xml')
@@ -419,6 +431,18 @@ def test_with_name_empty(self):
         self.assertRaises(ValueError, P('a/b').with_name, '')
         self.assertRaises(ValueError, P('a/b').with_name, '.')
 
+    @needs_windows
+    def test_with_stem_windows(self):
+        P = self.cls
+        self.assertRaises(ValueError, P('c:').with_stem, 'd')
+        self.assertRaises(ValueError, P('c:/').with_stem, 'd')
+        self.assertRaises(ValueError, P('//My/Share').with_stem, 'd')
+        # NTFS alternate data streams
+        self.assertEqual(str(P('a').with_stem('d:')), '.\\d:')
+        self.assertEqual(str(P('a').with_stem('d:e')), '.\\d:e')
+        self.assertEqual(P('c:a/b').with_stem('d:'), P('c:a/d:'))
+        self.assertEqual(P('c:a/b').with_stem('d:e'), P('c:a/d:e'))
+
     def test_with_stem_empty(self):
         P = self.cls
         self.assertRaises(ValueError, P('').with_stem, 'd')
diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py 
b/Lib/test/test_pathlib/test_pathlib_abc.py
index 779c8a60bece82..a93af961b503a1 100644
--- a/Lib/test/test_pathlib/test_pathlib_abc.py
+++ b/Lib/test/test_pathlib/test_pathlib_abc.py
@@ -108,70 +108,6 @@ def test_str_subclass_windows(self):
         self._check_str_subclass('\\\\some\\share\\a')
         self._check_str_subclass('\\\\some\\share\\a\\b.txt')
 
-    @needs_windows
-    def test_join_windows(self):
-        P = self.cls
-        p = P('C:/a/b')
-        pp = p.joinpath('x/y')
-        self.assertEqual(pp, P('C:/a/b/x/y'))
-        pp = p.joinpath('/x/y')
-        self.assertEqual(pp, P('C:/x/y'))
-        # Joining with a different drive => the first path is ignored, even
-        # if the second path is relative.
-        pp = p.joinpath('D:x/y')
-        self.assertEqual(pp, P('D:x/y'))
-        pp = p.joinpath('D:/x/y')
-        self.assertEqual(pp, P('D:/x/y'))
-        pp = p.joinpath('//host/share/x/y')
-        self.assertEqual(pp, P('//host/share/x/y'))
-        # Joining with the same drive => the first path is appended to if
-        # the second path is relative.
-        pp = p.joinpath('c:x/y')
-        self.assertEqual(pp, P('C:/a/b/x/y'))
-        pp = p.joinpath('c:/x/y')
-        self.assertEqual(pp, P('C:/x/y'))
-        # Joining with files with NTFS data streams => the filename should
-        # not be parsed as a drive letter
-        pp = p.joinpath(P('./d:s'))
-        self.assertEqual(pp, P('C:/a/b/d:s'))
-        pp = p.joinpath(P('./dd:s'))
-        self.assertEqual(pp, P('C:/a/b/dd:s'))
-        pp = p.joinpath(P('E:d:s'))
-        self.assertEqual(pp, P('E:d:s'))
-        # Joining onto a UNC path with no root
-        pp = P('//').joinpath('server')
-        self.assertEqual(pp, P('//server'))
-        pp = P('//server').joinpath('share')
-        self.assertEqual(pp, P('//server/share'))
-        pp = P('//./BootPartition').joinpath('Windows')
-        self.assertEqual(pp, P('//./BootPartition/Windows'))
-
-    @needs_windows
-    def test_div_windows(self):
-        # Basically the same as joinpath().
-        P = self.cls
-        p = P('C:/a/b')
-        self.assertEqual(p / 'x/y', P('C:/a/b/x/y'))
-        self.assertEqual(p / 'x' / 'y', P('C:/a/b/x/y'))
-        self.assertEqual(p / '/x/y', P('C:/x/y'))
-        self.assertEqual(p / '/x' / 'y', P('C:/x/y'))
-        # Joining with a different drive => the first path is ignored, even
-        # if the second path is relative.
-        self.assertEqual(p / 'D:x/y', P('D:x/y'))
-        self.assertEqual(p / 'D:' / 'x/y', P('D:x/y'))
-        self.assertEqual(p / 'D:/x/y', P('D:/x/y'))
-        self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y'))
-        self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y'))
-        # Joining with the same drive => the first path is appended to if
-        # the second path is relative.
-        self.assertEqual(p / 'c:x/y', P('C:/a/b/x/y'))
-        self.assertEqual(p / 'c:/x/y', P('C:/x/y'))
-        # Joining with files with NTFS data streams => the filename should
-        # not be parsed as a drive letter
-        self.assertEqual(p / P('./d:s'), P('C:/a/b/d:s'))
-        self.assertEqual(p / P('./dd:s'), P('C:/a/b/dd:s'))
-        self.assertEqual(p / P('E:d:s'), P('E:d:s'))
-
     def _check_str(self, expected, args):
         p = self.cls(*args)
         self.assertEqual(str(p), expected.replace('/', self.sep))
@@ -195,221 +131,6 @@ def test_str_windows(self):
         p = self.cls('//a/b/c/d')
         self.assertEqual(str(p), '\\\\a\\b\\c\\d')
 
-    @needs_windows
-    def test_parts_windows(self):
-        P = self.cls
-        p = P('c:a/b')
-        parts = p.parts
-        self.assertEqual(parts, ('c:', 'a', 'b'))
-        p = P('c:/a/b')
-        parts = p.parts
-        self.assertEqual(parts, ('c:\\', 'a', 'b'))
-        p = P('//a/b/c/d')
-        parts = p.parts
-        self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd'))
-
-    @needs_windows
-    def test_parent_windows(self):
-        # Anchored
-        P = self.cls
-        p = P('z:a/b/c')
-        self.assertEqual(p.parent, P('z:a/b'))
-        self.assertEqual(p.parent.parent, P('z:a'))
-        self.assertEqual(p.parent.parent.parent, P('z:'))
-        self.assertEqual(p.parent.parent.parent.parent, P('z:'))
-        p = P('z:/a/b/c')
-        self.assertEqual(p.parent, P('z:/a/b'))
-        self.assertEqual(p.parent.parent, P('z:/a'))
-        self.assertEqual(p.parent.parent.parent, P('z:/'))
-        self.assertEqual(p.parent.parent.parent.parent, P('z:/'))
-        p = P('//a/b/c/d')
-        self.assertEqual(p.parent, P('//a/b/c'))
-        self.assertEqual(p.parent.parent, P('//a/b'))
-        self.assertEqual(p.parent.parent.parent, P('//a/b'))
-
-    @needs_windows
-    def test_parents_windows(self):
-        # Anchored
-        P = self.cls
-        p = P('z:a/b/')
-        par = p.parents
-        self.assertEqual(len(par), 2)
-        self.assertEqual(par[0], P('z:a'))
-        self.assertEqual(par[1], P('z:'))
-        self.assertEqual(par[0:1], (P('z:a'),))
-        self.assertEqual(par[:-1], (P('z:a'),))
-        self.assertEqual(par[:2], (P('z:a'), P('z:')))
-        self.assertEqual(par[1:], (P('z:'),))
-        self.assertEqual(par[::2], (P('z:a'),))
-        self.assertEqual(par[::-1], (P('z:'), P('z:a')))
-        self.assertEqual(list(par), [P('z:a'), P('z:')])
-        with self.assertRaises(IndexError):
-            par[2]
-        p = P('z:/a/b/')
-        par = p.parents
-        self.assertEqual(len(par), 2)
-        self.assertEqual(par[0], P('z:/a'))
-        self.assertEqual(par[1], P('z:/'))
-        self.assertEqual(par[0:1], (P('z:/a'),))
-        self.assertEqual(par[0:-1], (P('z:/a'),))
-        self.assertEqual(par[:2], (P('z:/a'), P('z:/')))
-        self.assertEqual(par[1:], (P('z:/'),))
-        self.assertEqual(par[::2], (P('z:/a'),))
-        self.assertEqual(par[::-1], (P('z:/'), P('z:/a'),))
-        self.assertEqual(list(par), [P('z:/a'), P('z:/')])
-        with self.assertRaises(IndexError):
-            par[2]
-        p = P('//a/b/c/d')
-        par = p.parents
-        self.assertEqual(len(par), 2)
-        self.assertEqual(par[0], P('//a/b/c'))
-        self.assertEqual(par[1], P('//a/b'))
-        self.assertEqual(par[0:1], (P('//a/b/c'),))
-        self.assertEqual(par[0:-1], (P('//a/b/c'),))
-        self.assertEqual(par[:2], (P('//a/b/c'), P('//a/b')))
-        self.assertEqual(par[1:], (P('//a/b'),))
-        self.assertEqual(par[::2], (P('//a/b/c'),))
-        self.assertEqual(par[::-1], (P('//a/b'), P('//a/b/c')))
-        self.assertEqual(list(par), [P('//a/b/c'), P('//a/b')])
-        with self.assertRaises(IndexError):
-            par[2]
-
-    @needs_windows
-    def test_anchor_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:').anchor, 'c:')
-        self.assertEqual(P('c:a/b').anchor, 'c:')
-        self.assertEqual(P('c:/').anchor, 'c:\\')
-        self.assertEqual(P('c:/a/b/').anchor, 'c:\\')
-        self.assertEqual(P('//a/b').anchor, '\\\\a\\b\\')
-        self.assertEqual(P('//a/b/').anchor, '\\\\a\\b\\')
-        self.assertEqual(P('//a/b/c/d').anchor, '\\\\a\\b\\')
-
-    @needs_windows
-    def test_name_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:').name, '')
-        self.assertEqual(P('c:/').name, '')
-        self.assertEqual(P('c:a/b').name, 'b')
-        self.assertEqual(P('c:/a/b').name, 'b')
-        self.assertEqual(P('c:a/b.py').name, 'b.py')
-        self.assertEqual(P('c:/a/b.py').name, 'b.py')
-        self.assertEqual(P('//My.py/Share.php').name, '')
-        self.assertEqual(P('//My.py/Share.php/a/b').name, 'b')
-
-    @needs_windows
-    def test_suffix_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:').suffix, '')
-        self.assertEqual(P('c:/').suffix, '')
-        self.assertEqual(P('c:a/b').suffix, '')
-        self.assertEqual(P('c:/a/b').suffix, '')
-        self.assertEqual(P('c:a/b.py').suffix, '.py')
-        self.assertEqual(P('c:/a/b.py').suffix, '.py')
-        self.assertEqual(P('c:a/.hgrc').suffix, '')
-        self.assertEqual(P('c:/a/.hgrc').suffix, '')
-        self.assertEqual(P('c:a/.hg.rc').suffix, '.rc')
-        self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc')
-        self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz')
-        self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz')
-        self.assertEqual(P('c:a/trailing.dot.').suffix, '.')
-        self.assertEqual(P('c:/a/trailing.dot.').suffix, '.')
-        self.assertEqual(P('//My.py/Share.php').suffix, '')
-        self.assertEqual(P('//My.py/Share.php/a/b').suffix, '')
-
-    @needs_windows
-    def test_suffixes_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:').suffixes, [])
-        self.assertEqual(P('c:/').suffixes, [])
-        self.assertEqual(P('c:a/b').suffixes, [])
-        self.assertEqual(P('c:/a/b').suffixes, [])
-        self.assertEqual(P('c:a/b.py').suffixes, ['.py'])
-        self.assertEqual(P('c:/a/b.py').suffixes, ['.py'])
-        self.assertEqual(P('c:a/.hgrc').suffixes, [])
-        self.assertEqual(P('c:/a/.hgrc').suffixes, [])
-        self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc'])
-        self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc'])
-        self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz'])
-        self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz'])
-        self.assertEqual(P('//My.py/Share.php').suffixes, [])
-        self.assertEqual(P('//My.py/Share.php/a/b').suffixes, [])
-        self.assertEqual(P('c:a/trailing.dot.').suffixes, ['.dot', '.'])
-        self.assertEqual(P('c:/a/trailing.dot.').suffixes, ['.dot', '.'])
-
-    @needs_windows
-    def test_stem_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:').stem, '')
-        self.assertEqual(P('c:.').stem, '')
-        self.assertEqual(P('c:..').stem, '..')
-        self.assertEqual(P('c:/').stem, '')
-        self.assertEqual(P('c:a/b').stem, 'b')
-        self.assertEqual(P('c:a/b.py').stem, 'b')
-        self.assertEqual(P('c:a/.hgrc').stem, '.hgrc')
-        self.assertEqual(P('c:a/.hg.rc').stem, '.hg')
-        self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar')
-        self.assertEqual(P('c:a/trailing.dot.').stem, 'trailing.dot')
-
-    @needs_windows
-    def test_with_name_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:a/b').with_name('d.xml'), P('c:a/d.xml'))
-        self.assertEqual(P('c:/a/b').with_name('d.xml'), P('c:/a/d.xml'))
-        self.assertEqual(P('c:a/Dot ending.').with_name('d.xml'), 
P('c:a/d.xml'))
-        self.assertEqual(P('c:/a/Dot ending.').with_name('d.xml'), 
P('c:/a/d.xml'))
-        self.assertRaises(ValueError, P('c:').with_name, 'd.xml')
-        self.assertRaises(ValueError, P('c:/').with_name, 'd.xml')
-        self.assertRaises(ValueError, P('//My/Share').with_name, 'd.xml')
-        self.assertEqual(str(P('a').with_name('d:')), '.\\d:')
-        self.assertEqual(str(P('a').with_name('d:e')), '.\\d:e')
-        self.assertEqual(P('c:a/b').with_name('d:'), P('c:a/d:'))
-        self.assertEqual(P('c:a/b').with_name('d:e'), P('c:a/d:e'))
-        self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e')
-        self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share')
-
-    @needs_windows
-    def test_with_stem_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:a/b').with_stem('d'), P('c:a/d'))
-        self.assertEqual(P('c:/a/b').with_stem('d'), P('c:/a/d'))
-        self.assertEqual(P('c:a/Dot ending.').with_stem('d'), P('c:a/d.'))
-        self.assertEqual(P('c:/a/Dot ending.').with_stem('d'), P('c:/a/d.'))
-        self.assertRaises(ValueError, P('c:').with_stem, 'd')
-        self.assertRaises(ValueError, P('c:/').with_stem, 'd')
-        self.assertRaises(ValueError, P('//My/Share').with_stem, 'd')
-        self.assertEqual(str(P('a').with_stem('d:')), '.\\d:')
-        self.assertEqual(str(P('a').with_stem('d:e')), '.\\d:e')
-        self.assertEqual(P('c:a/b').with_stem('d:'), P('c:a/d:'))
-        self.assertEqual(P('c:a/b').with_stem('d:e'), P('c:a/d:e'))
-        self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:/e')
-        self.assertRaises(ValueError, P('c:a/b').with_stem, '//My/Share')
-
-    @needs_windows
-    def test_with_suffix_windows(self):
-        P = self.cls
-        self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz'))
-        self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz'))
-        self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz'))
-        self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz'))
-        # 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.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz')
-        # Invalid suffix.
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, '/')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d')
-        self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d')
-        self.assertRaises(TypeError, P('c:a/b').with_suffix, None)
 
 #
 # Tests for the virtual classes.

_______________________________________________
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