Skip to content

Commit

Permalink
pythonGH-115060: Speed up pathlib.Path.glob() by omitting initial `…
Browse files Browse the repository at this point in the history
…stat()`

Since 6258844, paths that might not exist can be fed into pathlib's
globbing implementation, which will call `os.scandir()` / `os.lstat()` only
when strictly necessary. This allows us to drop an initial `self.is_dir()`
call, which saves a `stat()`.
  • Loading branch information
barneygale committed Apr 13, 2024
1 parent 30f0643 commit 3d1bbe1
Show file tree
Hide file tree
Showing 4 changed files with 6 additions and 9 deletions.
4 changes: 1 addition & 3 deletions Doc/library/pathlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1004,9 +1004,7 @@ call fails (for example because the path doesn't exist).
.. seealso::
:ref:`pathlib-pattern-language` documentation.

This method calls :meth:`Path.is_dir` on the top-level directory and
propagates any :exc:`OSError` exception that is raised. Subsequent
:exc:`OSError` exceptions from scanning directories are suppressed.
This method suppresses any :exc:`OSError` exceptions raised while scanning.

By default, or when the *case_sensitive* keyword-only argument is set to
``None``, this method matches paths using platform-specific casing rules:
Expand Down
4 changes: 1 addition & 3 deletions Lib/pathlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,9 @@ def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=False):
if raw[-1] in (self.parser.sep, self.parser.altsep):
# GH-65238: pathlib doesn't preserve trailing slash. Add it back.
parts.append('')
if not self.is_dir():
return iter([])
select = self._glob_selector(parts[::-1], case_sensitive, recurse_symlinks)
root = str(self)
paths = select(root, exists=True)
paths = select(root)

# Normalize results
if root == '.':
Expand Down
4 changes: 1 addition & 3 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,10 +705,8 @@ def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=True):
anchor, parts = pattern._stack
if anchor:
raise NotImplementedError("Non-relative patterns are unsupported")
if not self.is_dir():
return iter([])
select = self._glob_selector(parts, case_sensitive, recurse_symlinks)
return select(self, exists=True)
return select(self)

def rglob(self, pattern, *, case_sensitive=None, recurse_symlinks=True):
"""Recursively yield all existing files (of any kind, including
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Speed up :meth:`pathlib.Path.glob` my omitting an initial
:meth:`~pathlib.Path.is_dir` call. As a result of this change,
:meth:`~pathlib.Path.glob` can no longer raise :exc:`OSError`.

0 comments on commit 3d1bbe1

Please sign in to comment.