Skip to content

Commit 63e89f4

Browse files
committed
Split exception formatting into two phases:
one to format each frame and exception message, one to assemble the final string. perhaps a step towards a feature where it returns somewhat more structured data
1 parent 32c19bf commit 63e89f4

File tree

1 file changed

+74
-71
lines changed

1 file changed

+74
-71
lines changed

stackprinter/formatting.py

Lines changed: 74 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -109,89 +109,93 @@ def format_stack_from_frame(fr, add_summary=False, **kwargs):
109109
return format_stack(stack, **kwargs)
110110

111111

112-
def format_exc_info(etype, evalue, tb, style='plaintext', add_summary='auto',
113-
reverse=False, suppressed_exceptions=[KeyboardInterrupt],
114-
**kwargs):
115-
"""
116-
Format an exception traceback, including the exception message
112+
def format_parts(etype, evalue, tb, style='plaintext', add_summary='auto',
113+
reverse=False, suppressed_exceptions=[KeyboardInterrupt],
114+
**kwargs):
115+
""" Render this exception's traceback as a list of strings """
117116

118-
see stackprinter.format() for docs about the keyword arguments
119-
"""
117+
parts = []
120118
if etype is None:
121119
etype = type(None)
122120

123-
msg = ''
124-
try:
125-
# First, recursively format any chained exceptions (exceptions
126-
# during whose handling the given one happened).
127-
# TODO: refactor this whole messy function to return a
128-
# more... structured datastructure before assembling a string,
129-
# so that e.g. a summary of the whole chain can be shown at
130-
# the end.
131-
context = getattr(evalue, '__context__', None)
132-
cause = getattr(evalue, '__cause__', None)
133-
suppress_context = getattr(evalue, '__suppress_context__', False)
134-
if cause:
135-
chained_exc = cause
136-
chain_hint = ("\n\nThe above exception was the direct cause "
137-
"of the following exception:\n\n")
138-
elif context and not suppress_context:
139-
chained_exc = context
140-
chain_hint = ("\n\nWhile handling the above exception, "
141-
"another exception occurred:\n\n")
121+
# First, recursively format any chained exceptions (exceptions
122+
# during whose handling the given one happened).
123+
# TODO: refactor this whole messy function to return a
124+
# more... structured datastructure before assembling a string,
125+
# so that e.g. a summary of the whole chain can be shown at
126+
# the end.
127+
context = getattr(evalue, '__context__', None)
128+
cause = getattr(evalue, '__cause__', None)
129+
suppress_context = getattr(evalue, '__suppress_context__', False)
130+
if cause:
131+
chained_exc = cause
132+
chain_hint = ("\n\nThe above exception was the direct cause "
133+
"of the following exception:\n\n")
134+
elif context and not suppress_context:
135+
chained_exc = context
136+
chain_hint = ("\n\nWhile handling the above exception, "
137+
"another exception occurred:\n\n")
138+
else:
139+
chained_exc = None
140+
141+
if chained_exc:
142+
parts.extend(format_parts(chained_exc.__class__,
143+
chained_exc,
144+
chained_exc.__traceback__,
145+
style=style,
146+
add_summary=add_summary,
147+
reverse=reverse,
148+
**kwargs))
149+
if style == 'plaintext':
150+
parts.append(chain_hint)
142151
else:
143-
chained_exc = None
144-
145-
if chained_exc:
146-
msg += format_exc_info(chained_exc.__class__,
147-
chained_exc,
148-
chained_exc.__traceback__,
149-
style=style,
150-
add_summary=add_summary,
151-
reverse=reverse,
152-
**kwargs)
153-
154-
if style == 'plaintext':
155-
msg += chain_hint
156-
else:
157-
sc = getattr(colorschemes, style)
158-
clr = get_ansi_tpl(*sc.colors['exception_type'])
159-
msg += clr % chain_hint
160-
161-
# Now, actually do some formatting:
162-
parts = []
163-
if tb:
164-
frameinfos = [ex.get_info(tb_) for tb_ in _walk_traceback(tb)]
165-
if (suppressed_exceptions and
166-
issubclass(etype, tuple(suppressed_exceptions))):
152+
sc = getattr(colorschemes, style)
153+
clr = get_ansi_tpl(*sc.colors['exception_type'])
154+
parts.append(clr % chain_hint)
155+
156+
# Now, actually do some formatting:
157+
if tb:
158+
frameinfos = [ex.get_info(tb_) for tb_ in _walk_traceback(tb)]
159+
if (suppressed_exceptions and
160+
issubclass(etype, tuple(suppressed_exceptions))):
161+
summary = format_summary(frameinfos, style=style,
162+
reverse=reverse, **kwargs)
163+
parts = [summary]
164+
else:
165+
whole_stack = format_stack(frameinfos, style=style,
166+
reverse=reverse, **kwargs)
167+
parts.append(whole_stack)
168+
169+
if add_summary == 'auto':
170+
add_summary = whole_stack.count('\n') > 50
171+
172+
if add_summary:
167173
summary = format_summary(frameinfos, style=style,
168174
reverse=reverse, **kwargs)
169-
parts = [summary]
170-
else:
171-
whole_stack = format_stack(frameinfos, style=style,
172-
reverse=reverse, **kwargs)
173-
parts.append(whole_stack)
175+
summary += '\n'
176+
parts.append('---- (full traceback below) ----\n\n' if reverse else
177+
'---- (full traceback above) ----\n')
178+
parts.append(summary)
174179

175-
if add_summary == 'auto':
176-
add_summary = whole_stack.count('\n') > 50
180+
exc = format_exception_message(etype, evalue, style=style)
181+
parts.append('\n\n' if reverse else '')
182+
parts.append(exc)
177183

178-
if add_summary:
179-
summary = format_summary(frameinfos, style=style,
180-
reverse=reverse, **kwargs)
181-
summary += '\n'
182-
parts.append('---- (full traceback below) ----\n\n' if reverse else
183-
'---- (full traceback above) ----\n')
184-
parts.append(summary)
184+
if reverse:
185+
parts = reversed(parts)
185186

186-
exc = format_exception_message(etype, evalue, style=style)
187-
parts.append('\n\n' if reverse else '')
188-
parts.append(exc)
187+
return parts
189188

190-
if reverse:
191-
parts = reversed(parts)
192189

193-
msg += ''.join(parts)
190+
def format_exc_info(etype, evalue, tb, **kwargs):
191+
"""
192+
Format an exception traceback, including the exception message
194193
194+
see stackprinter.format() for docs about the keyword arguments
195+
"""
196+
try:
197+
parts = format_parts(etype, evalue, tb, **kwargs)
198+
msg = ''.join(parts)
195199
except Exception as exc:
196200
import os
197201
if 'PY_STACKPRINTER_DEBUG' in os.environ:
@@ -207,7 +211,6 @@ def format_exc_info(etype, evalue, tb, style='plaintext', add_summary='auto',
207211
msg += 'So here is your original traceback at least:\n\n'
208212
msg += ''.join(traceback.format_exception(etype, evalue, tb))
209213

210-
211214
return msg
212215

213216

0 commit comments

Comments
 (0)