From 05c075d629fc81035b438e3b146872dc7799f260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Wed, 7 Mar 2007 11:04:33 +0000 Subject: Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). --- Doc/lib/libposixpath.tex | 7 ++++++- Lib/genericpath.py | 29 +++++++++++++++++++++++++++++ Lib/macpath.py | 14 +++----------- Lib/ntpath.py | 13 +++---------- Lib/posixpath.py | 11 +++-------- Lib/test/test_macpath.py | 2 +- Lib/test/test_ntpath.py | 3 ++- Lib/test/test_posixpath.py | 28 ++++++++++++++++++++-------- Misc/NEWS | 2 ++ 9 files changed, 69 insertions(+), 40 deletions(-) diff --git a/Doc/lib/libposixpath.tex b/Doc/lib/libposixpath.tex index 0b2da66..1dbe32f 100644 --- a/Doc/lib/libposixpath.tex +++ b/Doc/lib/libposixpath.tex @@ -234,7 +234,12 @@ empty string. On systems which do not use drive specifications, Split the pathname \var{path} into a pair \code{(\var{root}, \var{ext})} such that \code{\var{root} + \var{ext} == \var{path}}, and \var{ext} is empty or begins with a period and contains -at most one period. +at most one period. Leading periods on the basename are +ignored; \code{\var{splitext}.('.cshrc')} returns +\code{('.cshrc', '')}. + +\versionchanged[Earlier versions could produce an empty root when +the only period was the first character]{2.6} \end{funcdesc} \begin{funcdesc}{splitunc}{path} diff --git a/Lib/genericpath.py b/Lib/genericpath.py index 1574cef..6d11ec0 100644 --- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -75,3 +75,32 @@ def commonprefix(m): if s1[i] != s2[i]: return s1[:i] return s1[:n] + +# Split a path in root and extension. +# The extension is everything starting at the last dot in the last +# pathname component; the root is everything before that. +# It is always true that root + ext == p. + +# Generic implementation of splitext, to be parametrized with +# the separators +def _splitext(p, sep, altsep, extsep): + """Split the extension from a pathname. + + Extension is everything from the last dot to the end, ignoring + leading dots. Returns "(root, ext)"; ext may be empty.""" + + sepIndex = p.rfind(sep) + if altsep: + altsepIndex = p.rfind(altsep) + sepIndex = max(sepIndex, altsepIndex) + + dotIndex = p.rfind(extsep) + if dotIndex > sepIndex: + # skip all leading dots + filenameIndex = sepIndex + 1 + while filenameIndex < dotIndex: + if p[filenameIndex] != extsep: + return p[:dotIndex], p[dotIndex:] + filenameIndex += 1 + + return p, '' diff --git a/Lib/macpath.py b/Lib/macpath.py index d389d70..f54ffa0 100644 --- a/Lib/macpath.py +++ b/Lib/macpath.py @@ -2,6 +2,7 @@ import os from stat import * +import genericpath from genericpath import * __all__ = ["normcase","isabs","join","splitdrive","split","splitext", @@ -69,17 +70,8 @@ def split(s): def splitext(p): - """Split a path into root and extension. - The extension is everything starting at the last dot in the last - pathname component; the root is everything before that. - It is always true that root + ext == p.""" - - i = p.rfind('.') - if i<=p.rfind(':'): - return p, '' - else: - return p[:i], p[i:] - + return genericpath._splitext(p, sep, altsep, extsep) +splitext.__doc__ = genericpath._splitext.__doc__ def splitdrive(p): """Split a pathname into a drive specification and the rest of the diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 23d5127..2ea3358 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -8,6 +8,7 @@ module as os.path. import os import stat import sys +import genericpath from genericpath import * __all__ = ["normcase","isabs","join","splitdrive","split","splitext", @@ -182,16 +183,8 @@ def split(p): # It is always true that root + ext == p. def splitext(p): - """Split the extension from a pathname. - - Extension is everything from the last dot to the end. - Return (root, ext), either part may be empty.""" - - i = p.rfind('.') - if i<=max(p.rfind('/'), p.rfind('\\')): - return p, '' - else: - return p[:i], p[i:] + return genericpath._splitext(p, sep, altsep, extsep) +splitext.__doc__ = genericpath._splitext.__doc__ # Return the tail (basename) part of a path. diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 1521236..661d8db 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -12,6 +12,7 @@ for manipulation of the pathname component of URLs. import os import stat +import genericpath from genericpath import * __all__ = ["normcase","isabs","join","splitdrive","split","splitext", @@ -88,14 +89,8 @@ def split(p): # It is always true that root + ext == p. def splitext(p): - """Split the extension from a pathname. Extension is everything from the - last dot to the end. Returns "(root, ext)", either part may be empty.""" - i = p.rfind('.') - if i<=p.rfind('/'): - return p, '' - else: - return p[:i], p[i:] - + return genericpath._splitext(p, sep, altsep, extsep) +splitext.__doc__ = genericpath._splitext.__doc__ # Split a pathname into a drive specification and the rest of the # path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. diff --git a/Lib/test/test_macpath.py b/Lib/test/test_macpath.py index 3a3cf04..2449b0a 100644 --- a/Lib/test/test_macpath.py +++ b/Lib/test/test_macpath.py @@ -48,7 +48,7 @@ class MacPathTestCase(unittest.TestCase): splitext = macpath.splitext self.assertEquals(splitext(":foo.ext"), (':foo', '.ext')) self.assertEquals(splitext("foo:foo.ext"), ('foo:foo', '.ext')) - self.assertEquals(splitext(".ext"), ('', '.ext')) + self.assertEquals(splitext(".ext"), ('.ext', '')) self.assertEquals(splitext("foo.ext:foo"), ('foo.ext:foo', '')) self.assertEquals(splitext(":foo.ext:"), (':foo.ext:', '')) self.assertEquals(splitext(""), ('', '')) diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 6bc2a05..da80bc6 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -18,13 +18,14 @@ def tester(fn, wantResult): tester('ntpath.splitext("foo.ext")', ('foo', '.ext')) tester('ntpath.splitext("/foo/foo.ext")', ('/foo/foo', '.ext')) -tester('ntpath.splitext(".ext")', ('', '.ext')) +tester('ntpath.splitext(".ext")', ('.ext', '')) tester('ntpath.splitext("\\foo.ext\\foo")', ('\\foo.ext\\foo', '')) tester('ntpath.splitext("foo.ext\\")', ('foo.ext\\', '')) tester('ntpath.splitext("")', ('', '')) tester('ntpath.splitext("foo.bar.ext")', ('foo.bar', '.ext')) tester('ntpath.splitext("xx/foo.bar.ext")', ('xx/foo.bar', '.ext')) tester('ntpath.splitext("xx\\foo.bar.ext")', ('xx\\foo.bar', '.ext')) +tester('ntpath.splitext("c:a/b\\c.d")', ('c:a/b\\c', '.d')) tester('ntpath.splitdrive("c:\\foo\\bar")', ('c:', '\\foo\\bar')) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py index 20a1fc5..d34c7e2 100644 --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -43,15 +43,27 @@ class PosixPathTest(unittest.TestCase): self.assertRaises(TypeError, posixpath.split) - def test_splitext(self): - self.assertEqual(posixpath.splitext("foo.ext"), ("foo", ".ext")) - self.assertEqual(posixpath.splitext("/foo/foo.ext"), ("/foo/foo", ".ext")) - self.assertEqual(posixpath.splitext(".ext"), ("", ".ext")) - self.assertEqual(posixpath.splitext("/foo.ext/foo"), ("/foo.ext/foo", "")) - self.assertEqual(posixpath.splitext("foo.ext/"), ("foo.ext/", "")) - self.assertEqual(posixpath.splitext(""), ("", "")) - self.assertEqual(posixpath.splitext("foo.bar.ext"), ("foo.bar", ".ext")) + def splitextTest(self, path, filename, ext): + self.assertEqual(posixpath.splitext(path), (filename, ext)) + self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext)) + self.assertEqual(posixpath.splitext("abc/" + path), ("abc/" + filename, ext)) + self.assertEqual(posixpath.splitext("abc.def/" + path), ("abc.def/" + filename, ext)) + self.assertEqual(posixpath.splitext("/abc.def/" + path), ("/abc.def/" + filename, ext)) + self.assertEqual(posixpath.splitext(path + "/"), (filename + ext + "/", "")) + def test_splitext(self): + self.splitextTest("foo.bar", "foo", ".bar") + self.splitextTest("foo.boo.bar", "foo.boo", ".bar") + self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar") + self.splitextTest(".csh.rc", ".csh", ".rc") + self.splitextTest("nodots", "nodots", "") + self.splitextTest(".cshrc", ".cshrc", "") + self.splitextTest("...manydots", "...manydots", "") + self.splitextTest("...manydots.ext", "...manydots", ".ext") + self.splitextTest(".", ".", "") + self.splitextTest("..", "..", "") + self.splitextTest("........", "........", "") + self.splitextTest("", "", "") self.assertRaises(TypeError, posixpath.splitext) def test_isabs(self): diff --git a/Misc/NEWS b/Misc/NEWS index 0452f83..23f6712 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -152,6 +152,8 @@ Core and builtins Library ------- +- Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). + - Patch #787789: allow to pass custom TestRunner instances to unittest's main() function. -- cgit v0.12