]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117459: Keep the traceback in _convert_future_exc (#117460)
authorrsp4jack <rsp4jack@outlook.com>
Thu, 4 Apr 2024 03:13:32 +0000 (11:13 +0800)
committerGitHub <noreply@github.com>
Thu, 4 Apr 2024 03:13:32 +0000 (20:13 -0700)
Lib/asyncio/futures.py
Lib/test/test_asyncio/test_futures.py
Misc/NEWS.d/next/Library/2024-04-02-13-13-46.gh-issue-117459.jiIZmH.rst [new file with mode: 0644]

index 5d35321db7943b0f8f1a01bc62b44d188b82a985..9c1b5e49e1a70be61881f95a3c4bde51c629471a 100644 (file)
@@ -319,11 +319,9 @@ def _set_result_unless_cancelled(fut, result):
 def _convert_future_exc(exc):
     exc_class = type(exc)
     if exc_class is concurrent.futures.CancelledError:
-        return exceptions.CancelledError(*exc.args)
-    elif exc_class is concurrent.futures.TimeoutError:
-        return exceptions.TimeoutError(*exc.args)
+        return exceptions.CancelledError(*exc.args).with_traceback(exc.__traceback__)
     elif exc_class is concurrent.futures.InvalidStateError:
-        return exceptions.InvalidStateError(*exc.args)
+        return exceptions.InvalidStateError(*exc.args).with_traceback(exc.__traceback__)
     else:
         return exc
 
index d3e8efec1c04c2baddc50cd99cae0df423c2ead5..458b70451a306a869bee1f70d5e4baa918bb3a4e 100644 (file)
@@ -5,6 +5,7 @@ import gc
 import re
 import sys
 import threading
+import traceback
 import unittest
 from unittest import mock
 from types import GenericAlias
@@ -416,6 +417,24 @@ class BaseFutureTests:
         _copy_future_state(f_cancelled, newf_cancelled)
         self.assertTrue(newf_cancelled.cancelled())
 
+        try:
+            raise concurrent.futures.InvalidStateError
+        except BaseException as e:
+            f_exc = e
+
+        f_conexc = self._new_future(loop=self.loop)
+        f_conexc.set_exception(f_exc)
+
+        newf_conexc = self._new_future(loop=self.loop)
+        _copy_future_state(f_conexc, newf_conexc)
+        self.assertTrue(newf_conexc.done())
+        try:
+            newf_conexc.result()
+        except BaseException as e:
+            newf_exc = e # assertRaises context manager drops the traceback
+        newf_tb = ''.join(traceback.format_tb(newf_exc.__traceback__))
+        self.assertEqual(newf_tb.count('raise concurrent.futures.InvalidStateError'), 1)
+
     def test_iter(self):
         fut = self._new_future(loop=self.loop)
 
diff --git a/Misc/NEWS.d/next/Library/2024-04-02-13-13-46.gh-issue-117459.jiIZmH.rst b/Misc/NEWS.d/next/Library/2024-04-02-13-13-46.gh-issue-117459.jiIZmH.rst
new file mode 100644 (file)
index 0000000..549bd44
--- /dev/null
@@ -0,0 +1 @@
+:meth:`asyncio.asyncio.run_coroutine_threadsafe` now keeps the traceback of :class:`CancelledError`, :class:`TimeoutError` and :class:`InvalidStateError` which are raised in the coroutine.