diff -r e539761d45e3 -r 704d1bcc942e Include/code.h --- a/Include/code.h Thu Nov 14 15:35:47 2013 +0100 +++ b/Include/code.h Mon Nov 25 12:51:33 2013 +0100 @@ -30,6 +30,8 @@ typedef struct { Objects/lnotab_notes.txt for details. */ void *co_zombieframe; /* for optimization only (see frameobject.c) */ PyObject *co_weakreflist; /* to support weakrefs to code objects */ + PyObject *co_annotation; /* Annotation function (used for formatting + additional info in traceback) */ } PyCodeObject; /* Masks for co_flags above */ diff -r e539761d45e3 -r 704d1bcc942e Lib/traceback.py --- a/Lib/traceback.py Thu Nov 14 15:35:47 2013 +0100 +++ b/Lib/traceback.py Mon Nov 25 12:51:33 2013 +0100 @@ -15,8 +15,11 @@ import operator # def _format_list_iter(extracted_list): - for filename, lineno, name, line in extracted_list: - item = ' File "{}", line {}, in {}\n'.format(filename, lineno, name) + for filename, lineno, name, line, annotation, frame in extracted_list: + item = ' File "{}", line {}, in {}'.format(filename, lineno, name) + if annotation is not None: + item += ': {}'.format(annotation(frame)) + item += '\n' if line: item = item + ' {}\n'.format(line.strip()) yield item @@ -60,6 +63,7 @@ def _extract_tb_or_stack_iter(curr, limi co = f.f_code filename = co.co_filename name = co.co_name + annotation = co.co_annotation linecache.checkcache(filename) line = linecache.getline(filename, lineno, f.f_globals) @@ -69,7 +73,7 @@ def _extract_tb_or_stack_iter(curr, limi else: line = None - yield (filename, lineno, name, line) + yield (filename, lineno, name, line, annotation, f) curr = next_item n += 1 @@ -310,3 +314,11 @@ def clear_frames(tb): # Ignore the exception raised if the frame is still executing. pass tb = tb.tb_next + +def annotate(format): + def wrapper(f): + def formatter(frame): + return format.format(**frame.f_locals) + f.__code__.co_annotation = formatter + return f + return wrapper diff -r e539761d45e3 -r 704d1bcc942e Objects/codeobject.c --- a/Objects/codeobject.c Thu Nov 14 15:35:47 2013 +0100 +++ b/Objects/codeobject.c Mon Nov 25 12:51:33 2013 +0100 @@ -152,6 +152,7 @@ PyCode_New(int argcount, int kwonlyargco co->co_lnotab = lnotab; co->co_zombieframe = NULL; co->co_weakreflist = NULL; + co->co_annotation = NULL; return co; } @@ -221,6 +222,7 @@ static PyMemberDef code_memberlist[] = { {"co_name", T_OBJECT, OFF(co_name), READONLY}, {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, {"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY}, + {"co_annotation", T_OBJECT, OFF(co_annotation), 0}, {NULL} /* Sentinel */ }; diff -r e539761d45e3 -r 704d1bcc942e Python/traceback.c --- a/Python/traceback.c Thu Nov 14 15:35:47 2013 +0100 +++ b/Python/traceback.c Mon Nov 25 12:51:33 2013 +0100 @@ -343,15 +343,38 @@ int } static int -tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name) +tb_displayline(PyObject *f, PyTracebackObject *tb) { int err; PyObject *line; + PyObject *filename = tb->tb_frame->f_code->co_filename; + int lineno = tb->tb_lineno; + PyObject *name = tb->tb_frame->f_code->co_name; + PyObject *annotation = tb->tb_frame->f_code->co_annotation; + if (filename == NULL || name == NULL) return -1; - line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n", - filename, lineno, name); + if (annotation == NULL) + line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n", + filename, lineno, name); + else + { + PyObject *formatted = PyObject_CallFunctionObjArgs(annotation, + tb->tb_frame, NULL); + if (formatted == NULL) + { + /* If formatting the annotation failed, retry without the annotation */ + line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U: ?\n", + filename, lineno, name); + } + else + { + line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U: %S\n", + filename, lineno, name, formatted); + Py_DECREF(formatted); + } + } if (line == NULL) return -1; err = PyFile_WriteObject(line, f, Py_PRINT_RAW); @@ -376,10 +399,7 @@ tb_printinternal(PyTracebackObject *tb, } while (tb != NULL && err == 0) { if (depth <= limit) { - err = tb_displayline(f, - tb->tb_frame->f_code->co_filename, - tb->tb_lineno, - tb->tb_frame->f_code->co_name); + err = tb_displayline(f, tb); } depth--; tb = tb->tb_next;