-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
- I've checked docs and closed issues for possible solutions.
- I can't find my issue in the FAQ.
Describe the bug
console.print_exception
will enter an infinite loop when exc.__cause__ is exc
. This can happen if we raise exc from exc
. Here is the minimal example. Python enters infinite loop eating all resources until killed.
from rich.console import Console
console = Console()
def foo() -> None:
try:
raise RuntimeError("Hello")
except Exception as e:
raise e from e
def bar():
try:
foo()
except Exception as e:
assert e is e.__cause__
console.print_exception(show_locals=True)
bar()
I suspect the culprit is here:
Lines 564 to 572 in 0c6c756
cause = getattr(exc_value, "__cause__", None) | |
if cause: | |
exc_type = cause.__class__ | |
exc_value = cause | |
# __traceback__ can be None, e.g. for exceptions raised by the | |
# 'multiprocessing' module | |
traceback = cause.__traceback__ | |
is_cause = True | |
continue |
I image the patch to look smth like this, but I am not familiar with the codebase. I am not sure if the same can happen with the __context__
attribute a few lines below the snippet above.
cause = getattr(exc_value, "__cause__", None)
- if cause:
+ if cause and cause is not exc_value:
exc_type = cause.__class__
exc_value = cause
# __traceback__ can be None, e.g. for exceptions raised by the
# 'multiprocessing' module
traceback = cause.__traceback__
is_cause = True
continue
Now I know that raise exc from exc
does not make sense and should just be raise exc
. But nevertheless, Rich should handle this case as well and not loop forever until it eats the whole RAM. Some python libraries unfortunately use raise exc from exc
and fixing all of them is not a viable option.
I am using the latest release of Rich with Python 3.13.3