diff -r 265e36e277f3 Doc/library/shutil.rst --- a/Doc/library/shutil.rst Mon Jul 16 17:11:10 2012 +0200 +++ b/Doc/library/shutil.rst Tue Jul 17 07:57:42 2012 +0900 @@ -52,7 +52,7 @@ Copy the contents (no metadata) of the file named *src* to a file named *dst* and return *dst*. *dst* must be the complete target file name; look at :func:`shutil.copy` for a copy that accepts a target directory path. If - *src* and *dst* are the same files, :exc:`Error` is raised. + *src* and *dst* are the same files, :exc:`SameFileError` is raised. The destination location must be writable; otherwise, an :exc:`OSError` exception will be raised. If *dst* already exists, it will be replaced. Special files @@ -63,6 +63,10 @@ a new symbolic link will be created instead of copying the file *src* points to. + + .. versionchanged:: 3.???? + Added raising :exc:`SameFileError`. + .. versionchanged:: 3.3 :exc:`IOError` used to be raised instead of :exc:`OSError`. Added *follow_symlinks* argument. @@ -261,6 +265,12 @@ .. versionadded:: 3.3 +.. 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.???? .. function:: which(cmd, mode=os.F_OK | os.X_OK, path=None) diff -r 265e36e277f3 Lib/shutil.py --- a/Lib/shutil.py Mon Jul 16 17:11:10 2012 +0200 +++ b/Lib/shutil.py Tue Jul 17 07:57:42 2012 +0900 @@ -42,6 +42,10 @@ class Error(EnvironmentError): pass +class SameFileError(Error): + """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)""" @@ -90,7 +94,7 @@ """ 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: @@ -215,6 +219,9 @@ If follow_symlinks is false, symlinks won't be followed. This resembles GNU's "cp -P src dst". + If the source and destination files are same, a SameFileError exception + will be raised. + """ if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) diff -r 265e36e277f3 Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py Mon Jul 16 17:11:10 2012 +0200 +++ b/Lib/test/test_shutil.py Tue Jul 17 07:57:42 2012 +0900 @@ -18,7 +18,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 @@ -1215,6 +1216,16 @@ self.assertTrue(os.path.exists(rv)) self.assertEqual(read_file(src_file), read_file(dst_file)) + def test_copyfile_same_file(self): + # copyfile() should raise SameFileError if The source and destination + # are the same. + src_dir = self.mkdtemp() + src_file = os.path.join(src_dir, 'foo') + write_file(src_file, 'foo') + + with self.assertRaises(SameFileError): + rv = shutil.copyfile(src_file, src_file) + def test_copytree_return_value(self): # copytree returns its destination path. src_dir = self.mkdtemp()