Skip to content

Support exist_ok for pathlib's Path.copy_into() #143052

Open

Description

@Sevrain1

Bug report

Bug description:

Background

The Path.copy_into() method (introduced in Python 3.14) is used to copy files or directories into another directory.
The behaviour of files being copied and directories being copied is inconsistent when the destination directory contains a file or directory with the same name.

Examples

When a file is copied into a directory that already has a file with that name, the copied file overwrites the file at the destination directory:

"""
# Copying a file into a directory that already has a file with the same name #

Directory Structure:
dir_a
    |__my_file.txt

dir_b
    |__my_file.txt
"""
from pathlib import Path

dir_a_my_file = Path("dir_a") / "my_file.txt"
dir_b = Path("dir_b")

# Act
dir_a_my_file.copy_into(dir_b)  # Success - dir_a/my_file.txt overwrites dir_b/my_file.txt

However, when a directory is copied into another directory (one which contains a sub-directory with the same name),
the copy operation fails and FileExistsError is raised:

"""
# Copying a directory into a directory, that contains a sub-directory with the same name #

Directory Structure:
dir_a
    |__my_dir

dir_b
    |__my_dir
"""
from pathlib import Path

dir_a_my_dir = Path("dir_a") / "my_dir"
dir_b = Path("dir_b")

# Act
dir_a_my_dir.copy_into(dir_b)  # Failure - FileExistsError is raised.

Problem

The behaviour of the copy_into() method in the file case (success) and in the directory case (failure) is inconsistent.
It is also inconsistent with how Linux (when using cp -r) handles this exact same case.

Expected Result

Instead of raising an exception, the copied directory should be merged with the existing one.

Fix Suggestion

  1. Add a default exist_ok=True parameter to copy_into().
    This parameter is already used in the Path.touch() and Path.mkdir() methods, and should be familiar to users.

  2. When a file is copied into a destination directory that already has a file with the same name:

    • If exist_ok=True, the copied file should overwrite the file at the destination directory.
      This is the already the current behaviour, so no additional changes are required.

    • If exist_ok=False, a FileExistsError exception will be raised. This is consistent with the behaviour of Path.touch().

  3. When a directory is copied into a destination directory that contains a sub-directory with the same name:

    • If exist_ok=True, the copied directory will be merged with the destination's sub-directory.
      This is consistent with the behaviour of copying in Linux.
    • If exist_ok=False, a FileExistsError exception will be raised. This is consistent with the behaviour of Path.mkdir().

Thank you.

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

Activity

  1. changed the title [-]Inconsistent behaviour in `pathlib.Path.copy_into()` when copying files vs. copying directories[/-] [+]Inconsistent behaviour in `pathlib`'s `Path.copy_into()` when copying files vs. copying directories[/+] on Dec 21, 2025
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Dec 22, 2025
  3. added 2 commits that reference this issue on Dec 22, 2025
  4. picnixz commented on Dec 24, 2025

    @picnixz
    Member

    What is the behavior of Path.copy()? I believe we should align copy_into(). Note that the default behavior is the same as of shutil.copytree() which raises such errors on existing directories so I do not think it is a bug.

  5. added
    type-featureA feature request or enhancement
    and removed
    type-bugAn unexpected behavior, bug, or error
    on Dec 24, 2025
  6. changed the title [-]Inconsistent behaviour in `pathlib`'s `Path.copy_into()` when copying files vs. copying directories[/-] [+]Support `exist_ok` for `pathlib`'s `Path.copy_into()`[/+] on Dec 24, 2025
  7. picnixz commented on Dec 24, 2025

    @picnixz
    Member

    Now for more advanced usages such as this feature request, I believe shutil.copytree should be preferred then. We sometimes have APIs that are more restrictive because generic ones exist elsewhere.

    cc @barneygale

  8. added
    pendingThe issue will be closed if no feedback is provided
    on Dec 24, 2025
  9. 0x6e6174 commented on Dec 31, 2025

    @0x6e6174

    I find the it confusing that Path.mkdir() accepts an exists_ok argument, but Path.copy() and Path.copy_into() do not. I think that allowing said methods to overwrite existing files is a feature that makes sense to implement, because otherwise one would have to remove the target directory prior to copying or defer to something outside of pathlib.

  10. picnixz commented on Dec 31, 2025

    @picnixz
    Member

    I think the reason why mkdir accepts exists_ok is because os.makedirs does (but not os.mkdir) and that creating a directory is usually harmless but copying something into a directory that may already exist and overwriting stuff is not harmless.

    I looks like it was a deliberate choice (see #73991 (comment)) where we restricted the interface. Since it was explicitly asked to open a https://discuss.python.org/c/ideas/6 thread to discuss improvements, that's what we should do.


    Note: I personally don't care about which design we choose but I do care about maintenance burden (the implementation doesn't look trivial to me as it seems to assume that we won't encounter existing directories), which is why I'm leaving it to Barney. He may also decide whether this should be considered a bug or not (maybe it is!)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    pendingThe issue will be closed if no feedback is providedstdlibStandard Library Python modules in the Lib/ directorytopic-pathlibtype-featureA feature request or enhancement

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions