Skip to content

Commit

Permalink
GH-125413: pathlib ABCs: use scandir() to speed up walk() (#126262)
Browse files Browse the repository at this point in the history
Use the new `PathBase.scandir()` method in `PathBase.walk()`, which greatly
reduces the number of `PathBase.stat()` calls needed when walking.

There are no user-facing changes, because the pathlib ABCs are still
private and `Path.walk()` doesn't use the implementation in its superclass.
  • Loading branch information
barneygale authored Nov 1, 2024
1 parent 68a51e0 commit 37651cf
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 12 deletions.
22 changes: 12 additions & 10 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -693,16 +693,18 @@ def walk(self, top_down=True, on_error=None, follow_symlinks=False):
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)
with path.scandir() as entries:
for entry in entries:
name = entry.name
try:
if entry.is_dir(follow_symlinks=follow_symlinks):
if not top_down:
paths.append(path.joinpath(name))
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)
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_pathlib/test_pathlib_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1951,7 +1951,7 @@ def ordered_walk(path):
if self.can_symlink:
# Add some symlinks
source.joinpath('linkC').symlink_to('fileC')
source.joinpath('linkD').symlink_to('dirD')
source.joinpath('linkD').symlink_to('dirD', target_is_directory=True)

# Perform the copy
target = base / 'copyC'
Expand Down Expand Up @@ -2969,7 +2969,7 @@ def setUpWalk(self):
f.write(f"I'm {path} and proud of it. Blame test_pathlib.\n")

if self.can_symlink:
self.link_path.symlink_to(t2_path)
self.link_path.symlink_to(t2_path, target_is_directory=True)
broken_link_path.symlink_to('broken')
broken_link2_path.symlink_to(self.cls('tmp3', 'broken'))
self.sub2_tree = (self.sub2_path, [], ["broken_link", "broken_link2", "link", "tmp3"])
Expand Down

0 comments on commit 37651cf

Please sign in to comment.