@@ -43,6 +43,9 @@ impl PyPayload for PyBaseException {
43
43
}
44
44
}
45
45
46
+ const TRACEBACK_LIMIT : usize = 1000 ;
47
+ const TRACEBACK_RECURSIVE_CUTOFF : usize = 3 ; // Also hardcoded in traceback.py.
48
+
46
49
impl VirtualMachine {
47
50
// Why `impl VirtualMachine`?
48
51
// These functions are natively free function in CPython - not methods of PyException
@@ -131,10 +134,40 @@ impl VirtualMachine {
131
134
exc : & PyBaseExceptionRef ,
132
135
) -> Result < ( ) , W :: Error > {
133
136
let vm = self ;
137
+
138
+ // TODO: Get tracebacklimit from sys and replace limit with that if it exists
139
+ let limit = TRACEBACK_LIMIT ;
134
140
if let Some ( tb) = exc. traceback . read ( ) . clone ( ) {
135
141
writeln ! ( output, "Traceback (most recent call last):" ) ?;
142
+ let mut tb_list = vec ! [ ] ;
136
143
for tb in tb. iter ( ) {
137
- write_traceback_entry ( output, & tb) ?;
144
+ tb_list. push ( tb) ;
145
+ }
146
+ let mut repeat_counter = 0 ;
147
+ let mut previous_file = "" . to_string ( ) ;
148
+ let mut previous_line = 0 ;
149
+ let mut previous_name = "" . to_string ( ) ;
150
+ // Gets the last `limit` traceback entries
151
+ for tb in tb_list. into_iter ( ) . rev ( ) . take ( limit) . rev ( ) {
152
+ if previous_file != tb. frame . code . source_path . as_str ( )
153
+ || previous_line != tb. lineno . get ( )
154
+ || previous_name != tb. frame . code . obj_name . as_str ( )
155
+ {
156
+ if repeat_counter > TRACEBACK_RECURSIVE_CUTOFF {
157
+ write_repeat_traceback_entry ( output, & tb, repeat_counter) ?;
158
+ }
159
+ previous_file = tb. frame . code . source_path . as_str ( ) . to_string ( ) ;
160
+ previous_line = tb. lineno . get ( ) ;
161
+ previous_name = tb. frame . code . obj_name . as_str ( ) . to_string ( ) ;
162
+ repeat_counter = 0 ;
163
+ }
164
+ repeat_counter += 1 ;
165
+ if repeat_counter <= TRACEBACK_RECURSIVE_CUTOFF {
166
+ write_traceback_entry ( output, & tb) ?;
167
+ }
168
+ }
169
+ if repeat_counter > TRACEBACK_RECURSIVE_CUTOFF {
170
+ write_repeat_traceback_entry ( output, & tb_list[ 0 ] , repeat_counter) ?;
138
171
}
139
172
}
140
173
@@ -383,6 +416,20 @@ fn write_traceback_entry<W: Write>(
383
416
Ok ( ( ) )
384
417
}
385
418
419
+ fn write_repeat_traceback_entry < W : Write > (
420
+ output : & mut W ,
421
+ tb_entry : & PyTracebackRef ,
422
+ repeat_counter : usize ,
423
+ ) -> Result < ( ) , W :: Error > {
424
+ let count = repeat_counter - TRACEBACK_RECURSIVE_CUTOFF ;
425
+ writeln ! (
426
+ output,
427
+ r##" [Previous line repeated {} more time{}]"## ,
428
+ count,
429
+ if count == 1 { "" } else { "s" }
430
+ )
431
+ }
432
+
386
433
#[ derive( Clone ) ]
387
434
pub enum ExceptionCtor {
388
435
Class ( PyTypeRef ) ,
0 commit comments