diff options
-rw-r--r-- | Doc/library/shutil.rst | 3 | ||||
-rw-r--r-- | Lib/shutil.py | 19 | ||||
-rw-r--r-- | Lib/test/test_shutil.py | 10 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2018-02-13-17-58-30.bpo-32689.a-3SnH.rst | 2 |
4 files changed, 32 insertions, 2 deletions
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 174b7e875a..59390d0e90 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -355,6 +355,9 @@ Directory and files operations copy the file more efficiently. See :ref:`shutil-platform-dependent-efficient-copy-operations` section. + .. versionchanged:: 3.9 + Accepts a :term:`path-like object` for both *src* and *dst*. + .. function:: disk_usage(path) Return disk usage statistics about the given path as a :term:`named tuple` diff --git a/Lib/shutil.py b/Lib/shutil.py index 5c1255a671..f0d0336636 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -730,8 +730,20 @@ def rmtree(path, ignore_errors=False, onerror=None): rmtree.avoids_symlink_attacks = _use_fd_functions def _basename(path): - # A basename() variant which first strips the trailing slash, if present. - # Thus we always get the last component of the path, even for directories. + """A basename() variant which first strips the trailing slash, if present. + Thus we always get the last component of the path, even for directories. + + path: Union[PathLike, str] + + e.g. + >>> os.path.basename('/bar/foo') + 'foo' + >>> os.path.basename('/bar/foo/') + '' + >>> _basename('/bar/foo/') + 'foo' + """ + path = os.fspath(path) sep = os.path.sep + (os.path.altsep or '') return os.path.basename(path.rstrip(sep)) @@ -769,7 +781,10 @@ def move(src, dst, copy_function=copy2): os.rename(src, dst) return + # Using _basename instead of os.path.basename is important, as we must + # ignore any trailing slash to avoid the basename returning '' real_dst = os.path.join(dst, _basename(src)) + if os.path.exists(real_dst): raise Error("Destination path '%s' already exists" % real_dst) try: diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index ab0f96d251..428d4f3417 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1835,6 +1835,16 @@ class TestMove(BaseTest, unittest.TestCase): # Move a file inside an existing dir on the same filesystem. self._check_move_file(self.src_file, self.dst_dir, self.dst_file) + def test_move_file_to_dir_pathlike_src(self): + # Move a pathlike file to another location on the same filesystem. + src = pathlib.Path(self.src_file) + self._check_move_file(src, self.dst_dir, self.dst_file) + + def test_move_file_to_dir_pathlike_dst(self): + # Move a file to another pathlike location on the same filesystem. + dst = pathlib.Path(self.dst_dir) + self._check_move_file(self.src_file, dst, self.dst_file) + @mock_rename def test_move_file_other_fs(self): # Move a file to an existing dir on another filesystem. diff --git a/Misc/NEWS.d/next/Library/2018-02-13-17-58-30.bpo-32689.a-3SnH.rst b/Misc/NEWS.d/next/Library/2018-02-13-17-58-30.bpo-32689.a-3SnH.rst new file mode 100644 index 0000000000..d435351a3a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-02-13-17-58-30.bpo-32689.a-3SnH.rst @@ -0,0 +1,2 @@ +Update :func:`shutil.move` function to allow for Path objects to be used as +source argument. Patch by Emily Morehouse and Maxwell "5.13b" McKinnon. |