]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-119169: Simplify `os.walk()` exception handling (#121435)
authorBarney Gale <barney.gale@gmail.com>
Mon, 8 Jul 2024 16:41:01 +0000 (17:41 +0100)
committerGitHub <noreply@github.com>
Mon, 8 Jul 2024 16:41:01 +0000 (17:41 +0100)
Handle errors from `os.scandir()` and `ScandirIterator` similarly, which
lets us loop over directory entries with `for`.

Lib/os.py
Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst [new file with mode: 0644]

index 4b48afb040e565346e130f9be8232107151e6e47..aaa758d955fe4c2a10ef8853524551d48f28e87f 100644 (file)
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -373,61 +373,45 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
         # minor reason when (say) a thousand readable directories are still
         # left to visit.
         try:
-            scandir_it = scandir(top)
+            with scandir(top) as entries:
+                for entry in entries:
+                    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()
+                    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
+
+                    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)
             continue
 
-        cont = False
-        with scandir_it:
-            while True:
-                try:
-                    try:
-                        entry = next(scandir_it)
-                    except StopIteration:
-                        break
-                except OSError as error:
-                    if onerror is not None:
-                        onerror(error)
-                    cont = True
-                    break
-
-                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()
-                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
-
-                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)
-        if cont:
-            continue
-
         if topdown:
             # Yield before sub-directory traversal if going top down
             yield top, dirs, nondirs
diff --git a/Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst b/Misc/NEWS.d/next/Library/2024-07-06-16-08-39.gh-issue-119169.o0YymL.rst
new file mode 100644 (file)
index 0000000..5d9b50d
--- /dev/null
@@ -0,0 +1 @@
+Slightly speed up :func:`os.walk` by simplifying exception handling.