https://github.com/python/cpython/commit/8f6b0afd401673c47c15e30947244b0fab4291b2 commit: 8f6b0afd401673c47c15e30947244b0fab4291b2 branch: 3.13 author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com> committer: picnixz <10796600+picn...@users.noreply.github.com> date: 2025-04-08T15:36:52Z summary:
[3.13] gh-132063: ensure that `ProcessPoolExecutor` does not swallow falsey exceptions (GH-132129) (#132275) gh-132063: ensure that `ProcessPoolExecutor` does not swallow falsey exceptions (GH-132129) (cherry picked from commit 933c6653cba235b3af2250bb19713694b560c367) Co-authored-by: Duprat <ydup...@gmail.com> files: A Misc/NEWS.d/next/Library/2025-04-05-15-05-09.gh-issue-132063.KHnslU.rst M Lib/concurrent/futures/_base.py M Lib/concurrent/futures/process.py M Lib/test/test_concurrent_futures/executor.py diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index 6742a07753c921..7d69a5baead428 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -396,7 +396,7 @@ def done(self): 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: diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index d73ef716134175..cb0b8be55ecced 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -440,7 +440,7 @@ def process_result_item(self, result_item): 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) diff --git a/Lib/test/test_concurrent_futures/executor.py b/Lib/test/test_concurrent_futures/executor.py index 3d1372a6428ec0..7442d3bee52ed8 100644 --- a/Lib/test/test_concurrent_futures/executor.py +++ b/Lib/test/test_concurrent_futures/executor.py @@ -23,6 +23,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 # ExecutorShutdownTest. @@ -132,3 +147,16 @@ def test_free_reference(self): 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 index 00000000000000..d3761759772d03 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-05-15-05-09.gh-issue-132063.KHnslU.rst @@ -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`. _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com