Skip to content

Commit a7aa7c4

Browse files
[3.13] GH-119169: Implement pathlib.Path.walk() using os.walk() (GH-119573) (#119750)
GH-119169: Implement `pathlib.Path.walk()` using `os.walk()` (GH-119573) For silly reasons, pathlib's generic implementation of `walk()` currently resides in `glob._Globber`. This commit moves it into `pathlib._abc.PathBase.walk()` where it really belongs, and makes `pathlib.Path.walk()` call `os.walk()`. (cherry picked from commit 7ff61f5) Co-authored-by: Barney Gale <barney.gale@gmail.com>
1 parent 061abf8 commit a7aa7c4

File tree

3 files changed

+34
-39
lines changed

3 files changed

+34
-39
lines changed

Lib/glob.py

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -523,43 +523,6 @@ def select_exists(self, path, exists=False):
523523
except OSError:
524524
pass
525525

526-
@classmethod
527-
def walk(cls, root, top_down, on_error, follow_symlinks):
528-
"""Walk the directory tree from the given root, similar to os.walk().
529-
"""
530-
paths = [root]
531-
while paths:
532-
path = paths.pop()
533-
if isinstance(path, tuple):
534-
yield path
535-
continue
536-
try:
537-
with cls.scandir(path) as scandir_it:
538-
dirnames = []
539-
filenames = []
540-
if not top_down:
541-
paths.append((path, dirnames, filenames))
542-
for entry in scandir_it:
543-
name = entry.name
544-
try:
545-
if entry.is_dir(follow_symlinks=follow_symlinks):
546-
if not top_down:
547-
paths.append(cls.parse_entry(entry))
548-
dirnames.append(name)
549-
else:
550-
filenames.append(name)
551-
except OSError:
552-
filenames.append(name)
553-
except OSError as error:
554-
if on_error is not None:
555-
on_error(error)
556-
else:
557-
if top_down:
558-
yield path, dirnames, filenames
559-
if dirnames:
560-
prefix = cls.add_slash(path)
561-
paths += [cls.concat_path(prefix, d) for d in reversed(dirnames)]
562-
563526

564527
class _StringGlobber(_Globber):
565528
lstat = staticmethod(os.lstat)

Lib/pathlib/_abc.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,37 @@ def rglob(self, pattern, *, case_sensitive=None, recurse_symlinks=True):
696696

697697
def walk(self, top_down=True, on_error=None, follow_symlinks=False):
698698
"""Walk the directory tree from this directory, similar to os.walk()."""
699-
return self._globber.walk(self, top_down, on_error, follow_symlinks)
699+
paths = [self]
700+
while paths:
701+
path = paths.pop()
702+
if isinstance(path, tuple):
703+
yield path
704+
continue
705+
dirnames = []
706+
filenames = []
707+
if not top_down:
708+
paths.append((path, dirnames, filenames))
709+
try:
710+
for child in path.iterdir():
711+
try:
712+
if child.is_dir(follow_symlinks=follow_symlinks):
713+
if not top_down:
714+
paths.append(child)
715+
dirnames.append(child.name)
716+
else:
717+
filenames.append(child.name)
718+
except OSError:
719+
filenames.append(child.name)
720+
except OSError as error:
721+
if on_error is not None:
722+
on_error(error)
723+
if not top_down:
724+
while not isinstance(paths.pop(), tuple):
725+
pass
726+
continue
727+
if top_down:
728+
yield path, dirnames, filenames
729+
paths += [path.joinpath(d) for d in reversed(dirnames)]
700730

701731
def absolute(self):
702732
"""Return an absolute version of this path

Lib/pathlib/_local.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,9 @@ def walk(self, top_down=True, on_error=None, follow_symlinks=False):
623623
"""Walk the directory tree from this directory, similar to os.walk()."""
624624
sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
625625
root_dir = str(self)
626-
results = self._globber.walk(root_dir, top_down, on_error, follow_symlinks)
626+
if not follow_symlinks:
627+
follow_symlinks = os._walk_symlinks_as_files
628+
results = os.walk(root_dir, top_down, on_error, follow_symlinks)
627629
for path_str, dirnames, filenames in results:
628630
if root_dir == '.':
629631
path_str = path_str[2:]

0 commit comments

Comments
 (0)