Skip to content

Commit e08eb83

Browse files
committed
[3.8] bpo-39390 shutil: fix argument types for ignore callback (GH-18122).
(cherry picked from commit 8870433) Co-authored-by: mbarkhau <[email protected]>
1 parent 0ea7309 commit e08eb83

File tree

4 files changed

+52
-1
lines changed

4 files changed

+52
-1
lines changed

Doc/whatsnew/3.8.rst

+7
Original file line numberDiff line numberDiff line change
@@ -2216,3 +2216,10 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more
22162216
details, see the documentation for ``loop.create_datagram_endpoint()``.
22172217
(Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in
22182218
:issue:`37228`.)
2219+
2220+
Notable changes in Python 3.8.2
2221+
===============================
2222+
2223+
Fixed a regression with the ``ignore`` callback of :func:`shutil.copytree`.
2224+
The argument types are now str and List[str] again.
2225+
(Contributed by Manuel Barkhau and Giampaolo Rodola in :issue:`39390`.)

Lib/shutil.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def _ignore_patterns(path, names):
442442
def _copytree(entries, src, dst, symlinks, ignore, copy_function,
443443
ignore_dangling_symlinks, dirs_exist_ok=False):
444444
if ignore is not None:
445-
ignored_names = ignore(src, {x.name for x in entries})
445+
ignored_names = ignore(os.fspath(src), [x.name for x in entries])
446446
else:
447447
ignored_names = set()
448448

Lib/test/test_shutil.py

+42
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,48 @@ def _filter(src, names):
880880
shutil.rmtree(src_dir)
881881
shutil.rmtree(os.path.dirname(dst_dir))
882882

883+
def test_copytree_arg_types_of_ignore(self):
884+
join = os.path.join
885+
exists = os.path.exists
886+
887+
tmp_dir = self.mkdtemp()
888+
src_dir = join(tmp_dir, "source")
889+
890+
os.mkdir(join(src_dir))
891+
os.mkdir(join(src_dir, 'test_dir'))
892+
os.mkdir(os.path.join(src_dir, 'test_dir', 'subdir'))
893+
write_file((src_dir, 'test_dir', 'subdir', 'test.txt'), '456')
894+
895+
invokations = []
896+
897+
def _ignore(src, names):
898+
invokations.append(src)
899+
self.assertIsInstance(src, str)
900+
self.assertIsInstance(names, list)
901+
self.assertEqual(len(names), len(set(names)))
902+
for name in names:
903+
self.assertIsInstance(name, str)
904+
return []
905+
906+
dst_dir = join(self.mkdtemp(), 'destination')
907+
shutil.copytree(src_dir, dst_dir, ignore=_ignore)
908+
self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
909+
'test.txt')))
910+
911+
dst_dir = join(self.mkdtemp(), 'destination')
912+
shutil.copytree(pathlib.Path(src_dir), dst_dir, ignore=_ignore)
913+
self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
914+
'test.txt')))
915+
916+
dst_dir = join(self.mkdtemp(), 'destination')
917+
src_dir_entry = list(os.scandir(tmp_dir))[0]
918+
self.assertIsInstance(src_dir_entry, os.DirEntry)
919+
shutil.copytree(src_dir_entry, dst_dir, ignore=_ignore)
920+
self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
921+
'test.txt')))
922+
923+
self.assertEqual(len(invokations), 9)
924+
883925
def test_copytree_retains_permissions(self):
884926
tmp_dir = tempfile.mkdtemp()
885927
src_dir = os.path.join(tmp_dir, 'source')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed a regression with the `ignore` callback of :func:`shutil.copytree`.
2+
The argument types are now str and List[str] again.

0 commit comments

Comments
 (0)