]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-79325: Fix recursion error in TemporaryDirectory cleanup on Windows (GH-112762)
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 7 Dec 2023 17:21:36 +0000 (19:21 +0200)
committerGitHub <noreply@github.com>
Thu, 7 Dec 2023 17:21:36 +0000 (17:21 +0000)
Lib/tempfile.py
Lib/test/test_tempfile.py
Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst [new file with mode: 0644]

index 4d99f91e1f53b7db4e5127cc84d8d1361bac282a..cbfc172a789b2519b62e98b7c48b65158cf77818 100644 (file)
@@ -888,9 +888,14 @@ class TemporaryDirectory:
             ignore_errors=self._ignore_cleanup_errors, delete=self._delete)
 
     @classmethod
-    def _rmtree(cls, name, ignore_errors=False):
+    def _rmtree(cls, name, ignore_errors=False, repeated=False):
         def onexc(func, path, exc):
             if isinstance(exc, PermissionError):
+                if repeated and path == name:
+                    if ignore_errors:
+                        return
+                    raise
+
                 try:
                     if path != name:
                         _resetperms(_os.path.dirname(path))
@@ -912,7 +917,8 @@ class TemporaryDirectory:
                             if ignore_errors:
                                 return
                             raise
-                        cls._rmtree(path, ignore_errors=ignore_errors)
+                        cls._rmtree(path, ignore_errors=ignore_errors,
+                                    repeated=(path == name))
                 except FileNotFoundError:
                     pass
             elif isinstance(exc, FileNotFoundError):
index 2729bec7a21c71d209a577b5d5347a2c4bf4a3c1..b64b6a4f2baeb571eef8d90de9d68e98e235af7a 100644 (file)
@@ -1651,6 +1651,17 @@ class TestTemporaryDirectory(BaseTestCase):
                 with self.assertRaises(PermissionError):
                     temp_dir.cleanup()
 
+    @unittest.skipUnless(os.name == "nt", "Only on Windows.")
+    def test_cleanup_with_used_directory(self):
+        with tempfile.TemporaryDirectory() as working_dir:
+            temp_dir = self.do_create(dir=working_dir)
+            subdir = os.path.join(temp_dir.name, "subdir")
+            os.mkdir(subdir)
+            with os_helper.change_cwd(subdir):
+                # Previously raised RecursionError on some OSes
+                # (e.g. Windows). See bpo-35144.
+                with self.assertRaises(PermissionError):
+                    temp_dir.cleanup()
 
     @os_helper.skip_unless_symlink
     def test_cleanup_with_symlink_to_a_directory(self):
diff --git a/Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst b/Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst
new file mode 100644 (file)
index 0000000..f3c32d2
--- /dev/null
@@ -0,0 +1,2 @@
+Fix an infinite recursion error in :func:`tempfile.TemporaryDirectory`
+cleanup on Windows.