diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 5d267481041e907..289ad2870136fba 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -207,7 +207,7 @@ def _process_chunk(fn, chunk): try: result = (fn(*args), None) except BaseException as exc: - result = (None, exc) + result = (None, _ExceptionWithTraceback(exc, exc.__traceback__)) results.append(result) return results diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index dafbda862c51c24..9ea959f88d80d16 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -14,7 +14,7 @@ from test.support import hashlib_helper, threading_helper, warnings_helper from test.test_importlib.metadata.fixtures import parameterize -from .executor import ExecutorTest, mul +from .executor import ExecutorTest, mul, raiser from .util import ( ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin, create_executor_tests, setup_module) @@ -141,6 +141,16 @@ def test_traceback(self): self.assertIn('raise RuntimeError(123) # some comment', f1.getvalue()) + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() + def test_map_traceback(self): + # The traceback from the child process is also kept for map(). + i = self.executor.map(raiser, [RuntimeError]) + with self.assertRaises(RuntimeError) as cm: + next(i) + cause = cm.exception.__cause__ + self.assertIs(type(cause), futures.process._RemoteTraceback) + self.assertIn('raise exception(msg)', cause.tb) + def test_traceback_when_child_process_terminates_abruptly(self): # gh-139462 enhancement - BrokenProcessPool exceptions # should describe which process terminated. diff --git a/Misc/NEWS.d/next/Library/2026-11-03-17-53-17.gh-issue-158497.gqFmXJ.rst b/Misc/NEWS.d/next/Library/2026-11-03-17-53-17.gh-issue-158497.gqFmXJ.rst new file mode 100644 index 000000000000000..5b596284bf406d6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-11-03-17-53-17.gh-issue-158497.gqFmXJ.rst @@ -0,0 +1,3 @@ +Fix :meth:`Executor.map() ` of a +:class:`~concurrent.futures.ProcessPoolExecutor` losing the traceback of an +exception raised in a worker process.