@@ -30,11 +30,15 @@ def print_list(extracted_list, file=None, *, show_lines=True):
30
30
"""Print the list of tuples as returned by extract_tb() or
31
31
extract_stack() as a formatted stack trace to the given file.
32
32
33
- If show_lines is False, source code lines are not included in the output.
33
+ To print in "recent call first" order, call "extracted_list.reverse()"
34
+ before passing it to this function.
35
+
36
+ If 'show_lines' is false, source code lines are not included in the output.
34
37
"""
35
38
if file is None :
36
39
file = sys .stderr
37
- for item in StackSummary .from_list (extracted_list ).format (show_lines = show_lines ):
40
+ for item in StackSummary .from_list (extracted_list ).format (
41
+ show_lines = show_lines ):
38
42
print (item , file = file , end = "" )
39
43
40
44
def format_list (extracted_list , * , show_lines = True ):
@@ -44,37 +48,41 @@ def format_list(extracted_list, *, show_lines=True):
44
48
extract_tb() or extract_stack(), return a list of strings ready
45
49
for printing.
46
50
47
- Each string in the resulting list corresponds to the item with the
48
- same index in the argument list. Each string ends in a newline;
49
- the strings may contain internal newlines as well, for those items
50
- whose source text line is not None.
51
+ Each string ends in a newline; the strings may contain internal newlines as
52
+ well, for those items whose source text line is not None.
51
53
52
- If show_lines is False , source code lines are not included in the output.
54
+ If ' show_lines' is false , source code lines are not included in the output.
53
55
"""
54
56
return StackSummary .from_list (extracted_list ).format (show_lines = show_lines )
55
57
56
58
#
57
59
# Printing and Extracting Tracebacks.
58
60
#
59
61
60
- def print_tb (tb , limit = None , file = None , * , show_lines = True ):
62
+ def print_tb (tb , limit = None , file = None , * , show_lines = True , recent_first = False ):
61
63
"""Print up to 'limit' stack trace entries from the traceback 'tb'.
62
64
63
65
If 'limit' is omitted or None, all entries are printed. If 'file'
64
66
is omitted or None, the output goes to sys.stderr; otherwise
65
67
'file' should be an open file or file-like object with a write()
66
68
method.
67
69
68
- If show_lines is False, source code lines are not included in the output.
70
+ If 'show_lines' is false, source code lines are not included in the output.
71
+ If 'recent_first' is true, the stack trace is printed in "most recent call
72
+ first" order.
69
73
"""
70
- print_list (extract_tb (tb , limit = limit ), file = file , show_lines = show_lines )
74
+ tblist = extract_tb (tb , limit = limit )
75
+ if recent_first :
76
+ tblist .reverse ()
77
+ print_list (tblist , file = file , show_lines = show_lines )
71
78
72
- def format_tb (tb , limit = None , * , show_lines = True ):
73
- """A shorthand for 'format_list(extract_tb(tb, limit))'.
79
+ def format_tb (tb , limit = None , * , show_lines = True , recent_first = False ):
80
+ """A shorthand for 'format_list(extract_tb(tb, limit))'."""
74
81
75
- If show_lines is False, source code lines are not included in the output.
76
- """
77
- return extract_tb (tb , limit = limit ).format (show_lines = show_lines )
82
+ tblist = extract_tb (tb , limit = limit )
83
+ if recent_first :
84
+ tblist .reverse ()
85
+ return tblist .format (show_lines = show_lines )
78
86
79
87
def extract_tb (tb , limit = None ):
80
88
"""
@@ -90,7 +98,7 @@ def extract_tb(tb, limit=None):
90
98
whitespace stripped; if the source is not available it is None.
91
99
"""
92
100
return StackSummary ._extract_from_extended_frame_gen (
93
- _walk_tb_with_full_positions (tb ), limit = limit , lookup_lines = False )
101
+ _walk_tb_with_full_positions (tb ), limit = limit )
94
102
95
103
#
96
104
# Exception formatting and output.
@@ -126,8 +134,9 @@ def _parse_value_tb(exc, value, tb):
126
134
return value , tb
127
135
128
136
129
- def print_exception (exc , / , value = _sentinel , tb = _sentinel , limit = None , \
130
- file = None , chain = True , show_lines = True , ** kwargs ):
137
+ def print_exception (exc , / , value = _sentinel , tb = _sentinel , limit = None ,
138
+ file = None , chain = True , * , show_lines = True ,
139
+ recent_first = False , ** kwargs ):
131
140
"""Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
132
141
133
142
This differs from print_tb() in the following ways: (1) if
@@ -138,13 +147,15 @@ def print_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \
138
147
occurred with a caret on the next line indicating the approximate
139
148
position of the error.
140
149
141
- If show_lines is False, source code lines are not included in the output.
150
+ If 'show_lines' is false, source code lines are not included in the output.
151
+ If 'recent_first' is true, exception is printed first and traceback is shown
152
+ by "most recent call first" order.
142
153
"""
143
154
colorize = kwargs .get ("colorize" , False )
144
155
value , tb = _parse_value_tb (exc , value , tb )
145
- te = TracebackException (type (value ), value , tb , limit = limit , compact = True ,
146
- lookup_lines = show_lines )
147
- te . print ( file = file , chain = chain , colorize = colorize , show_lines = show_lines )
156
+ te = TracebackException (type (value ), value , tb , limit = limit , compact = True )
157
+ te . print ( file = file , chain = chain , colorize = colorize ,
158
+ show_lines = show_lines , recent_first = recent_first )
148
159
149
160
150
161
BUILTIN_EXCEPTION_LIMIT = object ()
@@ -156,23 +167,21 @@ def _print_exception_bltin(exc, /):
156
167
return print_exception (exc , limit = BUILTIN_EXCEPTION_LIMIT , file = file , colorize = colorize )
157
168
158
169
159
- def format_exception (exc , / , value = _sentinel , tb = _sentinel , limit = None , \
160
- chain = True , show_lines = True , ** kwargs ):
170
+ def format_exception (exc , / , value = _sentinel , tb = _sentinel , limit = None ,
171
+ chain = True , * , show_lines = True , recent_first = False , ** kwargs ):
161
172
"""Format a stack trace and the exception information.
162
173
163
174
The arguments have the same meaning as the corresponding arguments
164
175
to print_exception(). The return value is a list of strings, each
165
176
ending in a newline and some containing internal newlines. When
166
177
these lines are concatenated and printed, exactly the same text is
167
178
printed as does print_exception().
168
-
169
- If show_lines is False, source code lines are not included in the output.
170
179
"""
171
180
colorize = kwargs .get ("colorize" , False )
172
181
value , tb = _parse_value_tb (exc , value , tb )
173
- te = TracebackException (type (value ), value , tb , limit = limit , compact = True ,
174
- lookup_lines = show_lines )
175
- return list ( te . format ( chain = chain , colorize = colorize , show_lines = show_lines ))
182
+ te = TracebackException (type (value ), value , tb , limit = limit , compact = True )
183
+ return list ( te . format ( chain = chain , colorize = colorize ,
184
+ show_lines = show_lines , recent_first = recent_first ))
176
185
177
186
178
187
def format_exception_only (exc , / , value = _sentinel , * , show_group = False , ** kwargs ):
@@ -221,61 +230,63 @@ def _safe_string(value, what, func=str):
221
230
222
231
# --
223
232
224
- def print_exc (limit = None , file = None , chain = True , * , show_lines = True ):
225
- """Shorthand for 'print_exception(sys.exception(), limit=limit, file=file, chain=chain)'.
226
-
227
- If show_lines is False, source code lines are not included in the output.
228
- """
229
- print_exception (sys .exception (), limit = limit , file = file , chain = chain , show_lines = show_lines )
230
-
231
- def format_exc (limit = None , chain = True , * , show_lines = True ):
232
- """Like print_exc() but return a string.
233
-
234
- If show_lines is False, source code lines are not included in the output.
235
- """
236
- return "" .join (format_exception (sys .exception (), limit = limit , chain = chain , show_lines = show_lines ))
237
-
238
- def print_last (limit = None , file = None , chain = True , * , show_lines = True ):
239
- """This is a shorthand for 'print_exception(sys.last_exc, limit=limit, file=file, chain=chain)'.
240
-
241
- If show_lines is False, source code lines are not included in the output.
242
- """
233
+ def print_exc (limit = None , file = None , chain = True , * , show_lines = True ,
234
+ recent_first = False ):
235
+ """Shorthand for 'print_exception(sys.exception(), limit=limit, file=file, chain=chain, ...)'."""
236
+ print_exception (sys .exception (), limit = limit , file = file , chain = chain ,
237
+ show_lines = show_lines , recent_first = recent_first )
238
+
239
+ def format_exc (limit = None , chain = True , * , show_lines = True , recent_first = False ):
240
+ """Like print_exc() but return a string."""
241
+ return "" .join (format_exception (
242
+ sys .exception (), limit = limit , chain = chain ,
243
+ show_lines = show_lines , recent_first = recent_first ))
244
+
245
+ def print_last (limit = None , file = None , chain = True , * , show_lines = True ,
246
+ recent_first = False ):
247
+ """This is a shorthand for 'print_exception(sys.last_exc, limit=limit, file=file, chain=chain, ...)'."""
243
248
if not hasattr (sys , "last_exc" ) and not hasattr (sys , "last_type" ):
244
249
raise ValueError ("no last exception" )
245
250
246
251
if hasattr (sys , "last_exc" ):
247
- print_exception (sys .last_exc , limit = limit , file = file , chain = chain , show_lines = show_lines )
252
+ print_exception (sys .last_exc , limit = limit , file = file , chain = chain ,
253
+ show_lines = show_lines , recent_first = recent_first )
248
254
else :
249
255
print_exception (sys .last_type , sys .last_value , sys .last_traceback ,
250
- limit = limit , file = file , chain = chain , show_lines = show_lines )
256
+ limit = limit , file = file , chain = chain ,
257
+ show_lines = show_lines , recent_first = recent_first )
251
258
252
259
253
260
#
254
261
# Printing and Extracting Stacks.
255
262
#
256
263
257
- def print_stack (f = None , limit = None , file = None , * , show_lines = True ):
264
+ def print_stack (f = None , limit = None , file = None , * , show_lines = True , recent_first = False ):
258
265
"""Print a stack trace from its invocation point.
259
266
260
267
The optional 'f' argument can be used to specify an alternate
261
268
stack frame at which to start. The optional 'limit' and 'file'
262
269
arguments have the same meaning as for print_exception().
263
270
264
- If show_lines is False, source code lines are not included in the output.
271
+ If 'show_lines' is false, source code lines are not included in the output.
272
+ If 'recent_first' is true, stack is printed by "most recent call first" order.
265
273
"""
266
274
if f is None :
267
275
f = sys ._getframe ().f_back
268
- print_list (extract_stack (f , limit = limit ), file = file , show_lines = show_lines )
276
+ stack = extract_stack (f , limit = limit )
277
+ if recent_first :
278
+ stack .reverse ()
279
+ print_list (stack , file = file , show_lines = show_lines )
269
280
270
281
271
- def format_stack (f = None , limit = None , * , show_lines = True ):
272
- """Shorthand for 'format_list(extract_stack(f, limit))'.
273
-
274
- If show_lines is False, source code lines are not included in the output.
275
- """
282
+ def format_stack (f = None , limit = None , * , show_lines = True , recent_first = False ):
283
+ """Shorthand for 'format_list(extract_stack(f, limit), show_lines)'."""
276
284
if f is None :
277
285
f = sys ._getframe ().f_back
278
- return format_list (extract_stack (f , limit = limit ), show_lines = show_lines )
286
+ stack = extract_stack (f , limit = limit )
287
+ if recent_first :
288
+ stack .reverse ()
289
+ return format_list (stack , show_lines = show_lines )
279
290
280
291
281
292
def extract_stack (f = None , limit = None ):
@@ -289,7 +300,8 @@ def extract_stack(f=None, limit=None):
289
300
"""
290
301
if f is None :
291
302
f = sys ._getframe ().f_back
292
- stack = StackSummary .extract (walk_stack (f ), limit = limit , lookup_lines = False )
303
+ stack = StackSummary .extract (walk_stack (f ), limit = limit )
304
+ # Traceback should use "recent call last" order.
293
305
stack .reverse ()
294
306
return stack
295
307
@@ -465,7 +477,7 @@ class StackSummary(list):
465
477
"""A list of FrameSummary objects, representing a stack of frames."""
466
478
467
479
@classmethod
468
- def extract (klass , frame_gen , * , limit = None , lookup_lines = True ,
480
+ def extract (klass , frame_gen , * , limit = None , lookup_lines = False ,
469
481
capture_locals = False ):
470
482
"""Create a StackSummary from a traceback or stack object.
471
483
@@ -488,7 +500,7 @@ def extended_frame_gen():
488
500
489
501
@classmethod
490
502
def _extract_from_extended_frame_gen (klass , frame_gen , * , limit = None ,
491
- lookup_lines = True , capture_locals = False ):
503
+ lookup_lines = False , capture_locals = False ):
492
504
# Same as extract but operates on a frame generator that yields
493
505
# (frame, (lineno, end_lineno, colno, end_colno)) in the stack.
494
506
# Only lineno is required, the remaining fields can be None if the
@@ -560,8 +572,6 @@ def format_frame_summary(self, frame_summary, *, show_lines=True, **kwargs):
560
572
561
573
Returns a string representing one frame involved in the stack. This
562
574
gets called for every frame to be printed in the stack summary.
563
-
564
- If show_lines is False, source code lines are not included in the output.
565
575
"""
566
576
colorize = kwargs .get ("colorize" , False )
567
577
row = []
@@ -785,8 +795,6 @@ def format(self, *, show_lines=True, **kwargs):
785
795
For long sequences of the same frame and line, the first few
786
796
repetitions are shown, followed by a summary line stating the exact
787
797
number of further repetitions.
788
-
789
- If show_lines is False, source code lines are not included in the output.
790
798
"""
791
799
colorize = kwargs .get ("colorize" , False )
792
800
result = []
@@ -1076,7 +1084,7 @@ class TracebackException:
1076
1084
"""
1077
1085
1078
1086
def __init__ (self , exc_type , exc_value , exc_traceback , * , limit = None ,
1079
- lookup_lines = True , capture_locals = False , compact = False ,
1087
+ lookup_lines = False , capture_locals = False , compact = False ,
1080
1088
max_group_width = 15 , max_group_depth = 10 , save_exc_type = True , _seen = None ):
1081
1089
# NB: we need to accept exc_traceback, exc_value, exc_traceback to
1082
1090
# permit backwards compat with the existing API, otherwise we
@@ -1499,7 +1507,7 @@ def _format_syntax_error(self, stype, **kwargs):
1499
1507
filename_suffix ,
1500
1508
)
1501
1509
1502
- def format (self , * , chain = True , show_lines = True , _ctx = None , ** kwargs ):
1510
+ def format (self , * , chain = True , show_lines = True , _ctx = None , recent_first = False , ** kwargs ):
1503
1511
"""Format the exception.
1504
1512
1505
1513
If chain is not *True*, *__cause__* and *__context__* will not be formatted.
@@ -1510,8 +1518,6 @@ def format(self, *, chain=True, show_lines=True, _ctx=None, **kwargs):
1510
1518
1511
1519
The message indicating which exception occurred is always the last
1512
1520
string in the output.
1513
-
1514
- If show_lines is False, source code lines are not included in the output.
1515
1521
"""
1516
1522
colorize = kwargs .get ("colorize" , False )
1517
1523
if _ctx is None :
@@ -1541,10 +1547,16 @@ def format(self, *, chain=True, show_lines=True, _ctx=None, **kwargs):
1541
1547
if msg is not None :
1542
1548
yield from _ctx .emit (msg )
1543
1549
if exc .exceptions is None :
1544
- if exc .stack :
1550
+ if not recent_first and exc .stack :
1545
1551
yield from _ctx .emit ('Traceback (most recent call last):\n ' )
1546
- yield from _ctx .emit (exc .stack .format (show_lines = show_lines , colorize = colorize ))
1552
+ yield from _ctx .emit (exc .stack .format (
1553
+ show_lines = show_lines , colorize = colorize ))
1547
1554
yield from _ctx .emit (exc .format_exception_only (colorize = colorize ))
1555
+ if recent_first and exc .stack :
1556
+ yield from _ctx .emit ('Traceback (most recent call first):\n ' )
1557
+ reversed_stack = StackSummary (reversed (self .stack ))
1558
+ yield from _ctx .emit (reversed_stack .format (
1559
+ show_lines = show_lines , colorize = colorize ))
1548
1560
elif _ctx .exception_group_depth > self .max_group_depth :
1549
1561
# exception group, but depth exceeds limit
1550
1562
yield from _ctx .emit (
@@ -1555,13 +1567,22 @@ def format(self, *, chain=True, show_lines=True, _ctx=None, **kwargs):
1555
1567
if is_toplevel :
1556
1568
_ctx .exception_group_depth += 1
1557
1569
1558
- if exc .stack :
1570
+ if not recent_first and exc .stack :
1559
1571
yield from _ctx .emit (
1560
1572
'Exception Group Traceback (most recent call last):\n ' ,
1561
1573
margin_char = '+' if is_toplevel else None )
1562
- yield from _ctx .emit (exc .stack .format (show_lines = show_lines , colorize = colorize ))
1574
+ yield from _ctx .emit (exc .stack .format (
1575
+ show_lines = show_lines , colorize = colorize ))
1563
1576
1564
1577
yield from _ctx .emit (exc .format_exception_only (colorize = colorize ))
1578
+ if recent_first and exc .stack :
1579
+ yield from _ctx .emit (
1580
+ 'Exception Group Traceback (most recent call first):\n ' ,
1581
+ margin_char = '+' if is_toplevel else None )
1582
+ reversed_stack = StackSummary (reversed (self .stack ))
1583
+ yield from _ctx .emit (reversed_stack .format (
1584
+ show_lines = show_lines , colorize = colorize ))
1585
+
1565
1586
num_excs = len (exc .exceptions )
1566
1587
if num_excs <= self .max_group_width :
1567
1588
n = num_excs
@@ -1602,15 +1623,13 @@ def format(self, *, chain=True, show_lines=True, _ctx=None, **kwargs):
1602
1623
_ctx .exception_group_depth = 0
1603
1624
1604
1625
1605
- def print (self , * , file = None , chain = True , show_lines = True , ** kwargs ):
1606
- """Print the result of self.format(chain=chain) to 'file'.
1607
-
1608
- If show_lines is False, source code lines are not included in the output.
1609
- """
1626
+ def print (self , * , file = None , chain = True , show_lines = True , recent_first = False , ** kwargs ):
1627
+ """Print the result of self.format(chain=chain) to 'file'."""
1610
1628
colorize = kwargs .get ("colorize" , False )
1611
1629
if file is None :
1612
1630
file = sys .stderr
1613
- for line in self .format (chain = chain , show_lines = show_lines , colorize = colorize ):
1631
+ for line in self .format (chain = chain , show_lines = show_lines ,
1632
+ recent_first = recent_first , colorize = colorize ):
1614
1633
print (line , file = file , end = "" )
1615
1634
1616
1635
0 commit comments