]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] GH-119169: Implement `pathlib.Path.walk()` using `os.walk()` (GH-119573) ...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 29 May 2024 21:24:42 +0000 (23:24 +0200)
committerGitHub <noreply@github.com>
Wed, 29 May 2024 21:24:42 +0000 (21:24 +0000)
GH-119169: Implement `pathlib.Path.walk()` using `os.walk()` (GH-119573)

For silly reasons, pathlib's generic implementation of `walk()` currently
resides in `glob._Globber`. This commit moves it into
`pathlib._abc.PathBase.walk()` where it really belongs, and makes
`pathlib.Path.walk()` call `os.walk()`.
(cherry picked from commit 7ff61f51b6f75315291419269295a8ac3933397b)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
Lib/glob.py
Lib/pathlib/_abc.py
Lib/pathlib/_local.py

index 6088de00a67a99cbb68fa84feeba5d23f5a75aff..c506e0e2157c512a6f0e88e59157816d888d5867 100644 (file)
@@ -523,43 +523,6 @@ class _Globber:
             except OSError:
                 pass
 
-    @classmethod
-    def walk(cls, root, top_down, on_error, follow_symlinks):
-        """Walk the directory tree from the given root, similar to os.walk().
-        """
-        paths = [root]
-        while paths:
-            path = paths.pop()
-            if isinstance(path, tuple):
-                yield path
-                continue
-            try:
-                with cls.scandir(path) as scandir_it:
-                    dirnames = []
-                    filenames = []
-                    if not top_down:
-                        paths.append((path, dirnames, filenames))
-                    for entry in scandir_it:
-                        name = entry.name
-                        try:
-                            if entry.is_dir(follow_symlinks=follow_symlinks):
-                                if not top_down:
-                                    paths.append(cls.parse_entry(entry))
-                                dirnames.append(name)
-                            else:
-                                filenames.append(name)
-                        except OSError:
-                            filenames.append(name)
-            except OSError as error:
-                if on_error is not None:
-                    on_error(error)
-            else:
-                if top_down:
-                    yield path, dirnames, filenames
-                    if dirnames:
-                        prefix = cls.add_slash(path)
-                        paths += [cls.concat_path(prefix, d) for d in reversed(dirnames)]
-
 
 class _StringGlobber(_Globber):
     lstat = staticmethod(os.lstat)
index 90684526422d65f2d72f5cbdbf5686015f1f2d05..4d24146aa53f3b04ee290788d1b2feb5defd65dc 100644 (file)
@@ -696,7 +696,37 @@ class PathBase(PurePathBase):
 
     def walk(self, top_down=True, on_error=None, follow_symlinks=False):
         """Walk the directory tree from this directory, similar to os.walk()."""
-        return self._globber.walk(self, top_down, on_error, follow_symlinks)
+        paths = [self]
+        while paths:
+            path = paths.pop()
+            if isinstance(path, tuple):
+                yield path
+                continue
+            dirnames = []
+            filenames = []
+            if not top_down:
+                paths.append((path, dirnames, filenames))
+            try:
+                for child in path.iterdir():
+                    try:
+                        if child.is_dir(follow_symlinks=follow_symlinks):
+                            if not top_down:
+                                paths.append(child)
+                            dirnames.append(child.name)
+                        else:
+                            filenames.append(child.name)
+                    except OSError:
+                        filenames.append(child.name)
+            except OSError as error:
+                if on_error is not None:
+                    on_error(error)
+                if not top_down:
+                    while not isinstance(paths.pop(), tuple):
+                        pass
+                continue
+            if top_down:
+                yield path, dirnames, filenames
+                paths += [path.joinpath(d) for d in reversed(dirnames)]
 
     def absolute(self):
         """Return an absolute version of this path
index b1e678aceb9ce8d60439951f24206befe5886150..fbc8db78b86e61a6d43a4914c67c6cb0dbe4c34e 100644 (file)
@@ -623,7 +623,9 @@ class Path(PathBase, PurePath):
         """Walk the directory tree from this directory, similar to os.walk()."""
         sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
         root_dir = str(self)
-        results = self._globber.walk(root_dir, top_down, on_error, follow_symlinks)
+        if not follow_symlinks:
+            follow_symlinks = os._walk_symlinks_as_files
+        results = os.walk(root_dir, top_down, on_error, follow_symlinks)
         for path_str, dirnames, filenames in results:
             if root_dir == '.':
                 path_str = path_str[2:]