diff --git a/Lib/os.py b/Lib/os.py index aaa758d955fe4c..92d8b9940b0a81 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -365,7 +365,9 @@ def walk(top, topdown=True, onerror=None, followlinks=False): dirs = [] nondirs = [] - walk_dirs = [] + if not topdown: + # Yield after sub-directory traversal if going bottom up + stack.append((top, dirs, nondirs)) # We may not have read permission for top, in which case we can't # get a list of the files the directory contains. @@ -375,41 +377,34 @@ def walk(top, topdown=True, onerror=None, followlinks=False): try: with scandir(top) as entries: for entry in entries: + is_dir = False try: if followlinks is _walk_symlinks_as_files: is_dir = entry.is_dir(follow_symlinks=False) and not entry.is_junction() else: is_dir = entry.is_dir() + if is_dir and not topdown: + # Exclude symlink if followlinks is False + if followlinks or not entry.is_symlink(): + # Traverse into sub-directory + stack.append(entry.path) except OSError: # If is_dir() raises an OSError, consider the entry not to # be a directory, same behaviour as os.path.isdir(). - is_dir = False + pass if is_dir: dirs.append(entry.name) else: nondirs.append(entry.name) - if not topdown and is_dir: - # Bottom-up: traverse into sub-directory, but exclude - # symlinks to directories if followlinks is False - if followlinks: - walk_into = True - else: - try: - is_symlink = entry.is_symlink() - except OSError: - # If is_symlink() raises an OSError, consider the - # entry not to be a symbolic link, same behaviour - # as os.path.islink(). - is_symlink = False - walk_into = not is_symlink - - if walk_into: - walk_dirs.append(entry.path) except OSError as error: if onerror is not None: onerror(error) + if not topdown: + # Undo additions to stack. + while not isinstance(stack.pop(), tuple): + pass continue if topdown: @@ -424,12 +419,6 @@ def walk(top, topdown=True, onerror=None, followlinks=False): # above. if followlinks or not islink(new_path): stack.append(new_path) - else: - # Yield after sub-directory traversal if going bottom up - stack.append((top, dirs, nondirs)) - # Traverse into sub-directories - for new_path in reversed(walk_dirs): - stack.append(new_path) __all__.append("walk") diff --git a/Misc/NEWS.d/next/Library/2024-05-19-20-13-09.gh-issue-119169.CuE7q0.rst b/Misc/NEWS.d/next/Library/2024-05-19-20-13-09.gh-issue-119169.CuE7q0.rst new file mode 100644 index 00000000000000..5d9b50d452a9cd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-19-20-13-09.gh-issue-119169.CuE7q0.rst @@ -0,0 +1 @@ +Slightly speed up :func:`os.walk` by simplifying exception handling.