diff -r 5c8b6e03ebfe Doc/library/shutil.rst --- a/Doc/library/shutil.rst Tue Sep 06 19:03:35 2011 +0200 +++ b/Doc/library/shutil.rst Wed Sep 07 22:13:15 2011 +0700 @@ -167,7 +167,11 @@ The destination directory must not already exist. If the destination already exists but is not a directory, it may be overwritten depending on - :func:`os.rename` semantics. + :func:`os.rename` semantics. If the operation fails, a :exc:`SameFileError` + will be raised. + + .. versionchanged:: 3.2 + Added raising :exc:`SameFileError`. If the destination is on the current filesystem, then :func:`os.rename` is used. Otherwise, *src* is copied (using :func:`copy2`) to *dst* and then @@ -203,6 +207,12 @@ operation. For :func:`copytree`, the exception argument is a list of 3-tuples (*srcname*, *dstname*, *exception*). +.. exception:: SameFileError + + This exception is raised if source and destination in :func:`move` + are the same files. It is a subclass of :exc:`Error`. + + .. versionadded:: 3.2 .. _shutil-example: @@ -421,6 +431,4 @@ -rwxr-xr-x tarek/staff 609 2008-06-09 13:26:54 ./id_dsa.pub -rw------- tarek/staff 1675 2008-06-09 13:26:54 ./id_rsa -rw-r--r-- tarek/staff 397 2008-06-09 13:26:54 ./id_rsa.pub - -rw-r--r-- tarek/staff 37192 2010-02-06 18:23:10 ./known_hosts - - + -rw-r--r-- tarek/staff 37192 2010-02-06 18:23:10 ./known_hosts \ No newline at end of file diff -r 5c8b6e03ebfe Lib/shutil.py --- a/Lib/shutil.py Tue Sep 06 19:03:35 2011 +0200 +++ b/Lib/shutil.py Wed Sep 07 22:13:15 2011 +0700 @@ -41,6 +41,10 @@ class Error(EnvironmentError): pass +class SameFileError(Error): + """Is raised when source and destination are the same files.""" + pass + class SpecialFileError(EnvironmentError): """Raised when trying to do a kind of operation (e.g. copying) which is not supported on a special file (e.g. a named pipe)""" @@ -84,7 +88,7 @@ def copyfile(src, dst): """Copy data from src to dst""" if _samefile(src, dst): - raise Error("`%s` and `%s` are the same file" % (src, dst)) + raise SameFileError("{!r} and {!r} are the same file".format(src, dst)) for fn in [src, dst]: try: @@ -302,8 +306,9 @@ is moved inside the directory. The destination path must not already exist. - If the destination already exists but is not a directory, it may be - overwritten depending on os.rename() semantics. + If the destination already exists but is not a directory, on Unix, + it may be overwritten depending on os.rename() semantics. + On Windows, SameFileError will be raised. If the destination is on our current filesystem, then rename() is used. Otherwise, src is copied to the destination and then removed. diff -r 5c8b6e03ebfe Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py Tue Sep 06 19:03:35 2011 +0200 +++ b/Lib/test/test_shutil.py Wed Sep 07 22:13:15 2011 +0700 @@ -16,7 +16,8 @@ register_archive_format, unregister_archive_format, get_archive_formats, Error, unpack_archive, register_unpack_format, RegistryError, - unregister_unpack_format, get_unpack_formats) + unregister_unpack_format, get_unpack_formats, + SameFileError) import tarfile import warnings @@ -813,6 +814,18 @@ # Move a file inside an existing dir on the same filesystem. self._check_move_file(self.src_file, self.dst_dir, self.dst_file) + @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") + def test_move_same_file(self): + # The source and destination are the same, should raise SameFileError + # on Windows (due to implementation details of os.rename()). + with self.assertRaises(SameFileError): + self._check_move_file(self.src_file, self.src_file, + self.src_file) + + # Check that it can be also caught with shutil.Error exception + with self.assertRaises(Error): + self._check_move_file(self.src_file, self.src_file, self.src_file) + @mock_rename def test_move_file_other_fs(self): # Move a file to an existing dir on another filesystem. @@ -1010,4 +1023,4 @@ support.run_unittest(TestShutil, TestMove, TestCopyFile) if __name__ == '__main__': - test_main() + test_main() \ No newline at end of file