From a5ee60abfd624dcc5a3b498a1420c61b7c759778 Mon Sep 17 00:00:00 2001 From: barneygale Date: Mon, 22 Jul 2024 04:39:46 +0100 Subject: [PATCH] Fix moving a file/directory to itself. --- Doc/library/pathlib.rst | 5 +++-- Lib/pathlib/_local.py | 3 ++- Lib/test/test_pathlib/test_pathlib_abc.py | 10 ++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 8720db3bf74341..1afe116a456f9c 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1598,8 +1598,9 @@ Copying, moving and deleting return a new :class:`!Path` instance pointing to *target*. If the *target* doesn't exist it will be created. If both this path and the - *target* are existing files, then the target is overwritten. If the - *target* is a non-empty directory, :exc:`OSError` is raised. + *target* are existing files, then the target is overwritten. If both paths + point to the same file or directory, or the *target* is a non-empty + directory, then :exc:`OSError` is raised. If both paths are on the same filesystem, the move is performed with :func:`os.replace`. Otherwise, this path is copied (preserving metadata and diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py index fc656927ed0eb1..0f98454b7c97af 100644 --- a/Lib/pathlib/_local.py +++ b/Lib/pathlib/_local.py @@ -854,7 +854,8 @@ def move(self, target): """ Recursively move this file or directory tree to the given destination. """ - + if self._samefile_safe(target): + raise OSError(f"{self!r} and {target!r} are the same file") try: return self.replace(target) except TypeError: diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py index d3a3fa9d61de4a..9a0a8ae2d9017a 100644 --- a/Lib/test/test_pathlib/test_pathlib_abc.py +++ b/Lib/test/test_pathlib/test_pathlib_abc.py @@ -2011,6 +2011,11 @@ def test_move_file_to_dir(self): target = base / 'dirB' self.assertRaises(OSError, source.move, target) + def test_move_file_to_itself(self): + base = self.cls(self.base) + source = base / 'fileA' + self.assertRaises(OSError, source.move, source) + def test_move_dir(self): base = self.cls(self.base) source = base / 'dirC' @@ -2033,6 +2038,11 @@ def test_move_dir_to_dir(self): target = base / 'dirB' self.assertRaises(OSError, source.move, target) + def test_move_dir_to_itself(self): + base = self.cls(self.base) + source = base / 'dirC' + self.assertRaises(OSError, source.move, source) + def test_move_dir_into_itself(self): base = self.cls(self.base) source = base / 'dirC'