]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.8] bpo-39390 shutil: fix argument types for ignore callback (GH-18122)
authormbarkhau <mbarkhau@gmail.com>
Mon, 27 Jan 2020 23:46:29 +0000 (23:46 +0000)
committerGiampaolo Rodola <g.rodola@gmail.com>
Mon, 27 Jan 2020 23:46:29 +0000 (00:46 +0100)
Doc/whatsnew/3.8.rst
Lib/shutil.py
Lib/test/test_shutil.py
Misc/NEWS.d/next/Library/2020-01-23-21-34-29.bpo-39390.D2tSXk.rst [new file with mode: 0644]

index 7bc91a9fc19bf5bd77471c6039d7d5570da5cbca..007e3228f9ae6d12ba8149ab57691818904dc78b 100644 (file)
@@ -2216,3 +2216,10 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more
 details, see the documentation for ``loop.create_datagram_endpoint()``.
 (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in
 :issue:`37228`.)
+
+Notable changes in Python 3.8.2
+===============================
+
+Fixed a regression with the ``ignore`` callback of :func:`shutil.copytree`.
+The argument types are now str and List[str] again.
+(Contributed by Manuel Barkhau and Giampaolo Rodola in :issue:`39390`.)
index 755ce392e6d9ae09f8f8a311f12b6414159687b2..cde7b860050a26ec86c8843e13c548a748ef0475 100644 (file)
@@ -442,7 +442,7 @@ def ignore_patterns(*patterns):
 def _copytree(entries, src, dst, symlinks, ignore, copy_function,
               ignore_dangling_symlinks, dirs_exist_ok=False):
     if ignore is not None:
-        ignored_names = ignore(src, {x.name for x in entries})
+        ignored_names = ignore(os.fspath(src), [x.name for x in entries])
     else:
         ignored_names = set()
 
index 286e333a8aa9cdfe8a9265bcf727fe76a3aea452..bcb7e498e198e25479cec743624cf34bba2c8033 100644 (file)
@@ -880,6 +880,48 @@ class TestShutil(unittest.TestCase):
             shutil.rmtree(src_dir)
             shutil.rmtree(os.path.dirname(dst_dir))
 
+    def test_copytree_arg_types_of_ignore(self):
+        join = os.path.join
+        exists = os.path.exists
+
+        tmp_dir = self.mkdtemp()
+        src_dir = join(tmp_dir, "source")
+
+        os.mkdir(join(src_dir))
+        os.mkdir(join(src_dir, 'test_dir'))
+        os.mkdir(os.path.join(src_dir, 'test_dir', 'subdir'))
+        write_file((src_dir, 'test_dir', 'subdir', 'test.txt'), '456')
+
+        invokations = []
+
+        def _ignore(src, names):
+            invokations.append(src)
+            self.assertIsInstance(src, str)
+            self.assertIsInstance(names, list)
+            self.assertEqual(len(names), len(set(names)))
+            for name in names:
+                self.assertIsInstance(name, str)
+            return []
+
+        dst_dir = join(self.mkdtemp(), 'destination')
+        shutil.copytree(src_dir, dst_dir, ignore=_ignore)
+        self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
+                                    'test.txt')))
+
+        dst_dir = join(self.mkdtemp(), 'destination')
+        shutil.copytree(pathlib.Path(src_dir), dst_dir, ignore=_ignore)
+        self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
+                                    'test.txt')))
+
+        dst_dir = join(self.mkdtemp(), 'destination')
+        src_dir_entry = list(os.scandir(tmp_dir))[0]
+        self.assertIsInstance(src_dir_entry, os.DirEntry)
+        shutil.copytree(src_dir_entry, dst_dir, ignore=_ignore)
+        self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
+                                    'test.txt')))
+
+        self.assertEqual(len(invokations), 9)
+
     def test_copytree_retains_permissions(self):
         tmp_dir = tempfile.mkdtemp()
         src_dir = os.path.join(tmp_dir, 'source')
diff --git a/Misc/NEWS.d/next/Library/2020-01-23-21-34-29.bpo-39390.D2tSXk.rst b/Misc/NEWS.d/next/Library/2020-01-23-21-34-29.bpo-39390.D2tSXk.rst
new file mode 100644 (file)
index 0000000..ffa961e
--- /dev/null
@@ -0,0 +1,2 @@
+Fixed a regression with the `ignore` callback of :func:`shutil.copytree`.
+The argument types are now str and List[str] again.