drive. Either part may be empty."""
raise UnsupportedOperation(self._unsupported_msg('splitdrive()'))
+ def splitext(self, path):
+ """Split the path into a pair (root, ext), where *ext* is empty or
+ begins with a begins with a period and contains at most one period,
+ and *root* is everything before the extension."""
+ raise UnsupportedOperation(self._unsupported_msg('splitext()'))
+
def normcase(self, path):
"""Normalize the case of the path."""
raise UnsupportedOperation(self._unsupported_msg('normcase()'))
This includes the leading period. For example: '.txt'
"""
- name = self.name
- i = name.rfind('.')
- if 0 < i < len(name) - 1:
- return name[i:]
- else:
- return ''
+ return self.parser.splitext(self.name)[1]
@property
def suffixes(self):
These include the leading periods. For example: ['.tar', '.gz']
"""
- name = self.name
- if name.endswith('.'):
- return []
- name = name.lstrip('.')
- return ['.' + suffix for suffix in name.split('.')[1:]]
+ split = self.parser.splitext
+ stem, suffix = split(self.name)
+ suffixes = []
+ while suffix:
+ suffixes.append(suffix)
+ stem, suffix = split(stem)
+ return suffixes[::-1]
@property
def stem(self):
"""The final path component, minus its last suffix."""
- name = self.name
- i = name.rfind('.')
- if 0 < i < len(name) - 1:
- return name[:i]
- else:
- return name
+ return self.parser.splitext(self.name)[0]
def with_name(self, name):
"""Return a new path with the file name changed."""
if not stem:
# If the stem is empty, we can't make the suffix non-empty.
raise ValueError(f"{self!r} has an empty name")
- elif suffix and not (suffix.startswith('.') and len(suffix) > 1):
+ elif suffix and not suffix.startswith('.'):
raise ValueError(f"Invalid suffix {suffix!r}")
else:
return self.with_name(stem + suffix)
self.assertRaises(e, m.join, 'foo')
self.assertRaises(e, m.split, 'foo')
self.assertRaises(e, m.splitdrive, 'foo')
+ self.assertRaises(e, m.splitext, 'foo')
self.assertRaises(e, m.normcase, 'foo')
self.assertRaises(e, m.isabs, 'foo')
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/Some name. Ending with a dot.').suffix, '')
- self.assertEqual(P('/a/Some name. Ending with a dot.').suffix, '')
+ 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):
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/Some name. Ending with a dot.').suffix, '')
- self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffix, '')
+ 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, '')
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/Some name. Ending with a dot.').suffixes, [])
- self.assertEqual(P('/a/Some name. Ending with a dot.').suffixes, [])
+ 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):
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/Some name. Ending with a dot.').suffixes, [])
- self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffixes, [])
+ 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('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/Some name. Ending with a dot.').stem,
- 'Some name. Ending with a dot.')
+ 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):
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/Some name. Ending with a dot.').stem,
- 'Some name. Ending with a dot.')
+ 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.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.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
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.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')
# 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):
# 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, '.')
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')