in runtime/traceback-builtins.cpp [211:309]
RawObject tracebackWrite(Thread* thread, const Traceback& traceback,
const Object& file) {
HandleScope scope(thread);
Runtime* runtime = thread->runtime();
Object limit_obj(
&scope, runtime->lookupNameInModule(thread, ID(sys), ID(tracebacklimit)));
word limit = kTracebackLimit;
if (!limit_obj.isErrorNotFound() && runtime->isInstanceOfInt(*limit_obj)) {
limit = intUnderlying(*limit_obj).asWordSaturated();
if (limit <= 0) {
return NoneType::object();
}
}
Str line(&scope,
runtime->newStrFromCStr("Traceback (most recent call last):\n"));
Object result(&scope, thread->invokeMethod2(file, ID(write), line));
if (result.isErrorException()) return *result;
word depth = 0;
Object tb(&scope, *traceback);
while (tb.isTraceback()) {
depth++;
tb = Traceback::cast(*tb).next();
}
Traceback current(&scope, *traceback);
while (depth > limit) {
depth--;
current = current.next();
}
MutableBytes buffer(&scope, runtime->emptyMutableBytes());
Object filename(&scope, NoneType::object());
Object function_name(&scope, NoneType::object());
Object lineno(&scope, NoneType::object());
Object last_filename(&scope, NoneType::object());
Object last_function_name(&scope, NoneType::object());
Object last_lineno(&scope, NoneType::object());
Object next(&scope, NoneType::object());
for (word count = 0;;) {
filename = tracebackFilename(thread, current);
lineno = tracebackLineno(thread, current);
function_name = tracebackFunctionName(thread, current);
bool filename_changed =
last_filename.isNoneType() || filename.isNoneType() ||
!Str::cast(*last_filename).equals(Str::cast(*filename));
bool lineno_changed = last_lineno.isNoneType() || lineno != last_lineno;
bool function_name_changed =
last_function_name.isNoneType() || function_name.isNoneType() ||
!Str::cast(*last_function_name).equals(Str::cast(*function_name));
if (filename_changed || lineno_changed || function_name_changed) {
if (count > kTracebackRecursiveCutoff) {
line = lineRepeated(thread, count);
result = thread->invokeMethod2(file, ID(write), line);
if (result.isErrorException()) return *result;
}
last_filename = *filename;
last_lineno = *lineno;
last_function_name = *function_name;
count = 0;
}
count++;
if (count <= kTracebackRecursiveCutoff) {
word size =
tracebackWriteLine(filename, lineno, function_name, buffer, true);
buffer = runtime->newMutableBytesUninitialized(size);
tracebackWriteLine(filename, lineno, function_name, buffer, false);
line = buffer.becomeStr();
result = thread->invokeMethod2(file, ID(write), line);
if (result.isErrorException()) return *result;
result = sourceLine(thread, filename, lineno);
if (result.isErrorException()) return *result;
if (result.isStr()) {
result = thread->invokeMethod2(file, ID(write), result);
if (result.isErrorException()) return *result;
}
result = runtime->handlePendingSignals(thread);
if (result.isErrorException()) return *result;
}
next = current.next();
if (next.isNoneType()) {
if (count > kTracebackRecursiveCutoff) {
line = lineRepeated(thread, count);
result = thread->invokeMethod2(file, ID(write), line);
if (result.isErrorException()) return *result;
}
return NoneType::object();
}
current = *next;
buffer = runtime->emptyMutableBytes();
}
}