Skip to content

Commit

Permalink
pythonGH-113225: Speed up pathlib.Path.iterdir() and glob()
Browse files Browse the repository at this point in the history
Use `os.DirEntry.path` as the string representation of child paths, unless
the parent path is empty, in which case we use the entry `name`.
  • Loading branch information
barneygale committed Dec 17, 2023
1 parent 2f0ec7f commit 461b73d
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 6 deletions.
9 changes: 8 additions & 1 deletion Lib/pathlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,18 @@ def iterdir(self):
The children are yielded in arbitrary order, and the
special entries '.' and '..' are not included.
"""
return (self._make_child_relpath(name) for name in os.listdir(self))
with os.scandir(self) as entries:
return iter([self._make_child_entry(entry) for entry in entries])

def _scandir(self):
return os.scandir(self)

def _make_child_entry(self, entry):
# Transform an entry yielded from _scandir() into a path object.
path = self.with_segments(entry.path)
path._str = entry.name if str(self) == '.' else entry.path
return path

def absolute(self):
"""Return an absolute version of this path
No normalization or symlink resolution is performed.
Expand Down
13 changes: 8 additions & 5 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@ def _select_children(parent_paths, dir_only, follow_symlinks, match):
continue
except OSError:
continue
name = entry.name
if match(name):
yield parent_path._make_child_relpath(name)
if match(entry.name):
yield parent_path._make_child_entry(entry)


def _select_recursive(parent_paths, dir_only, follow_symlinks):
Expand All @@ -114,12 +113,12 @@ def _select_recursive(parent_paths, dir_only, follow_symlinks):
for entry in entries:
try:
if entry.is_dir(follow_symlinks=follow_symlinks):
paths.append(path._make_child_relpath(entry.name))
paths.append(path._make_child_entry(entry))
continue
except OSError:
pass
if not dir_only:
yield path._make_child_relpath(entry.name)
yield path._make_child_entry(entry)


def _select_unique(paths):
Expand Down Expand Up @@ -797,6 +796,10 @@ def _scandir(self):
from contextlib import nullcontext
return nullcontext(self.iterdir())

def _make_child_entry(self, entry):
# Transform an entry yielded from _scandir() into a path object.
return entry

def _make_child_relpath(self, name):
path_str = str(self)
tail = self._tail
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Speed up :meth:`pathlib.Path.iterdir` and :meth:`~pathlib.Path.glob` by
using :attr:`os.DirEntry.path` where possible.

0 comments on commit 461b73d

Please sign in to comment.