New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AsyncExitStack.enter_async_context() is mishandling exception __context__ #88760
Comments
Over at the Trio project, we have evidence that The symptom is a very long, unhelpful tracebacks because the __context__ of raised exceptions is not set to the expected object. I can't speak to this solution myself, but njsmith suggests this amendment to contextlib: saved_context = exc_details[1].__context__
try:
raise exc_details[1]
finally:
exc_details[1].__context__ = saved_context |
demonstrating the difference for async case: import contextlib
import trio
async def background():
assert False
async def main1():
async with trio.open_nursery() as nursery:
nursery.start_soon(background)
await trio.sleep_forever()
async def main2():
async with contextlib.AsyncExitStack() as stack:
nursery = await stack.enter_async_context(trio.open_nursery())
nursery.start_soon(background)
await trio.sleep_forever()
try:
trio.run(main1)
except BaseException as e:
print('main1, context:', e.__context__)
try:
trio.run(main2)
except BaseException as e:
print('main2, context:', e.__context__) main1, context: None |
To clarify the problem case, I believe the discrepancy is seen when raising exceptions as follows: exc = foo()
try:
raise exc
finally:
exc.__context__ = None (From my understanding, Trio has valid use cases for doing this since it wants to control complex exception chaining, and this is beyond the scope of __suppress_context__.) Neither ExitStack nor AsyncExcitStack are preserving the None context in the case above. === Traceback (most recent call last):
File "exit_stack_test.py", line 251, in <module>
assert False
File "/.../python3.7/contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "exit_stack_test.py", line 244, in my_cm
raise exc
MyException === enter_context() === Traceback (most recent call last):
File "exit_stack_test.py", line 240, in my_cm
yield
File "exit_stack_test.py", line 259, in <module>
assert False
AssertionError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "exit_stack_test.py", line 259, in <module>
assert False
File "/.../python3.7/contextlib.py", line 524, in __exit__
raise exc_details[1]
File "/.../python3.7/contextlib.py", line 509, in __exit__
if cb(*exc_details):
File "/.../python3.7/contextlib.py", line 377, in _exit_wrapper
return cm_exit(cm, exc_type, exc, tb)
File "/.../python3.7/contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "exit_stack_test.py", line 244, in my_cm
raise exc
MyException |
[reposting the example, with source] example: @contextmanager
def my_cm():
try:
yield
except BaseException:
exc = MyException()
try:
raise exc
finally:
exc.__context__ = None
print('\n=== `with` statement ===')
try:
with my_cm():
assert False
except BaseException as e:
traceback.print_exc() print('\n=== enter_context() ===') output: Traceback (most recent call last):
File "exit_stack_test.py", line 251, in <module>
assert False
File "/.../python3.7/contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "exit_stack_test.py", line 244, in my_cm
raise exc
MyException === enter_context() === Traceback (most recent call last):
File "exit_stack_test.py", line 240, in my_cm
yield
File "exit_stack_test.py", line 259, in <module>
assert False
AssertionError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "exit_stack_test.py", line 259, in <module>
assert False
File "/.../python3.7/contextlib.py", line 524, in __exit__
raise exc_details[1]
File "/.../python3.7/contextlib.py", line 509, in __exit__
if cb(*exc_details):
File "/.../python3.7/contextlib.py", line 377, in _exit_wrapper
return cm_exit(cm, exc_type, exc, tb)
File "/.../python3.7/contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "exit_stack_test.py", line 244, in my_cm
raise exc
MyException |
cc: ncoghlan for help with ExitStack exception context |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: