IronPython appears to lose frames from within the thread, where they are retained in CPython
(May be duplicate of #738 , or perhaps just related, but it seemed worth submitting the tests.)
Minimal repro.
import functools
import sys
import threading
import traceback
import unittest
print(sys.version)
class AsyncTask(object):
def __init__(self, func):
functools.wraps(func)(self)
self._func = func
self._result = None
self._exception = None
def __call__(self, *args, **kwargs):
self._thread = threading.Thread(target=self._run, args=args, kwargs=kwargs)
self._thread.start()
return self
def _run(self, *args, **kwargs):
try:
self._result = self._func(*args, **kwargs)
except Exception as err:
self._exception = err
finally:
self._complete = True
@property
def result(self):
if self._thread is None:
raise RuntimeError("Not started.")
self._thread.join()
if self._exception is not None:
raise self._exception
return self._result
def await_task(self, timeout=None):
if self._thread is None:
raise RuntimeError("Not started.")
self._thread.join(timeout)
completed = not self._thread.is_alive()
if completed and self._exception is not None:
raise self._exception
return completed
def module_level_raising_function(exc):
raise exc
class TestAsyncTaskException(unittest.TestCase):
def test_with_function_scoped_def(self):
def raising_function(exc):
raise exc
return self._test(raising_function)
def test_with_module_scoped_def(self):
self._test(module_level_raising_function)
def _test(self, raising_func):
the_exception = Exception('the exception message')
task = AsyncTask(raising_func)(the_exception)
caught_exception = None
try:
task.result
except Exception as caught_exception:
etype, evalue, etb = sys.exc_info()
trace = traceback.extract_tb(etb)
self.assertIs(caught_exception, the_exception)
print("\nTraceback for {}:\n{}".format(self._testMethodName, '\n'.join(traceback.format_tb(etb))))
(filenames, line_numbers, function_names, texts) = zip(*trace)
self.assertIn(raising_func.__name__, function_names)
else:
self.fail("Exception not raised.")
if __name__ == '__main__':
unittest.main()
Expected result - CPython 3.4
3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:24:06) [MSC v.1600 32 bit (Intel)]
Traceback for test_with_function_scoped_def:
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 68, in _test
task.result
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 36, in result
raise self._exception
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 24, in _run
self._result = self._func(*args, **kwargs)
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 56, in raising_function
raise exc
.
Traceback for test_with_module_scoped_def:
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 68, in _test
task.result
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 36, in result
raise self._exception
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 24, in _run
self._result = self._func(*args, **kwargs)
File "C:\Users\michael.phillips\repos\AsyncTask\minrepro.py", line 50, in module_level_raising_function
raise exc
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Observed result - IronPython 3.4
[.NETFramework,Version=v4.6.2 on .NET Framework 4.8.9324.0 (64-bit)]
Traceback for test_with_function_scoped_def:
File ".\minrepro.py", line 68, in _test
task.result
File ".\minrepro.py", line 36, in result
raise self._exception
F
Traceback for test_with_module_scoped_def:
File ".\minrepro.py", line 68, in _test
task.result
File ".\minrepro.py", line 36, in result
raise self._exception
F
======================================================================
FAIL: test_with_function_scoped_def (minrepro.TestAsyncTaskException)
----------------------------------------------------------------------
Traceback (most recent call last):
File ".\minrepro.py", line 58, in test_with_function_scoped_def
return self._test(raising_function)
File ".\minrepro.py", line 77, in _test
self.assertIn(raising_func.__name__, function_names)
AssertionError: 'raising_function' not found in ('_test', 'result')
======================================================================
FAIL: test_with_module_scoped_def (minrepro.TestAsyncTaskException)
----------------------------------------------------------------------
Traceback (most recent call last):
File ".\minrepro.py", line 61, in test_with_module_scoped_def
self._test(module_level_raising_function)
File ".\minrepro.py", line 77, in _test
self.assertIn(raising_func.__name__, function_names)
AssertionError: 'module_level_raising_function' not found in ('_test', 'result')
----------------------------------------------------------------------
Ran 2 tests in 0.620s
FAILED (failures=2)
IronPython appears to lose frames from within the thread, where they are retained in CPython
(May be duplicate of #738 , or perhaps just related, but it seemed worth submitting the tests.)
Minimal repro.
Expected result - CPython 3.4
Observed result - IronPython 3.4