Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 59 additions & 17 deletions Lib/idlelib/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,31 +249,73 @@ def print_exception():
sys.last_type, sys.last_value, sys.last_traceback = excinfo
sys.last_exc = val
seen = set()
exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
"debugger_r.py", "bdb.py")

def print_exc(typ, exc, tb):
def print_exc_group(typ, exc, tb, prefix=""):
prefix2 = prefix or " "
if tb:
if not prefix:
print(" + Exception Group Traceback (most recent call last):", file=efile)
else:
print(f"{prefix}| Exception Group Traceback (most recent call last):", file=efile)
tbe = traceback.extract_tb(tb)
cleanup_traceback(tbe, exclude)
for line in traceback.format_list(tbe):
for subline in line.rstrip().splitlines():
print(f"{prefix2}| {subline}", file=efile)
lines = get_message_lines(typ, exc, tb)
for line in lines:
print(f"{prefix2}| {line}", end="", file=efile)
for i, sub in enumerate(exc.exceptions, 1):
if i == 1:
first_line_pre = "+-"
else:
first_line_pre = " "
print(f"{prefix2}{first_line_pre}+---------------- {i} ----------------", file=efile)
if id(sub) not in seen:
if not prefix:
print_exc(type(sub), sub, sub.__traceback__, " ")
else:
print_exc(type(sub), sub, sub.__traceback__, prefix + " ")
need_print_underline = not isinstance(sub, BaseExceptionGroup)
else:
print(f"{prefix2} | <exception {type(sub).__name__} has printed>")
need_print_underline = True
if need_print_underline:
print(f"{prefix2} +------------------------------------", file=efile)

def print_exc(typ, exc, tb, prefix=""):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is anyway a local function, I'd suggest having other helpers to reduce the complexity of the function.

seen.add(id(exc))
context = exc.__context__
cause = exc.__cause__
prefix2 = f"{prefix}| " if prefix else ""
if cause is not None and id(cause) not in seen:
print_exc(type(cause), cause, cause.__traceback__)
print("\nThe above exception was the direct cause "
"of the following exception:\n", file=efile)
print_exc(type(cause), cause, cause.__traceback__, prefix)
print(f"{prefix2}\n{prefix2}The above exception was the direct cause "
f"of the following exception:\n{prefix2}", file=efile)
elif (context is not None and
not exc.__suppress_context__ and
id(context) not in seen):
print_exc(type(context), context, context.__traceback__)
print("\nDuring handling of the above exception, "
"another exception occurred:\n", file=efile)
if tb:
tbe = traceback.extract_tb(tb)
print('Traceback (most recent call last):', file=efile)
exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
"debugger_r.py", "bdb.py")
cleanup_traceback(tbe, exclude)
traceback.print_list(tbe, file=efile)
lines = get_message_lines(typ, exc, tb)
for line in lines:
print(line, end='', file=efile)
print_exc(type(context), context, context.__traceback__, prefix)
print(f"{prefix2}\n{prefix2}During handling of the above exception, "
f"another exception occurred:\n{prefix2}", file=efile)
if isinstance(exc, BaseExceptionGroup):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For instance, here, I would suggest using a separate function, say print_exc_group() that you would define locally as well.

Copy link
Member

@picnixz picnixz Oct 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change that if isinstance(val, BaseExceptionGroup) branch becomes a function alone is difficult because it is a closure function.

Even with that, it's not really important. What is the issue with it being a local function? print_exc is already a local function. Just pass the arguments you need to that local function.

print_exc_group(typ, exc, tb, prefix=prefix)
else:
if tb:
print(f"{prefix2}Traceback (most recent call last):", file=efile)
tbe = traceback.extract_tb(tb)
cleanup_traceback(tbe, exclude)
if prefix:
for line in traceback.format_list(tbe):
for subline in line.rstrip().splitlines():
print(f"{prefix}| {subline}", file=efile)
else:
traceback.print_list(tbe, file=efile)
lines = get_message_lines(typ, exc, tb)
for line in lines:
print(f"{prefix2}{line}", end="", file=efile)

print_exc(typ, val, tb)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support rendering :exc:`BaseExceptionGroup` in IDLE.
Loading