Skip to content

Commit e31eda0

Browse files
committed
limit and repeat trucation for traceback
1 parent 0b35946 commit e31eda0

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

vm/src/exceptions.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
4649
impl 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)]
387434
pub enum ExceptionCtor {
388435
Class(PyTypeRef),

0 commit comments

Comments
 (0)