]> granicus.if.org Git - python/commitdiff
Fix #14772: Return the destination from some shutil functions.
authorBrian Curtin <brian@python.org>
Mon, 18 Jun 2012 23:41:07 +0000 (18:41 -0500)
committerBrian Curtin <brian@python.org>
Mon, 18 Jun 2012 23:41:07 +0000 (18:41 -0500)
Doc/library/shutil.rst
Lib/shutil.py
Lib/test/test_shutil.py
Misc/NEWS

index 27d374a19a5266e3d7eb2410f8ac5a7dc05256b5..3b9e6f4f73c98a7ea2a8299e5d8b78f34a5f22c3 100644 (file)
@@ -50,7 +50,7 @@ Directory and files operations
 .. function:: copyfile(src, dst, symlinks=False)
 
    Copy the contents (no metadata) of the file named *src* to a file named
-   *dst*.  *dst* must be the complete target file name; look at
+   *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.
 
@@ -91,7 +91,8 @@ Directory and files operations
 
 .. function:: copy(src, dst, symlinks=False))
 
-   Copy the file *src* to the file or directory *dst*.  If *dst* is a directory, a
+   Copy the file *src* to the file or directory *dst* and return the file's
+   destination.  If *dst* is a directory, a
    file with the same basename as *src*  is created (or overwritten) in the
    directory specified.  Permission bits are copied.  *src* and *dst* are path
    names given as strings.  If *symlinks* is true, symbolic links won't be
@@ -102,7 +103,8 @@ Directory and files operations
 
 .. function:: copy2(src, dst, symlinks=False)
 
-   Similar to :func:`shutil.copy`, but metadata is copied as well. This is
+   Similar to :func:`shutil.copy`, including that the destination is
+   returned, but metadata is copied as well. This is
    similar to the Unix command :program:`cp -p`.  If *symlinks* is true,
    symbolic links won't be followed but recreated instead -- this resembles
    GNU's :program:`cp -P`.
@@ -120,7 +122,8 @@ Directory and files operations
 
 .. function:: copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False)
 
-   Recursively copy an entire directory tree rooted at *src*.  The destination
+   Recursively copy an entire directory tree rooted at *src*, returning the
+   destination directory.  The destination
    directory, named by *dst*, must not already exist; it will be created as
    well as missing parent directories.  Permissions and times of directories
    are copied with :func:`copystat`, individual files are copied using
@@ -189,7 +192,8 @@ Directory and files operations
 
 .. function:: move(src, dst)
 
-   Recursively move a file or directory (*src*) to another location (*dst*).
+   Recursively move a file or directory (*src*) to another location (*dst*)
+   and return the destination.
 
    If the destination is a directory or a symlink to a directory, then *src* is
    moved inside that directory.
index ce60c3b113799ac2794ae3a2d414dff86f998457..46398efd0170362cd73570bd9e25262757ca9579 100644 (file)
@@ -109,6 +109,7 @@ def copyfile(src, dst, symlinks=False):
         with open(src, 'rb') as fsrc:
             with open(dst, 'wb') as fdst:
                 copyfileobj(fsrc, fdst)
+    return dst
 
 def copymode(src, dst, symlinks=False):
     """Copy mode bits from src to dst.
@@ -197,7 +198,7 @@ else:
         pass
 
 def copy(src, dst, symlinks=False):
-    """Copy data and mode bits ("cp src dst").
+    """Copy data and mode bits ("cp src dst"). Return the file's destination.
 
     The destination may be a directory.
 
@@ -209,9 +210,11 @@ def copy(src, dst, symlinks=False):
         dst = os.path.join(dst, os.path.basename(src))
     copyfile(src, dst, symlinks=symlinks)
     copymode(src, dst, symlinks=symlinks)
+    return dst
 
 def copy2(src, dst, symlinks=False):
-    """Copy data and all stat info ("cp -p src dst").
+    """Copy data and all stat info ("cp -p src dst"). Return the file's
+    destination."
 
     The destination may be a directory.
 
@@ -224,6 +227,7 @@ def copy2(src, dst, symlinks=False):
     copyfile(src, dst, symlinks=symlinks)
     copystat(src, dst, symlinks=symlinks)
     _copyxattr(src, dst, symlinks=symlinks)
+    return dst
 
 def ignore_patterns(*patterns):
     """Function that can be used as copytree() ignore parameter.
@@ -322,6 +326,7 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
             errors.extend((src, dst, str(why)))
     if errors:
         raise Error(errors)
+    return dst
 
 def rmtree(path, ignore_errors=False, onerror=None):
     """Recursively delete a directory tree.
@@ -379,7 +384,8 @@ def _basename(path):
 
 def move(src, dst):
     """Recursively move a file or directory to another location. This is
-    similar to the Unix "mv" command.
+    similar to the Unix "mv" command. Return the file or directory's
+    destination.
 
     If the destination is a directory or a symlink to a directory, the source
     is moved inside the directory. The destination path must not already
@@ -423,6 +429,7 @@ def move(src, dst):
         else:
             copy2(src, real_dst)
             os.unlink(src)
+    return real_dst
 
 def _destinsrc(src, dst):
     src = abspath(src)
index 3b4e381a0b4747648ffc17efe7cce14dab695230..118152031ad8d84c63cf5b140e90e21d95b2144e 100644 (file)
@@ -1095,6 +1095,38 @@ class TestShutil(unittest.TestCase):
         shutil.chown(dirname, user, group)
         check_chown(dirname, uid, gid)
 
+    def test_copy_return_value(self):
+        # copy and copy2 both return their destination path.
+        for fn in (shutil.copy, shutil.copy2):
+            src_dir = self.mkdtemp()
+            dst_dir = self.mkdtemp()
+            src = os.path.join(src_dir, 'foo')
+            write_file(src, 'foo')
+            rv = fn(src, dst_dir)
+            self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
+            rv = fn(src, os.path.join(dst_dir, 'bar'))
+            self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
+
+    def test_copyfile_return_value(self):
+        # copytree returns its destination path.
+        src_dir = self.mkdtemp()
+        dst_dir = self.mkdtemp()
+        dst_file = os.path.join(dst_dir, 'bar')
+        src_file = os.path.join(src_dir, 'foo')
+        write_file(src_file, 'foo')
+        rv = shutil.copyfile(src_file, dst_file)
+        self.assertTrue(os.path.exists(rv))
+        self.assertEqual(read_file(src_file), read_file(dst_file))
+
+    def test_copytree_return_value(self):
+        # copytree returns its destination path.
+        src_dir = self.mkdtemp()
+        dst_dir = src_dir + "dest"
+        src = os.path.join(src_dir, 'foo')
+        write_file(src, 'foo')
+        rv = shutil.copytree(src_dir, dst_dir)
+        self.assertEqual(['foo'], os.listdir(rv))
+
 
 class TestMove(unittest.TestCase):
 
@@ -1251,6 +1283,15 @@ class TestMove(unittest.TestCase):
         self.assertTrue(os.path.islink(dst_link))
         self.assertTrue(os.path.samefile(src, dst_link))
 
+    def test_move_return_value(self):
+        rv = shutil.move(self.src_file, self.dst_dir)
+        self.assertEqual(rv,
+                os.path.join(self.dst_dir, os.path.basename(self.src_file)))
+
+    def test_move_as_rename_return_value(self):
+        rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
+        self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
+
 
 class TestCopyFile(unittest.TestCase):
 
index 93aeaf877165a84d1e27ceb38c5af968f2b45559..de7a2c485d6362ccda9836d4502a0dbe4539731f 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -31,6 +31,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #14772: Return destination values from some shutil functions.
+
 - Issue #15064: Implement context manager protocol for multiprocessing types
 
 - Issue #15101: Make pool finalizer avoid joining current thread.