-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
gh-90385: Add pathlib.Path.walk()
method
#92517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
ac622b7
14f031a
b203517
3ad60a9
889d7fe
2f98823
513030a
5fdd72e
452f24e
3702a12
fabc925
b387b54
097fbbf
76fadfc
0c19871
50b4a2b
cade3e9
b32627c
d1a0833
e367f1f
bf8b0eb
d8667c7
4509797
20a73ed
e61d57b
15d96b9
92e1a7a
c509da3
cfa730d
7aec96d
38fe1e5
eef3ba3
4dfdcd7
8fe3b62
e8ea6ba
79cf8fd
bed850e
203ec3d
eef6054
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -920,6 +920,112 @@ call fails (for example because the path doesn't exist). | |
to the directory after creating the iterator, whether a path object for | ||
that file be included is unspecified. | ||
|
||
.. method:: Path.walk(top_down=True, on_error=None, follow_symlinks=False) | ||
|
||
Generate the file names in a directory tree by walking the tree | ||
either top-down or bottom-up. | ||
|
||
For each directory in the directory tree rooted at *self* (including | ||
*self* but excluding '.' and '..'), yields a 3-tuple | ||
``(dirpath, dirnames, filenames)`` | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
*dirpath* is a Path to the directory, *dirnames* is a list of the names | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
of the subdirectories in *dirpath* (excluding ``'.'`` and ``'..'``), and | ||
*filenames* is a list of the names of the non-directory files in *dirpath*. | ||
Note that the names in the lists contain no path components. To get a full | ||
path (which begins with *self*) to a file or directory in *dirpath*, do | ||
``dirpath / name``. Whether or not the lists are sorted depends on the file | ||
system. If a file or a directory is removed from or added to the *dirpath* | ||
during the generation of *dirnames* and *filenames*, it is uncertain whether | ||
the new entry will appear in the generated lists. | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
If optional argument *top_down* is ``True`` or not specified, the triple for a | ||
directory is generated before the triples for any of its subdirectories | ||
(directories are generated top-down). If *top_down* is ``False``, the triple | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for a directory is generated after the triples for all of its subdirectories | ||
(directories are generated bottom-up). No matter the value of *top_down*, the | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
list of subdirectories is retrieved before the tuples for the directory and | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
its subdirectories are generated. | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
When *top_down* is True, the caller can modify the *dirnames* list in-place | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(For example, using :keyword:`del` or slice assignment), and :meth:`Path.walk` | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
will only recurse into the subdirectories whose names remain in *dirnames*; | ||
this can be used to prune the search, or to impose a specific order of visiting, | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
or even to inform :meth:`Path.walk` about directories the caller creates or | ||
renames before it resumes :meth:`Path.walk` again. Modifying *dirnames* when | ||
*top_down* is False has no effect on the behavior of :meth:`Path.walk()`, since the | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
directories in *dirnames* have already been generated by the time *dirnames* | ||
is yielded to the caller. | ||
|
||
By default errors from :meth:`Path._scandir` call are ignored. If | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
optional argument *on_error* is specified, it should be a callable; it | ||
will be called with one argument, an :exc:`OSError` instance. It can | ||
report the error to continue with the walk, or raise the exception | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean by "report the error to continue the walk"? Do you mean suppress/consume the exception, or else re-raise it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly that. Please, take a look at these lines again. I tried to clarify and simplify it a little bit. |
||
to abort the walk. Note that the filename is available as the | ||
``filename`` attribute of the exception object. | ||
|
||
By default, :meth:`Path.walk` will not walk down into symbolic links that | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
resolve to directories. Set *follow_symlinks* to ``True`` to visit directories | ||
pointed to by symlinks, on systems that support them. | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
.. note:: | ||
|
||
Be aware that setting *follow_symlinks* to ``True`` can lead to infinite | ||
recursion if a link points to a parent directory of itself. :meth:`Path.walk` | ||
does not keep track of the directories it visited already. | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
.. note:: | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
If self is a relative Path, don't change the current working directory between | ||
resumptions of :meth:`Path.walk`. :meth:`Path.walk` never changes the current | ||
directory, and assumes that the caller doesn't either. | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.. note:: | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
:meth:`Path.walk` assumes the directories have not been modified between | ||
its resumptions. I.e. If a directory from *dirnames* has been replaced | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
with a symlink and *follow_symlinks* = ``False``, :meth:`Path.walk` will | ||
still try to descend into it. To prevent such behavior, remove directories | ||
from *dirnames* if they have been modified and you do not want to | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
descend into them anymore. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This note feels like unnecessary detail to me - replacing a directory with a symlink is an edge case, and it can already be inferred from the prior section on dirnames that entries should be removed from dirnames if they no longer exist, or are no longer directories. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You see, the fact that we still try to descend into these "no-longer-directories" is more of an optimization, and not an intuitive one at that. So I feel like having a short note about it at the end of the documentation of the method won't hurt. |
||
|
||
.. note:: | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Unlike :func:`os.walk`, :meth:`Path.walk` adds symlinks to directories into *filenames* | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This example displays the number of bytes taken by non-directory files in each | ||
directory under the starting directory, except that it doesn't look under any | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
__pycache__ subdirectory:: | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
from pathlib import Path | ||
for root, dirs, files in Path("cpython/Lib/concurrent").walk(on_error=print): | ||
print( | ||
root, | ||
"consumes", | ||
sum((root / file).stat().st_size for file in files), | ||
"bytes in", | ||
len(files), | ||
"non-directory files" | ||
) | ||
if '__pycache__' in dirs: | ||
dirs.remove('__pycache__') | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
In the next example (simple implementation of :func:`shutil.rmtree`), | ||
walking the tree bottom-up is essential, :func:`rmdir` doesn't allow | ||
deleting a directory before the directory is empty:: | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Delete everything reachable from the directory "top", | ||
# assuming there are no symbolic links. | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# CAUTION: This is dangerous! For example, if top == Path('/'), | ||
# it could delete all your disk files. | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for root, dirs, files in top.walk(topdown=False): | ||
for name in files: | ||
(root / name).unlink() | ||
for name in dirs: | ||
(root / name).rmdir() | ||
|
||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.. versionadded:: 3.12 | ||
|
||
.. method:: Path.lchmod(mode) | ||
|
||
Like :meth:`Path.chmod` but, if the path points to a symbolic link, the | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Added method walk to :class:`pathlib.Path` objects as a pathlib alternative for :func:`os.walk` | ||
zmievsa marked this conversation as resolved.
Show resolved
Hide resolved
|
Uh oh!
There was an error while loading. Please reload this page.