diff -r d8e49a2795e7 Lib/os.py --- a/Lib/os.py Sat Mar 07 18:14:07 2015 -0800 +++ b/Lib/os.py Sat Mar 07 22:10:20 2015 -0500 @@ -323,7 +323,7 @@ the value of topdown, the list of subdirectories is retrieved before the tuples for the directory and its subdirectories are generated. - By default errors from the os.listdir() call are ignored. If + By default errors from the os.scandir() call are ignored. If optional arg 'onerror' is specified, it should be a function; it will be called with one argument, an OSError instance. It can report the error to continue with the walk, or raise the exception @@ -351,36 +351,43 @@ dirs.remove('CVS') # don't visit CVS directories """ - - islink, join, isdir = path.islink, path.join, path.isdir - - # 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 - # always suppressed the exception then, rather than blow up for a - # minor reason when (say) a thousand readable directories are still - # left to visit. That logic is copied here. + # Determine which are files and which are directories + dirs = [] + nondirs = [] + symlinks = set() try: - # Note that listdir is global in this module due - # to earlier import-*. - names = listdir(top) - except OSError as err: + for entry in scandir(top): + try: + if entry.is_dir(): + dirs.append(entry.name) + else: + nondirs.append(entry.name) + except OSError: + # os.walk() includes paths where is_dir() raises + # OSError in the nondirs list + nondirs.append(entry.name) + try: + if entry.is_symlink(): + symlinks.add(entry.name) + except OSError: + pass + except OSError as error: if onerror is not None: - onerror(err) + onerror(error) return - dirs, nondirs = [], [] - for name in names: - if isdir(join(top, name)): - dirs.append(name) - else: - nondirs.append(name) - + # Yield before recursion if going top down if topdown: yield top, dirs, nondirs + + # Recurse into sub-directories, following symbolic links if + # "followlinks" is True for name in dirs: - new_path = join(top, name) - if followlinks or not islink(new_path): + if followlinks or name not in symlinks: + new_path = path.join(top, name) yield from walk(new_path, topdown, onerror, followlinks) + + # Yield after recursion if going bottom up if not topdown: yield top, dirs, nondirs