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