summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZackery Spytz <zspytz@gmail.com>2022-11-07 11:45:16 (GMT)
committerGitHub <noreply@github.com>2022-11-07 11:45:16 (GMT)
commit5ff81da6d3a8eb01fc5500fd1c9eaa6543286301 (patch)
treed53d1f869765652d672f55999cf500acb660e42a
parentcfec5b18bf4af9813ac3d83c5489469af4844708 (diff)
downloadcpython-5ff81da6d3a8eb01fc5500fd1c9eaa6543286301.zip
cpython-5ff81da6d3a8eb01fc5500fd1c9eaa6543286301.tar.gz
cpython-5ff81da6d3a8eb01fc5500fd1c9eaa6543286301.tar.bz2
bpo-38523: ignore_dangling_symlinks does not apply recursively (GH-22937)
-rw-r--r--Lib/shutil.py5
-rw-r--r--Lib/test/test_shutil.py19
-rw-r--r--Misc/NEWS.d/next/Library/2020-10-23-22-20-52.bpo-38523.CrkxLh.rst2
3 files changed, 18 insertions, 8 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py
index ac1dd53..f5687e3 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -490,12 +490,13 @@ def _copytree(entries, src, dst, symlinks, ignore, copy_function,
# otherwise let the copy occur. copy2 will raise an error
if srcentry.is_dir():
copytree(srcobj, dstname, symlinks, ignore,
- copy_function, dirs_exist_ok=dirs_exist_ok)
+ copy_function, ignore_dangling_symlinks,
+ dirs_exist_ok)
else:
copy_function(srcobj, dstname)
elif srcentry.is_dir():
copytree(srcobj, dstname, symlinks, ignore, copy_function,
- dirs_exist_ok=dirs_exist_ok)
+ ignore_dangling_symlinks, dirs_exist_ok)
else:
# Will raise a SpecialFileError for unsupported file types
copy_function(srcobj, dstname)
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 6789fe4..8fe6221 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -752,18 +752,25 @@ class TestCopyTree(BaseTest, unittest.TestCase):
@os_helper.skip_unless_symlink
def test_copytree_dangling_symlinks(self):
- # a dangling symlink raises an error at the end
src_dir = self.mkdtemp()
+ valid_file = os.path.join(src_dir, 'test.txt')
+ write_file(valid_file, 'abc')
+ dir_a = os.path.join(src_dir, 'dir_a')
+ os.mkdir(dir_a)
+ for d in src_dir, dir_a:
+ os.symlink('IDONTEXIST', os.path.join(d, 'broken'))
+ os.symlink(valid_file, os.path.join(d, 'valid'))
+
+ # A dangling symlink should raise an error.
dst_dir = os.path.join(self.mkdtemp(), 'destination')
- os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
- os.mkdir(os.path.join(src_dir, 'test_dir'))
- write_file((src_dir, 'test_dir', 'test.txt'), '456')
self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
- # a dangling symlink is ignored with the proper flag
+ # Dangling symlinks should be ignored with the proper flag.
dst_dir = os.path.join(self.mkdtemp(), 'destination2')
shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
- self.assertNotIn('test.txt', os.listdir(dst_dir))
+ for root, dirs, files in os.walk(dst_dir):
+ self.assertNotIn('broken', files)
+ self.assertIn('valid', files)
# a dangling symlink is copied if symlinks=True
dst_dir = os.path.join(self.mkdtemp(), 'destination3')
diff --git a/Misc/NEWS.d/next/Library/2020-10-23-22-20-52.bpo-38523.CrkxLh.rst b/Misc/NEWS.d/next/Library/2020-10-23-22-20-52.bpo-38523.CrkxLh.rst
new file mode 100644
index 0000000..3810e29
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-10-23-22-20-52.bpo-38523.CrkxLh.rst
@@ -0,0 +1,2 @@
+:func:`shutil.copytree` now applies the *ignore_dangling_symlinks* argument
+recursively.