Commit 591ec3a9 authored by Berker Peksag's avatar Berker Peksag

Issue #21697: shutil.copytree() now correctly handles symbolic links that point to directories.

Patch by Eduardo Seabra and Thomas Kluyver.
parent daf14ad2
...@@ -321,6 +321,10 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ...@@ -321,6 +321,10 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
if not os.path.exists(linkto) and ignore_dangling_symlinks: if not os.path.exists(linkto) and ignore_dangling_symlinks:
continue continue
# otherwise let the copy occurs. copy2 will raise an error # otherwise let the copy occurs. copy2 will raise an error
if os.path.isdir(srcname):
copytree(srcname, dstname, symlinks, ignore,
copy_function)
else:
copy_function(srcname, dstname) copy_function(srcname, dstname)
elif os.path.isdir(srcname): elif os.path.isdir(srcname):
copytree(srcname, dstname, symlinks, ignore, copy_function) copytree(srcname, dstname, symlinks, ignore, copy_function)
......
...@@ -895,6 +895,26 @@ class TestShutil(unittest.TestCase): ...@@ -895,6 +895,26 @@ class TestShutil(unittest.TestCase):
shutil.copytree(src_dir, dst_dir, symlinks=True) shutil.copytree(src_dir, dst_dir, symlinks=True)
self.assertIn('test.txt', os.listdir(dst_dir)) self.assertIn('test.txt', os.listdir(dst_dir))
@support.skip_unless_symlink
def test_copytree_symlink_dir(self):
src_dir = self.mkdtemp()
dst_dir = os.path.join(self.mkdtemp(), 'destination')
os.mkdir(os.path.join(src_dir, 'real_dir'))
with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
pass
os.symlink(os.path.join(src_dir, 'real_dir'),
os.path.join(src_dir, 'link_to_dir'),
target_is_directory=True)
shutil.copytree(src_dir, dst_dir, symlinks=False)
self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
dst_dir = os.path.join(self.mkdtemp(), 'destination2')
shutil.copytree(src_dir, dst_dir, symlinks=True)
self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
def _copy_file(self, method): def _copy_file(self, method):
fname = 'test.txt' fname = 'test.txt'
tmpdir = self.mkdtemp() tmpdir = self.mkdtemp()
......
...@@ -66,6 +66,9 @@ Core and Builtins ...@@ -66,6 +66,9 @@ Core and Builtins
Library Library
------- -------
- Issue #21697: shutil.copytree() now correctly handles symbolic links that
point to directories. Patch by Eduardo Seabra and Thomas Kluyver.
- Issue #24620: Random.setstate() now validates the value of state last element. - Issue #24620: Random.setstate() now validates the value of state last element.
- Issue #22153: Improve unittest docs. Patch from Martin Panter and evilzero. - Issue #22153: Improve unittest docs. Patch from Martin Panter and evilzero.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment