Issue 32073: Add copy_directory_metadata parameter to shutil.copytree (original) (raw)
I am sometimes using shutil.copytree to copy a directory to a destination that does not support setting metadata (like MTP mounts of Android devices).
Using the copy_function parameter allows passing shutil.copy or a custom function to ignore file metadata, however currently shutil.copytree always tries to call copystat on directories, which can fail with OSError (errno set to ENOTSUPP).
The code assumes copystat can fail on Windows, but propagates the error on other OS, even though the tree copy actually succeeds. See https://github.com/python/cpython/blob/9bb6fe52742340f6c92f0dda18599a4577a94e18/Lib/shutil.py#L352-L357
Traceback is not very useful in that case:
mkdir /tmp/a touch /tmp/a/b
python Python 3.6.6 (default, Jun 27 2018, 13:11:40) [GCC 8.1.1 20180531] on linux Type "help", "copyright", "credits" or "license" for more information.
import os, shutil os.getcwd() '/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C006%5D/sdcard1' shutil.copytree("/tmp/a", os.path.join(os.getcwd(), "test")) Traceback (most recent call last): File "", line 1, in File "/home/desbma/py-venvs/main/lib/python3.6/shutil.py", line 359, in copytree raise Error(errors) shutil.Error: [('/tmp/a/b', '/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C006%5D/sdcard1/test/b', '[Errno 95] Operation not supported'), ('/tmp/a', '/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C006%5D/sdcard1/test', '[Errno 95] Operation not supported')] shutil.copytree("/tmp/a", os.path.join(os.getcwd(), "test2"), copy_function=shutil.copy) Traceback (most recent call last): File "", line 1, in File "/home/desbma/py-venvs/main/lib/python3.6/shutil.py", line 359, in copytree raise Error(errors) shutil.Error: [('/tmp/a/b', '/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C006%5D/sdcard1/test2/b', "[Errno 95] Operation not supported: '/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C006%5D/sdcard1/test2/b'"), ('/tmp/a', '/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C006%5D/sdcard1/test2', '[Errno 95] Operation not supported')]
The exception is thrown from here https://github.com/python/cpython/blob/9bb6fe52742340f6c92f0dda18599a4577a94e18/Lib/shutil.py#L359