]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132063: ensure that `ProcessPoolExecutor` does not swallow falsey exceptions ...
authorDuprat <yduprat@gmail.com>
Tue, 8 Apr 2025 15:11:13 +0000 (17:11 +0200)
committerGitHub <noreply@github.com>
Tue, 8 Apr 2025 15:11:13 +0000 (15:11 +0000)
Lib/concurrent/futures/_base.py
Lib/concurrent/futures/process.py
Lib/test/test_concurrent_futures/executor.py
Misc/NEWS.d/next/Library/2025-04-05-15-05-09.gh-issue-132063.KHnslU.rst [new file with mode: 0644]

index d5ba39e3d7177482f411ff3f3132fd8fc40797d3..d98b1ebdd584b5a331c4925c5d80fbb2e1dc9552 100644 (file)
@@ -390,7 +390,7 @@ class Future(object):
             return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]
 
     def __get_result(self):
-        if self._exception:
+        if self._exception is not None:
             try:
                 raise self._exception
             finally:
index 4847550908adab7de81ca9b67b66a38402b5a5fb..76b7b2abe836d8265481d8258a84afb9cffc622d 100644 (file)
@@ -440,7 +440,7 @@ class _ExecutorManagerThread(threading.Thread):
         work_item = self.pending_work_items.pop(result_item.work_id, None)
         # work_item can be None if another process terminated (see above)
         if work_item is not None:
-            if result_item.exception:
+            if result_item.exception is not None:
                 work_item.future.set_exception(result_item.exception)
             else:
                 work_item.future.set_result(result_item.result)
index d88c34d1c8c8e4d14109fc35a821aaa72d886b33..95bf8fcd25bf54bd03185ea35876092e0ff183a6 100644 (file)
@@ -24,6 +24,21 @@ def make_dummy_object(_):
     return MyObject()
 
 
+# Used in test_swallows_falsey_exceptions
+def raiser(exception, msg='std'):
+    raise exception(msg)
+
+
+class FalseyBoolException(Exception):
+    def __bool__(self):
+        return False
+
+
+class FalseyLenException(Exception):
+    def __len__(self):
+        return 0
+
+
 class ExecutorTest:
 
     # Executor.shutdown() and context manager usage is tested by
@@ -205,3 +220,16 @@ class ExecutorTest:
             for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
                 if wr() is None:
                     break
+
+    def test_swallows_falsey_exceptions(self):
+        # see gh-132063: Prevent exceptions that evaluate as falsey
+        # from being ignored.
+        # Recall: `x` is falsey if `len(x)` returns 0 or `bool(x)` returns False.
+
+        msg = 'boolbool'
+        with self.assertRaisesRegex(FalseyBoolException, msg):
+            self.executor.submit(raiser, FalseyBoolException, msg).result()
+
+        msg = 'lenlen'
+        with self.assertRaisesRegex(FalseyLenException, msg):
+            self.executor.submit(raiser, FalseyLenException, msg).result()
diff --git a/Misc/NEWS.d/next/Library/2025-04-05-15-05-09.gh-issue-132063.KHnslU.rst b/Misc/NEWS.d/next/Library/2025-04-05-15-05-09.gh-issue-132063.KHnslU.rst
new file mode 100644 (file)
index 0000000..d376175
--- /dev/null
@@ -0,0 +1,2 @@
+Prevent exceptions that evaluate as falsey (namely, when their ``__bool__`` method returns ``False`` or their ``__len__`` method returns 0)
+from being ignored by :class:`concurrent.futures.ProcessPoolExecutor` and :class:`concurrent.futures.ThreadPoolExecutor`.