Index: Lib/os.py =================================================================== --- Lib/os.py (revision 41601) +++ Lib/os.py (working copy) @@ -24,6 +24,7 @@ #' import sys +import errno _names = sys.builtin_module_names @@ -147,6 +148,20 @@ # Super directory utilities. # (Inspired by Eric Raymond; the doc strings are mostly his) + +def _splits(name): + """ Split path removing trailing separators and curdir from tail + + >>> splits('a/b/c//.') + 'a/b', 'c' + + """ + head, tail = name, '' + while head and (tail == '' or tail == curdir): + head, tail = path.split(head) + return head, tail + + def makedirs(name, mode=0777): """makedirs(path [, mode=0777]) @@ -155,16 +170,17 @@ just the rightmost) will be created if it does not exist. This is recursive. - """ - head, tail = path.split(name) - if not tail: - head, tail = path.split(head) - if head and tail and not path.exists(head): - makedirs(head, mode) - if tail == curdir: # xxx/newdir/. exists if xxx/newdir exists - return - mkdir(name, mode) + """ + head, tail = _splits(name) + if head: + try: + mkdir(head, mode) + except error, err: + if err.errno != errno.EEXIST: + makedirs(head, mode) + mkdir(path.join(head, tail), mode) + def removedirs(name): """removedirs(path) @@ -177,9 +193,7 @@ """ rmdir(name) - head, tail = path.split(name) - if not tail: - head, tail = path.split(head) + head, tail = _splits(name) while head and tail: try: rmdir(head) Index: Lib/test/test_os.py =================================================================== --- Lib/test/test_os.py (revision 41601) +++ Lib/test/test_os.py (working copy) @@ -5,6 +5,7 @@ import os import unittest import warnings +import shutil from test import test_support warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, __name__) @@ -312,38 +313,70 @@ os.rmdir(join(root, name)) os.rmdir(test_support.TESTFN) -class MakedirTests (unittest.TestCase): + +class SplitsTests(unittest.TestCase): + + def test_empty(self): + self.assertEqual(os._splits(''), ('', '')) + + def test_single_element(self): + self.assertEqual(os._splits('a'), ('', 'a')) + + def test_curdir(self): + self.assertEqual(os._splits(os.curdir), ('', os.curdir)) + + def test_traling_seps(self): + path = os.path.join('a','b') + os.sep + os.sep + self.assertEqual(os._splits(path), ('a', 'b')) + + def test_traling_curdirs(self): + pointless = (os.sep + os.curdir) * 3 + path = os.path.join('a','b') + pointless + self.assertEqual(os._splits(path), ('a', 'b')) + + +class MakedirTests(unittest.TestCase): + + base = test_support.TESTFN + def setUp(self): - os.mkdir(test_support.TESTFN) + os.mkdir(self.base) + + def test_existing(self): + self.failUnlessRaises(OSError, os.makedirs, self.base) - def test_makedir(self): - base = test_support.TESTFN - path = os.path.join(base, 'dir1', 'dir2', 'dir3') - os.makedirs(path) # Should work - path = os.path.join(base, 'dir1', 'dir2', 'dir3', 'dir4') - os.makedirs(path) - - # Try paths with a '.' in them + def test_existing_curdir(self): self.failUnlessRaises(OSError, os.makedirs, os.curdir) - path = os.path.join(base, 'dir1', 'dir2', 'dir3', 'dir4', 'dir5', os.curdir) - os.makedirs(path) - path = os.path.join(base, 'dir1', os.curdir, 'dir2', 'dir3', 'dir4', - 'dir5', 'dir6') - os.makedirs(path) + def test_existing_pardir(self): + self.failUnlessRaises(OSError, os.makedirs, os.pardir) + self.failUnlessRaises(OSError, os.makedirs, + os.path.join(self.base, os.pardir)) + def test_single(self): + self._test(self.base, 'dir1') + def test_multiple(self): + self._test(self.base, 'dir1', 'dir2', 'dir3') + + def test_curdir_leading(self): + self._test(os.curdir, self.base, 'dir1', 'dir2') + def test_curdir_within(self): + self._test(self.base, 'dir1', os.curdir, 'dir2') + + def test_curdir_traling(self): + self._test(self.base, 'dir1', 'dir2', os.curdir) + + def _test(self, *parts): + path = os.path.join(*parts) + os.makedirs(path) + self.failUnless(os.path.isdir(path), + 'directory %s should exists' % path) + def tearDown(self): - path = os.path.join(test_support.TESTFN, 'dir1', 'dir2', 'dir3', - 'dir4', 'dir5', 'dir6') - # If the tests failed, the bottom-most directory ('../dir6') - # may not have been created, so we look for the outermost directory - # that exists. - while not os.path.exists(path) and path != test_support.TESTFN: - path = os.path.dirname(path) + shutil.rmtree(self.base, ignore_errors=True) - os.removedirs(path) class DevNullTests (unittest.TestCase): def test_devnull(self): @@ -370,6 +403,7 @@ StatAttributeTests, EnvironTests, WalkTests, + SplitsTests, MakedirTests, DevNullTests, URandomTests