Skip to content

GH-119169: Speed up os.walk(topdown=False) #119186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
39 changes: 14 additions & 25 deletions Lib/os.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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:
Expand All @@ -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")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Slightly speed up :func:`os.walk` by simplifying exception handling.
Loading