mirror of
https://github.com/python/cpython.git
synced 2024-11-27 03:45:08 +08:00
Fix #14772: Return the destination from some shutil functions.
This commit is contained in:
parent
e75ff35af2
commit
0d0a1dedbc
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user