@@ -43,6 +43,9 @@ impl PyPayload for PyBaseException {
4343 }
4444}
4545
46+ const TRACEBACK_LIMIT : usize = 1000 ;
47+ const TRACEBACK_RECURSIVE_CUTOFF : usize = 3 ; // Also hardcoded in traceback.py.
48+
4649impl VirtualMachine {
4750 // Why `impl VirtualMachine`?
4851 // These functions are natively free function in CPython - not methods of PyException
@@ -131,10 +134,40 @@ impl VirtualMachine {
131134 exc : & PyBaseExceptionRef ,
132135 ) -> Result < ( ) , W :: Error > {
133136 let vm = self ;
137+
138+ // TODO: Get tracebacklimit from sys and replace limit with that if it exists
139+ let limit = TRACEBACK_LIMIT ;
134140 if let Some ( tb) = exc. traceback . read ( ) . clone ( ) {
135141 writeln ! ( output, "Traceback (most recent call last):" ) ?;
142+ let mut tb_list = vec ! [ ] ;
136143 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) ?;
138171 }
139172 }
140173
@@ -383,6 +416,20 @@ fn write_traceback_entry<W: Write>(
383416 Ok ( ( ) )
384417}
385418
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+
386433#[ derive( Clone ) ]
387434pub enum ExceptionCtor {
388435 Class ( PyTypeRef ) ,
0 commit comments