summaryrefslogtreecommitdiffstats
path: root/Lib/glob.py
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2024-04-11 00:26:53 (GMT)
committerGitHub <noreply@github.com>2024-04-11 00:26:53 (GMT)
commit0cc71bde001950d3634c235e2b0d24cda6ce7dce (patch)
treeb7cdb33ccd2c1d0f793a8c3b60f590d9af8c0e0e /Lib/glob.py
parent6258844c27e3b5a43816e7c559089a5fe0a47123 (diff)
downloadcpython-0cc71bde001950d3634c235e2b0d24cda6ce7dce.zip
cpython-0cc71bde001950d3634c235e2b0d24cda6ce7dce.tar.gz
cpython-0cc71bde001950d3634c235e2b0d24cda6ce7dce.tar.bz2
GH-117586: Speed up `pathlib.Path.walk()` by working with strings (#117726)
Move `pathlib.Path.walk()` implementation into `glob._Globber`. The new `glob._Globber.walk()` classmethod works with strings internally, which is a little faster than generating `Path` objects and keeping them normalized. The `pathlib.Path.walk()` method converts the strings back to path objects. In the private pathlib ABCs, our existing subclass of `_Globber` ensures that `PathBase` instances are used throughout. Follow-up to #117589.
Diffstat (limited to 'Lib/glob.py')
-rw-r--r--Lib/glob.py37
1 files changed, 37 insertions, 0 deletions
diff --git a/Lib/glob.py b/Lib/glob.py
index 62cf039..b1d2681 100644
--- a/Lib/glob.py
+++ b/Lib/glob.py
@@ -498,3 +498,40 @@ class _Globber:
yield path
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)]