diff -r c7a700132018 Lib/os.py --- a/Lib/os.py Thu Mar 12 10:32:20 2015 +0100 +++ b/Lib/os.py Thu Mar 12 10:39:19 2015 +0100 @@ -354,7 +354,7 @@ def walk(top, topdown=True, onerror=None dirs = [] nondirs = [] - symlinks = set() + symlinks = {} # We may not have read permission for top, in which case we can't # get a list of the files the directory contains. os.walk @@ -379,13 +379,12 @@ def walk(top, topdown=True, onerror=None if is_dir and not followlinks: try: - if entry.is_symlink(): - symlinks.add(entry.name) + symlinks[entry.name] = entry.is_symlink() except OSError: # If is_symlink() raises an OSError, consider that the # entry is not a symbolik link, same behaviour than # os.path.islink(). - pass + symlinks[entry.name] = False except OSError as error: # scandir() or iterating into scandir() iterator raised an OSError if onerror is not None: @@ -398,7 +397,15 @@ def walk(top, topdown=True, onerror=None # Recurse into sub-directories for name in dirs: - if followlinks or name not in symlinks: + if followlinks: + walk_into = True + else: + try: + walk_into = not symlinks[name] + except KeyError: + # directory added after dirs was created + walk_into = not path.islink(path.join(top, name)) + if walk_into: new_path = path.join(top, name) yield from walk(new_path, topdown, onerror, followlinks) diff -r c7a700132018 Lib/test/test_os.py --- a/Lib/test/test_os.py Thu Mar 12 10:32:20 2015 +0100 +++ b/Lib/test/test_os.py Thu Mar 12 10:39:19 2015 +0100 @@ -884,6 +884,41 @@ class WalkTests(unittest.TestCase): else: self.fail("Didn't follow symlink with followlinks=True") + def check_add_dir(self, create_symlink, follow_symlinks): + if create_symlink: + dir2 = os.path.realpath(support.TESTFN + "2") + os.mkdir(dir2) + self.addCleanup(os.rmdir, dir2) + + newdir = os.path.join(self.walk_path, "newdir") + + walk_it = self.walk(self.walk_path, topdown=True, + follow_symlinks=follow_symlinks) + seen = False + for root, dirs, files in walk_it: + if root == self.walk_path: + if create_symlink: + os.symlink(dir2, newdir) + else: + os.mkdir(newdir) + dirs.append(os.path.basename(newdir)) + elif root == newdir: + seen = True + break + self.assertEqual(seen, follow_symlinks or not create_symlink) + + def test_add_dir(self): + self.check_add_dir(create_symlink=False, follow_symlinks=False) + + def test_add_dir_symlink(self): + self.check_add_dir(create_symlink=True, follow_symlinks=False) + + def test_add_dir_follow(self): + self.check_add_dir(create_symlink=False, follow_symlinks=True) + + def test_add_dir_symlink_follow(self): + self.check_add_dir(create_symlink=True, follow_symlinks=True) + def tearDown(self): # Tear everything down. This is a decent use for bottom-up on # Windows, which doesn't have a recursive delete command. The