I think this example might be a false positive:
https://github.com/zulip/zulip/blob/3dc54a10d7cbfb6f6f66a868a31d17ee9e215f53/zerver/worker/email_senders_base.py#L28-L45
It looks like a closure defined in the except handler will preserve its exc_info in the same call stack:
>>> import logging
>>> l = []
>>> def foo(f): f()
...
>>> try:
... raise ValueError("my error")
... except ValueError:
... logging.exception("building on_failure")
... def on_failure():
... logging.exception("on_failure called")
... foo(on_failure)
... l.append(on_failure)
...
ERROR:root:building on_failure
Traceback (most recent call last):
File "<python-input-19>", line 2, in <module>
raise ValueError("my error")
ValueError: my error
ERROR:root:on_failure called
Traceback (most recent call last):
File "<python-input-19>", line 2, in <module>
raise ValueError("my error")
ValueError: my error
>>> l[-1]()
ERROR:root:on_failure called
NoneType: None
but not if you store it somewhere else and call it later.
Originally posted by @ntBre in #18603 (comment)
I think this example might be a false positive:
https://github.com/zulip/zulip/blob/3dc54a10d7cbfb6f6f66a868a31d17ee9e215f53/zerver/worker/email_senders_base.py#L28-L45
It looks like a closure defined in the except handler will preserve its
exc_infoin the same call stack:but not if you store it somewhere else and call it later.
Originally posted by @ntBre in #18603 (comment)