Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
dedba1f
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
494a3a5
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
1865ac8
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
affb018
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
f15aa44
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
18f79a7
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
ed98ae3
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
c99b286
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
551256b
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
165d763
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
3e79c5c
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
dd4f5bb
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 15, 2022
0ce3fef
📜🤖 Added by blurb_it.
blurb-it[bot] May 16, 2022
00d8452
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
c6c5d9d
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
801b237
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
867b182
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
2f04d08
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
47b8756
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
13b9a52
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
0403cbb
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
2f3d44d
bpo-43950: Implement fine grained error locations for interactive mode
thatbirdguythatuknownot May 16, 2022
72f9079
Update peg_extension.c
thatbirdguythatuknownot May 16, 2022
847e77f
Don't try to get the source of the file
thatbirdguythatuknownot May 16, 2022
f12ac1b
Don't get the source of the file
thatbirdguythatuknownot May 16, 2022
b1fb696
Handle the case of <string>
thatbirdguythatuknownot May 17, 2022
bc5b734
Use `Py_XINCREF` instead of `Py_INCREF`
thatbirdguythatuknownot May 17, 2022
d401e86
Skip file-related operations when file is either `<stdin>` or `<string>`
thatbirdguythatuknownot May 17, 2022
a910c19
Py_INCREF the source line to prevent negative reference count
thatbirdguythatuknownot May 20, 2022
5dab69e
Get proper line from possible multilined statement
thatbirdguythatuknownot May 20, 2022
10a0796
Update traceback.c
thatbirdguythatuknownot May 20, 2022
29141b8
Get proper length of the unicode string
thatbirdguythatuknownot May 20, 2022
5345744
Merge branch 'main' into patch-22
thatbirdguythatuknownot Jun 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ typedef uint16_t _Py_CODEUNIT;
Type is a void* to keep the format private in codeobject.c to force \
people to go through the proper APIs. */ \
void *co_extra; \
PyObject *co_source; /* unicode (source code of the code, used \
for tracebacks) */ \
char co_code_adaptive[(SIZE)]; \
}

Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct _mod; // Type defined in pycore_ast.h
// Export the symbol for test_peg_generator (built as a library)
PyAPI_FUNC(PyCodeObject*) _PyAST_Compile(
struct _mod *mod,
PyObject *src,
PyObject *filename,
PyCompilerFlags *flags,
int optimize,
Expand Down
11 changes: 11 additions & 0 deletions Include/internal/pycore_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ extern struct _mod* _PyParser_ASTFromFile(
PyCompilerFlags *flags,
int *errcode,
PyArena *arena);
extern struct _mod* _PyParser_InteractiveASTFromFile(
FILE *fp,
PyObject *filename_ob,
const char *enc,
int mode,
const char *ps1,
const char *ps2,
PyCompilerFlags *flags,
int *errcode,
PyObject **interactive_src,
PyArena *arena);

#ifdef __cplusplus
}
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ def f():
]
self.assertEqual(traceback_lines, expected_lines)

def test_interactive_traceback_reporting(self):
output = run_on_interactive_mode("1 / 0 / 3 / 4")
traceback_lines = output.splitlines()[-6:-1]
expected_lines = [
"Traceback (most recent call last):",
" File \"<stdin>\", line 1, in <module>",
" 1 / 0 / 3 / 4",
" ~~^~~",
"ZeroDivisionError: division by zero",
]
self.assertEqual(traceback_lines, expected_lines)

if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement fine grained error tracebacks for interactive mode. Patch by Jeremiah Vivian.
4 changes: 4 additions & 0 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
co->co_weakreflist = NULL;
co->co_extra = NULL;
co->_co_code = NULL;
co->co_source = NULL;

co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code),
Expand Down Expand Up @@ -1537,7 +1538,9 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_qualname);
Py_XDECREF(co->co_linetable);
Py_XDECREF(co->co_exceptiontable);
Py_XDECREF(co->co_source);
Py_XDECREF(co->_co_code);
Py_XDECREF(co->co_source);
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)co);
}
Expand Down Expand Up @@ -1687,6 +1690,7 @@ static PyMemberDef code_memberlist[] = {
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
{"co_linetable", T_OBJECT, OFF(co_linetable), READONLY},
{"co_exceptiontable", T_OBJECT, OFF(co_exceptiontable), READONLY},
{"co_source", T_OBJECT, OFF(co_source), READONLY},
{NULL} /* Sentinel */
};

Expand Down
15 changes: 14 additions & 1 deletion Parser/peg_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,18 @@ _PyParser_ASTFromFile(FILE *fp, PyObject *filename_ob, const char *enc,
return NULL;
}
return _PyPegen_run_parser_from_file_pointer(fp, mode, filename_ob, enc, ps1, ps2,
flags, errcode, arena);
flags, errcode, NULL, arena);
}

mod_ty
_PyParser_InteractiveASTFromFile(FILE *fp, PyObject *filename_ob, const char *enc,
int mode, const char *ps1, const char* ps2,
PyCompilerFlags *flags, int *errcode,
PyObject **interactive_src, PyArena *arena)
{
if (PySys_Audit("compile", "OO", Py_None, filename_ob) < 0) {
return NULL;
}
return _PyPegen_run_parser_from_file_pointer(fp, mode, filename_ob, enc, ps1, ps2,
flags, errcode, interactive_src, arena);
}
14 changes: 13 additions & 1 deletion Parser/pegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,8 @@ _PyPegen_run_parser(Parser *p)
mod_ty
_PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filename_ob,
const char *enc, const char *ps1, const char *ps2,
PyCompilerFlags *flags, int *errcode, PyArena *arena)
PyCompilerFlags *flags, int *errcode,
PyObject **interactive_src, PyArena *arena)
{
struct tok_state *tok = _PyTokenizer_FromFile(fp, enc, ps1, ps2);
if (tok == NULL) {
Expand Down Expand Up @@ -890,6 +891,17 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena
result = _PyPegen_run_parser(p);
_PyPegen_Parser_Free(p);

if (tok->fp_interactive && tok->interactive_src_start &&
result && interactive_src != NULL)
{
*interactive_src = PyUnicode_FromString(tok->interactive_src_start);
if (!interactive_src || _PyArena_AddPyObject(arena, *interactive_src) < 0) {
Py_XDECREF(interactive_src);
result = NULL;
goto error;
}
}

error:
_PyTokenizer_Free(tok);
return result;
Expand Down
3 changes: 2 additions & 1 deletion Parser/pegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehensi
Parser *_PyPegen_Parser_New(struct tok_state *, int, int, int, int *, PyArena *);
void _PyPegen_Parser_Free(Parser *);
mod_ty _PyPegen_run_parser_from_file_pointer(FILE *, int, PyObject *, const char *,
const char *, const char *, PyCompilerFlags *, int *, PyArena *);
const char *, const char *, PyCompilerFlags *,
int *, PyObject **, PyArena *);
void *_PyPegen_run_parser(Parser *);
mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *);
asdl_stmt_seq *_PyPegen_interactive_exit(Parser *);
Expand Down
2 changes: 1 addition & 1 deletion Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
_PyArena_Free(arena);
goto error;
}
result = (PyObject*)_PyAST_Compile(mod, filename,
result = (PyObject*)_PyAST_Compile(mod, source, filename,
&cf, optimize, arena);
_PyArena_Free(arena);
}
Expand Down
12 changes: 10 additions & 2 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ struct compiler {
struct compiler_unit *u; /* compiler state for current block */
PyObject *c_stack; /* Python list holding compiler_unit ptrs */
PyArena *c_arena; /* pointer to memory allocation arena */
PyObject *c_source; /* source code of a file/interactive line */
};

typedef struct {
Expand Down Expand Up @@ -577,8 +578,8 @@ compiler_init(struct compiler *c)
}

PyCodeObject *
_PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
int optimize, PyArena *arena)
_PyAST_Compile(mod_ty mod, PyObject *source, PyObject *filename,
PyCompilerFlags *flags, int optimize, PyArena *arena)
{
struct compiler c;
PyCodeObject *co = NULL;
Expand All @@ -601,6 +602,8 @@ _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
c.c_flags = flags;
c.c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
c.c_nestlevel = 0;
Py_XINCREF(source);
c.c_source = source;

_PyASTOptimizeState state;
state.optimize = c.c_optimize;
Expand Down Expand Up @@ -635,6 +638,7 @@ compiler_free(struct compiler *c)
Py_XDECREF(c->c_filename);
Py_DECREF(c->c_const_cache);
Py_DECREF(c->c_stack);
Py_XDECREF(c->c_source);
}

static PyObject *
Expand Down Expand Up @@ -8746,6 +8750,10 @@ assemble(struct compiler *c, int addNone)
}

co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags);
if (co) {
Py_XINCREF(c->c_source);
co->co_source = c->c_source;
}
error:
Py_XDECREF(consts);
assemble_free(&a);
Expand Down
33 changes: 23 additions & 10 deletions Python/pythonrun.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extern "C" {
/* Forward */
static void flush_io(void);
static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *,
PyCompilerFlags *, PyArena *);
PyCompilerFlags *, PyObject *, PyArena *);
static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *,
PyCompilerFlags *);
static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *);
Expand Down Expand Up @@ -237,8 +237,9 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename,
return -1;
}

mod = _PyParser_ASTFromFile(fp, filename, enc, Py_single_input,
ps1, ps2, flags, &errcode, arena);
PyObject *interactive_src = NULL;
mod = _PyParser_InteractiveASTFromFile(fp, filename, enc, Py_single_input,
ps1, ps2, flags, &errcode, &interactive_src, arena);

Py_XDECREF(v);
Py_XDECREF(w);
Expand All @@ -257,7 +258,7 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename,
return -1;
}
d = PyModule_GetDict(m);
v = run_mod(mod, filename, d, d, flags, arena);
v = run_mod(mod, filename, d, d, flags, interactive_src, arena);
_PyArena_Free(arena);
if (v == NULL) {
return -1;
Expand Down Expand Up @@ -1600,8 +1601,14 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals,
mod = _PyParser_ASTFromString(
str, &_Py_STR(anon_string), start, flags, arena);

if (mod != NULL)
ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena);
if (mod != NULL) {
PyObject *string = PyUnicode_FromString(str);
if (string == NULL) {
_PyArena_Free(arena);
return NULL;
}
ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, string, arena);
}
_PyArena_Free(arena);
return ret;
}
Expand All @@ -1626,11 +1633,12 @@ pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals,

PyObject *ret;
if (mod != NULL) {
ret = run_mod(mod, filename, globals, locals, flags, arena);
ret = run_mod(mod, filename, globals, locals, flags, NULL, arena);
}
else {
ret = NULL;
}

_PyArena_Free(arena);

return ret;
Expand Down Expand Up @@ -1719,10 +1727,10 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py

static PyObject *
run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
PyCompilerFlags *flags, PyArena *arena)
PyCompilerFlags *flags, PyObject *src, PyArena *arena)
{
PyThreadState *tstate = _PyThreadState_GET();
PyCodeObject *co = _PyAST_Compile(mod, filename, flags, -1, arena);
PyCodeObject *co = _PyAST_Compile(mod, src, filename, flags, -1, arena);
if (co == NULL)
return NULL;

Expand Down Expand Up @@ -1799,7 +1807,12 @@ Py_CompileStringObject(const char *str, PyObject *filename, int start,
_PyArena_Free(arena);
return result;
}
co = _PyAST_Compile(mod, filename, flags, optimize, arena);
PyObject *string = PyUnicode_FromString(str);
if (string == NULL) {
_PyArena_Free(arena);
return NULL;
}
co = _PyAST_Compile(mod, string, filename, flags, optimize, arena);
_PyArena_Free(arena);
return (PyObject *)co;
}
Expand Down
Loading