Skip to content

gh-89721: Add copy_dir_stat parameter to shutil.copytree() - #160076

Open
ambv wants to merge 2 commits into
python:mainfrom
ambv:gh-89721-copytree-copy-dir-stat
Open

ambv wants to merge 2 commits into
python:mainfrom
ambv:gh-89721-copytree-copy-dir-stat

Conversation

@ambv

@ambv ambv commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Supersedes #109717 (closed).

Adds a copy_dir_stat parameter (default true) to shutil.copytree(). When false, directory permissions and times are not copied with copystat(), e.g. to copy a read-only tree into a writable one. Unlike the superseded PR, the flag propagates through recursive calls, and file metadata stays with copy_function (documented). Includes tests, docs, and a news entry.

copytree() now accepts copy_dir_stat (default true).  When false,
directory permissions and times are not copied with copystat(), e.g.
to copy a read-only tree into a writable one.  The flag propagates
through recursive calls; file metadata is unaffected and remains
handled by copy_function.  Document the parameter and cover both
behaviors with tests.

Co-authored-by: Muse Code (Meta Muse Spark)
@read-the-docs-community

read-the-docs-community Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #35306662 | 📁 Comparing 0861e82 against main (796b26b)

  🔍 Preview build  

28 files changed · + 1 added · ± 27 modified

+ Added

± Modified

WASI cannot change file mode bits, so skip the new copytree mode
tests there like the other chmod-dependent tests in test_shutil.

Co-authored-by: Muse Code (Meta Muse Spark)

@itamaro itamaro left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need a whatsnew bullet too?

Comment thread Lib/shutil.py
def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
ignore_dangling_symlinks=False, dirs_exist_ok=False):
ignore_dangling_symlinks=False, dirs_exist_ok=False,
copy_dir_stat=True):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a long args list. maybe at make new ones kw-only?

Suggested change
copy_dir_stat=True):
*, copy_dir_stat=True):

Comment thread Doc/library/shutil.rst
Comment on lines +254 to +257
If *copy_dir_stat* is false, permissions and times of directories are
not copied, e.g. to copy a read-only tree into a writable one. It
defaults to true. File metadata is always handled by *copy_function*.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps need different phrasing or clarification that, by default, just setting this to False will not magically make a read-only tree writable -- you also need to use a custom copy function, e.g. copy_function=shutil.copyfile

Comment thread Lib/test/test_shutil.py
self.assertEqual(os.stat(restrictive_subdir).st_mode,
os.stat(restrictive_subdir_dst).st_mode)

@os_helper.skip_unless_working_chmod

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: also assert on whether the times are copied or not (as per the documented behavior)

Comment thread Doc/library/shutil.rst
Permissions and times of directories are copied with :func:`copystat`,
individual files are copied using :func:`~shutil.copy2`.

If *copy_dir_stat* is false, permissions and times of directories are

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "permissions and times" is a subset of the metadata that's copied (or not).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting merge type-feature A feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants