Patch by Claudiu Popa.
match one of the glob-style *patterns* provided. See the example below.
-.. function:: copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False)
+.. function:: copytree(src, dst, symlinks=False, ignore=None, \
+ copy_function=copy2, ignore_dangling_symlinks=False)
Recursively copy an entire directory tree rooted at *src*, returning the
destination directory. The destination
.. versionadded:: 3.3
-.. function:: move(src, dst)
+.. function:: move(src, dst, copy_function=copy2)
Recursively move a file or directory (*src*) to another location (*dst*)
and return the destination.
:func:`os.rename` semantics.
If the destination is on the current filesystem, then :func:`os.rename` is
- used. Otherwise, *src* is copied (using :func:`shutil.copy2`) to *dst* and
- then removed. In case of symlinks, a new symlink pointing to the target of
- *src* will be created in or as *dst* and *src* will be removed.
+ used. Otherwise, *src* is copied to *dst* using *copy_function* and then
+ removed. In case of symlinks, a new symlink pointing to the target of *src*
+ will be created in or as *dst* and *src* will be removed.
+
+ If *copy_function* is given, it must be a callable that takes two arguments
+ *src* and *dst*, and will be used to copy *src* to *dest* if
+ :func:`os.rename` cannot be used. If the source is a directory,
+ :func:`copytree` is called, passing it the :func:`copy_function`. The
+ default *copy_function* is :func:`copy2`. Using :func:`copy` as the
+ *copy_function* allows the move to succeed when it is not possible to also
+ copy the metadata, at the expense of not copying any of the metadata.
.. versionchanged:: 3.3
Added explicit symlink handling for foreign filesystems, thus adapting
it to the behavior of GNU's :program:`mv`.
Now returns *dst*.
+ .. versionchanged:: 3.5
+ Added the *copy_function* keyword argument.
+
.. function:: disk_usage(path)
Return disk usage statistics about the given path as a :term:`named tuple`
network objects from existing addresses (contributed by Peter Moody
and Antoine Pitrou in :issue:`16531`).
+shutil
+------
+
+* :func:`~shutil.move` now accepts a *copy_function* argument, allowing,
+ for example, :func:`~shutil.copy` to be used instead of the default
+ :func:`~shutil.copy2` if there is a need to ignore metadata. (Contributed by
+ Claudiu Popa in :issue:`19840`.)
+
signal
------
sep = os.path.sep + (os.path.altsep or '')
return os.path.basename(path.rstrip(sep))
-def move(src, dst):
+def move(src, dst, copy_function=copy2):
"""Recursively move a file or directory to another location. This is
similar to the Unix "mv" command. Return the file or directory's
destination.
recreated under the new name if os.rename() fails because of cross
filesystem renames.
+ The optional `copy_function` argument is a callable that will be used
+ to copy the source or it will be delegated to `copytree`.
+ By default, copy2() is used, but any function that supports the same
+ signature (like copy()) can be used.
+
A lot more could be done here... A look at a mv.c shows a lot of
the issues this implementation glosses over.
os.unlink(src)
elif os.path.isdir(src):
if _destinsrc(src, dst):
- raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
- copytree(src, real_dst, symlinks=True)
+ raise Error("Cannot move a directory '%s' into itself"
+ " '%s'." % (src, dst))
+ copytree(src, real_dst, copy_function=copy_function,
+ symlinks=True)
rmtree(src)
else:
- copy2(src, real_dst)
+ copy_function(src, real_dst)
os.unlink(src)
return real_dst
rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
+ @mock_rename
+ def test_move_file_special_function(self):
+ moved = []
+ def _copy(src, dst):
+ moved.append((src, dst))
+ shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
+ self.assertEqual(len(moved), 1)
+
+ @mock_rename
+ def test_move_dir_special_function(self):
+ moved = []
+ def _copy(src, dst):
+ moved.append((src, dst))
+ support.create_empty_file(os.path.join(self.src_dir, 'child'))
+ support.create_empty_file(os.path.join(self.src_dir, 'child1'))
+ shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
+ self.assertEqual(len(moved), 3)
+
class TestCopyFile(unittest.TestCase):