Skip to content

Commit db00fee

Browse files
authored
GH-119169: Simplify os.walk() exception handling (#121435)
Handle errors from `os.scandir()` and `ScandirIterator` similarly, which lets us loop over directory entries with `for`.
1 parent 5289550 commit db00fee

File tree

2 files changed

+35
-50
lines changed

2 files changed

+35
-50
lines changed

Lib/os.py

+34-50
Original file line numberDiff line numberDiff line change
@@ -373,61 +373,45 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
373373
# minor reason when (say) a thousand readable directories are still
374374
# left to visit.
375375
try:
376-
scandir_it = scandir(top)
376+
with scandir(top) as entries:
377+
for entry in entries:
378+
try:
379+
if followlinks is _walk_symlinks_as_files:
380+
is_dir = entry.is_dir(follow_symlinks=False) and not entry.is_junction()
381+
else:
382+
is_dir = entry.is_dir()
383+
except OSError:
384+
# If is_dir() raises an OSError, consider the entry not to
385+
# be a directory, same behaviour as os.path.isdir().
386+
is_dir = False
387+
388+
if is_dir:
389+
dirs.append(entry.name)
390+
else:
391+
nondirs.append(entry.name)
392+
393+
if not topdown and is_dir:
394+
# Bottom-up: traverse into sub-directory, but exclude
395+
# symlinks to directories if followlinks is False
396+
if followlinks:
397+
walk_into = True
398+
else:
399+
try:
400+
is_symlink = entry.is_symlink()
401+
except OSError:
402+
# If is_symlink() raises an OSError, consider the
403+
# entry not to be a symbolic link, same behaviour
404+
# as os.path.islink().
405+
is_symlink = False
406+
walk_into = not is_symlink
407+
408+
if walk_into:
409+
walk_dirs.append(entry.path)
377410
except OSError as error:
378411
if onerror is not None:
379412
onerror(error)
380413
continue
381414

382-
cont = False
383-
with scandir_it:
384-
while True:
385-
try:
386-
try:
387-
entry = next(scandir_it)
388-
except StopIteration:
389-
break
390-
except OSError as error:
391-
if onerror is not None:
392-
onerror(error)
393-
cont = True
394-
break
395-
396-
try:
397-
if followlinks is _walk_symlinks_as_files:
398-
is_dir = entry.is_dir(follow_symlinks=False) and not entry.is_junction()
399-
else:
400-
is_dir = entry.is_dir()
401-
except OSError:
402-
# If is_dir() raises an OSError, consider the entry not to
403-
# be a directory, same behaviour as os.path.isdir().
404-
is_dir = False
405-
406-
if is_dir:
407-
dirs.append(entry.name)
408-
else:
409-
nondirs.append(entry.name)
410-
411-
if not topdown and is_dir:
412-
# Bottom-up: traverse into sub-directory, but exclude
413-
# symlinks to directories if followlinks is False
414-
if followlinks:
415-
walk_into = True
416-
else:
417-
try:
418-
is_symlink = entry.is_symlink()
419-
except OSError:
420-
# If is_symlink() raises an OSError, consider the
421-
# entry not to be a symbolic link, same behaviour
422-
# as os.path.islink().
423-
is_symlink = False
424-
walk_into = not is_symlink
425-
426-
if walk_into:
427-
walk_dirs.append(entry.path)
428-
if cont:
429-
continue
430-
431415
if topdown:
432416
# Yield before sub-directory traversal if going top down
433417
yield top, dirs, nondirs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Slightly speed up :func:`os.walk` by simplifying exception handling.

0 commit comments

Comments
 (0)