GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Support moving across filesystems in pathlib.Path, as shutil.move() does · Issue #73991 · python/cpython

Support moving across filesystems in pathlib.Path, as shutil.move() does #73991

New issue
Copy link
New issue
Copy link
Closed
Closed
Support moving across filesystems in pathlib.Path, as shutil.move() does#73991
Copy link
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-pathlibtype-featureA feature request or enhancementA feature request or enhancement

Description

LaurentMazuel
mannequin
opened on Mar 13, 2017
Issue body actions
BPO 29805
Nosy @brettcannon, @pfmoore, @ericvsmith, @tjguk, @zware, @eryksun, @zooba

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2017-03-13.21:03:44.694>
labels = ['3.8', 'type-feature', 'library', '3.9', '3.10']
title = 'Support moving across filesystems in pathlib.Path, as shutil.move() does'
updated_at = <Date 2021-03-15.21:26:30.922>
user = 'https://bugs.python.org/LaurentMazuel'

bugs.python.org fields:

activity = <Date 2021-03-15.21:26:30.922>
actor = 'eryksun'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2017-03-13.21:03:44.694>
creator = 'Laurent.Mazuel'
dependencies = []
files = []
hgrepos = []
issue_num = 29805
keywords = []
message_count = 6.0
messages = ['289549', '289552', '289559', '289630', '289687', '289688']
nosy_count = 8.0
nosy_names = ['brett.cannon', 'paul.moore', 'eric.smith', 'tim.golden', 'Laurent.Mazuel', 'zach.ware', 'eryksun', 'steve.dower']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue29805'
versions = ['Python 3.8', 'Python 3.9', 'Python 3.10']

Linked PRs

  • GH-73991: Add pathlib.Path.move that can handle rename across FS #30650
  • GH-73991: Add pathlib.Path.copy() #119058
  • GH-73991: Add pathlib.Path.rmtree() #119060
  • [WIP] GH-73991: Add os.copy() and friends #119079
  • GH-73991: Split "Directory and file operations" section in shutil docs #119159
  • GH-73991: Use same signature for shutil._rmtree_[un]safe(). #120517
  • GH-73991: Add follow_symlinks argument to pathlib.Path.copy() #120519
  • GH-73991: pathlib ABC tests: add DummyPath.unlink() and rmdir() #120715
  • GH-73991: Add pathlib.Path.copytree() #120718
  • GH-73991: Support preserving metadata in pathlib.Path.copy() #120806
  • GH-73991: Support copying directory symlinks on older Windows #120807
  • GH-73991: Support preserving metadata in pathlib.Path.copytree() #121438
  • GH-73991: Fix "Operation not supported" on Fedora buildbot. #121444
  • GH-73991: Add pathlib.Path.move() #122073
  • GH-73991: Rework pathlib.Path.rmtree() into delete() #122368
  • GH-73991: Rework pathlib.Path.copytree() into copy() #122369
  • GH-73991: Disallow copying directory into itself via pathlib.Path.copy() #122924
  • GH-73991: Prune pathlib.Path.delete() arguments #123158
  • GH-73991: Add pathlib.Path.copy_into() and move_into() #123314
  • GH-73991: Make pathlib.Path.delete() private. #123315
  • GH-73991: Prune pathlib.Path.copy() and copy_into() arguments #123337
Reacted by Andreas Poehlmann and EDM115

Activity

Next
  1. LaurentMazuel commented on Mar 13, 2017

    @LaurentMazuel
    LaurentMazuelmannequin
    on Mar 13, 2017
    MannequinAuthor
    More actions

    Trying to use Pathlib and Path.replace on Windows if drive are different leads to an issue:

      File "D:\\myscript.py", line 184, in update
        client_generated_path.replace(destination_folder)
      File "c:\\program files (x86)\\python35-32\\Lib\\pathlib.py", line 1273, in replace
        self.\_accessor.replace(self, target)
      File "c:\\program files (x86)\\python35-32\\Lib\\pathlib.py", line 377, in wrapped
        return strfunc(str(pathobjA), str(pathobjB), \*args)
    OSError: [WinError 17] The system cannot move the file to a different disk drive: 'C:\\\\MyFolder' -\> 'D:\\\\MyFolderNewName'
    

    This is a known situation of os.rename, and workaround I found is to use shutil or to copy/delete manually in two steps (e.g. http://stackoverflow.com/questions/21116510/python-oserror-winerror-17-the-system-cannot-move-the-file-to-a-different-d)

    When using Pathlib, it's not that easy to workaround using shutil (even if thanks to Brett Cannon now shutil accepts Path in Py3.6, not everybody has Py3.6). At least this should be documented with a recommendation for that situation. I love Pathlib and it's too bad my code becomes complicated when it was so simple :(

  2. LaurentMazuel
    added
    topic-IO
    OS-windows
    on Mar 13, 2017
  3. brettcannon
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    and removed
    topic-IO
    on Mar 13, 2017
  4. LaurentMazuel commented on Mar 13, 2017

    @LaurentMazuel
    LaurentMazuelmannequin
    on Mar 13, 2017
    MannequinAuthor
    More actions

    Just to confirm, I was able to workaround it with Py3.6:

        # client_generated_path.replace(destination_folder)
        shutil.move(client_generated_path, destination_folder)

    It is reasonable to think about adding a similar feature to pathlib if it doesn't support it and just special-case the drive-to-drive scenario for Windows

  5. eryksun commented on Mar 14, 2017

    @eryksun
    eryksun
    on Mar 14, 2017
    Contributor
    More actions

    Moving a file across volumes isn't atomic. Getting an exception in this case can be useful. There could be a "strict" keyword-only parameter that defaults to False. If it's true, then replace() won't try to move the file.

  6. ericvsmith commented on Mar 15, 2017

    @ericvsmith
    ericvsmith
    on Mar 15, 2017
    Member
    More actions

    I agree this needs to be different from replace(), due to not being atomic. That makes it an enhancement, so I'm removing 3.5.

    I'm +1 on Path supporting something like shutil.move().

  7. ericvsmith
    added
    type-featureA feature request or enhancementA feature request or enhancement
    on Mar 15, 2017
  8. brettcannon commented on Mar 15, 2017

    @brettcannon
    brettcannon
    on Mar 15, 2017
    Member
    More actions

    I also support the idea of getting something like shutil.move() into pathlib.

  9. brettcannon commented on Mar 15, 2017

    @brettcannon
    brettcannon
    on Mar 15, 2017
    Member
    More actions

    I should also mention that rename() (https://docs.python.org/3/library/pathlib.html#pathlib.Path.rename) and replace() (https://docs.python.org/3/library/pathlib.html#pathlib.Path.replace) already do exist, so it might be best to add a keyword-only flag to one of those for this use-case.

  10. eryksun
    added
    3.8 (EOL)end of lifeend of life
    3.9 (EOL)end of lifeend of life
    3.10 (EOL)end of lifeend of life
    and removed
    OS-windows
    on Mar 15, 2021
  11. 136 remaining items

  12. picnixz
    removed
    3.14bugs and security fixesbugs and security fixes
    on Aug 26, 2024
  13. barneygale
    added 5 commits that reference this issue on Aug 26, 2024

    GH-73991: Add `pathlib.Path.copy_into()` and `move_into()` (#123314)

    c68a93c

    Merge branch 'main' into pythongh-73991-private-delete

    3ddf1d0

    pythonGH-73991: Prune `pathlib.Path.copy()` and `copy_into()` arguments

    8d25830

    GH-73991: Make `pathlib.Path.delete()` private. (#123315)

    033d537

    GH-73991: Prune `pathlib.Path.copy()` and `copy_into()` arguments (#1…

    7bd6ebf
  14. barneygale commented on Aug 26, 2024

    @barneygale
    barneygale
    on Aug 26, 2024
    Contributor
    More actions

    It's done! Thank you everyone who helped formulate and review this feature.

    We've added new copy(), copy_into(), move() and move_into() methods, which work on both files and directories. The interfaces are refined to pathlib standards, with certain nonessential functionality (like support for filtering in copy()) omitted for now. Users may wish to propose new capabilities on the ideas forum.

    The new methods expect exact targets (or target directories for the _into() variants), whereas shutil checks for existing directories and adjusts the target as necessary. The latter behaviour is helpful in an interactive shell with tab-complete, but less so in a stored program where state of the filesystem might not be known (for example, shutil.copy('a', 'b') could create either b or b/a).

    The copy() and copy_into() methods use fcntl.FICLONE or os.copy_file_range where available (see GH-81338, GH-81340). This work has stalled for years in shutil for backwards-compatibility concerns, happily not present here.

    Feedback most welcome! We have ~9 months until 3.14 beta 1 where the interface is more locked down, so there's still plenty of time make changes. I'll close this issue, but I can re-open it (or log new issues) if problems are identified. Thanks again, all.

    Reacted by GalaxySnail, Andreas Poehlmann, Edgar Ramírez Mondragón, Nice Zombies, Johnny Arcitec, Tal Einat, Dima Tisnek, Petr Viktorin, traal, h-vetinari and 1 more
  15. barneygale
    closed this as completedon Aug 26, 2024
  16. github-project-automation
    moved this from Todo to Done in pathlib issueson Aug 26, 2024
  17. encukou commented on Dec 2, 2024

    @encukou
    encukou
    on Dec 2, 2024
    Member
    More actions

    For copying trees, what happens on error -- for example, when one of the files has a name that's incompatible with the target filesystem?

  18. barneygale commented on Dec 2, 2024

    @barneygale
    barneygale
    on Dec 2, 2024
    Contributor
    More actions

    In that case you'll get an OSError. Any copies already made will be left on disk, and in the case of move(), none of the original files will be deleted.

  19. agronholm commented on Dec 6, 2024

    @agronholm
    agronholm
    on Dec 6, 2024
    Contributor
    More actions

    It looks like, unlike copy(), this method fails if I pass a path-like object that just happens to have a method named stat(). It then fails at self._ensure_different_file(target) which already assumes a Path as its argument type. It really should do an isinstance check on the target. In my case, stat() is a coroutine method, so it fails with AttributeError: 'coroutine' object has no attribute 'st_ino'.

  20. zooba commented on Dec 9, 2024

    @zooba
    zooba
    on Dec 9, 2024
    Member
    More actions

    Passing an object that looks similar but isn't the same is the caller's error. An AttributeError is exactly what you should get in this case.

    That said, it probably wouldn't be unreasonable to convert any incoming paths to the same type as the source. We shouldn't type check here, we should try to convert and let the errors bubble out to the caller.

  21. agronholm commented on Dec 9, 2024

    @agronholm
    agronholm
    on Dec 9, 2024
    Contributor
    More actions

    Such type checks are done everywhere else, including in the method in question! This would be solved simply by doing said type check earlier.

    Is it reasonable to expect this to fail on a PathLike object? How am I supposed to know what I can pass as the target then?

  22. zooba commented on Dec 9, 2024

    @zooba
    zooba
    on Dec 9, 2024
    Member
    More actions

    In general for pathlib, you should be able to pass any object that can be interpreted as the same kind of path as the one you're passing it to. I know that upsets the static typing people because it's hard to define, but being accepting of inputs is a key Python feature.

    In this case, that means converting the input to the same type as the target before using it. Most of the functions that have type checks are essentially doing this - they're negative checks, followed by essentially type(self)(other), which will try its hardest to parse the path out of the input. But samefile is not doing this and clearly ought to be. I suggest opening a new issue.

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

    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-pathlibtype-featureA feature request or enhancementA feature request or enhancement

    Projects

    • pathlib issues
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.