diff options
author | Barney Gale <barney.gale@gmail.com> | 2024-04-11 00:26:53 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-11 00:26:53 (GMT) |
commit | 0cc71bde001950d3634c235e2b0d24cda6ce7dce (patch) | |
tree | b7cdb33ccd2c1d0f793a8c3b60f590d9af8c0e0e /Lib/glob.py | |
parent | 6258844c27e3b5a43816e7c559089a5fe0a47123 (diff) | |
download | cpython-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.py | 37 |
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)] |