diff -r 1b4fae183da3 Doc/library/shutil.rst --- a/Doc/library/shutil.rst Tue Aug 09 18:48:02 2011 -0500 +++ b/Doc/library/shutil.rst Wed Aug 10 21:31:26 2011 +0700 @@ -166,8 +166,8 @@ moved inside that directory. 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. + exists but is not a directory, on Unix, it may be overwritten depending on + :func:`os.rename` semantics. On Windows, :exc:`SameFileError` will be raised. 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 @@ -189,6 +189,10 @@ 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. .. _shutil-example: @@ -408,5 +412,3 @@ -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 - - diff -r 1b4fae183da3 Lib/shutil.py --- a/Lib/shutil.py Tue Aug 09 18:48:02 2011 -0500 +++ b/Lib/shutil.py Wed Aug 10 21:31:26 2011 +0700 @@ -40,6 +40,9 @@ class Error(EnvironmentError): pass +class SameFileError(Error): + 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)""" @@ -83,7 +86,8 @@ 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("`{0}` and `{1}` are the same file".format(src, + dst)) for fn in [src, dst]: try: @@ -301,8 +305,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. @@ -323,7 +328,7 @@ raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) - except OSError as exc: + except OSError: if os.path.isdir(src): if _destinsrc(src, dst): raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) @@ -788,4 +793,4 @@ """ total, free = nt._getdiskusage(path) used = total - free - return _ntuple_diskusage(total, used, free) + return _ntuple_diskusage(total, used, free) \ No newline at end of file diff -r 1b4fae183da3 Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py Tue Aug 09 18:48:02 2011 -0500 +++ b/Lib/test/test_shutil.py Wed Aug 10 21:31:26 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 @@ -780,6 +781,19 @@ # 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 catched 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. @@ -978,4 +992,4 @@ support.run_unittest(TestShutil, TestMove, TestCopyFile) if __name__ == '__main__': - test_main() + test_main() \ No newline at end of file