* The ``repr()`` output for AST nodes now includes more information.
(Contributed by Tomas R in :gh:`116022`.)
+* :func:`ast.parse`, when called with an AST as input, now always verifies
+ that the root node type is appropriate.
+ (Contributed by Irit Katriel in :gh:`130139`.)
+
calendar
--------
PyObject* PyAST_mod2obj(mod_ty t);
+int PyAst_CheckMode(PyObject *ast, int mode);
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
int PyAST_Check(PyObject* obj);
tree = ast.parse(snippet)
compile(tree, '<string>', 'exec')
+ def test_parse_invalid_ast(self):
+ # see gh-130139
+ for optval in (-1, 0, 1, 2):
+ self.assertRaises(TypeError, ast.parse, ast.Constant(42),
+ optimize=optval)
+
def test_optimization_levels__debug__(self):
cases = [(-1, '__debug__'), (0, '__debug__'), (1, False), (2, False)]
for (optval, expected) in cases:
self.check_ast_roundtrip(f"'''{docstring}'''")
def test_constant_tuples(self):
- self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
+ self.check_src_roundtrip(ast.Module([ast.Constant(value=(1,))]), "(1,)")
self.check_src_roundtrip(
- ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
+ ast.Module([ast.Constant(value=(1, 2, 3))]), "(1, 2, 3)"
)
def test_function_type(self):
--- /dev/null
+Fix bug where :func:`ast.parse` did not error on AST input which is not of the
+correct type, when called with optimize=False.
}
/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */
-mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
+int PyAst_CheckMode(PyObject *ast, int mode)
{
const char * const req_name[] = {"Module", "Expression", "Interactive"};
- int isinstance;
-
- if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
- return NULL;
- }
struct ast_state *state = get_ast_state();
if (state == NULL) {
- return NULL;
+ return -1;
}
PyObject *req_type[3];
req_type[2] = state->Interactive_type;
assert(0 <= mode && mode <= 2);
-
- isinstance = PyObject_IsInstance(ast, req_type[mode]);
- if (isinstance == -1)
- return NULL;
+ int isinstance = PyObject_IsInstance(ast, req_type[mode]);
+ if (isinstance == -1) {
+ return -1;
+ }
if (!isinstance) {
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
req_name[mode], _PyType_Name(Py_TYPE(ast)));
+ return -1;
+ }
+ return 0;
+}
+
+mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
+{
+ if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
+ return NULL;
+ }
+
+ struct ast_state *state = get_ast_state();
+ if (state == NULL) {
+ return NULL;
+ }
+
+ if (PyAst_CheckMode(ast, mode) < 0) {
return NULL;
}
f.write(textwrap.dedent("""
PyObject* PyAST_mod2obj(mod_ty t);
+ int PyAst_CheckMode(PyObject *ast, int mode);
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
int PyAST_Check(PyObject* obj);
}
/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */
-mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
+int PyAst_CheckMode(PyObject *ast, int mode)
{
const char * const req_name[] = {"Module", "Expression", "Interactive"};
- int isinstance;
-
- if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
- return NULL;
- }
struct ast_state *state = get_ast_state();
if (state == NULL) {
- return NULL;
+ return -1;
}
PyObject *req_type[3];
req_type[2] = state->Interactive_type;
assert(0 <= mode && mode <= 2);
-
- isinstance = PyObject_IsInstance(ast, req_type[mode]);
- if (isinstance == -1)
- return NULL;
+ int isinstance = PyObject_IsInstance(ast, req_type[mode]);
+ if (isinstance == -1) {
+ return -1;
+ }
if (!isinstance) {
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
req_name[mode], _PyType_Name(Py_TYPE(ast)));
+ return -1;
+ }
+ return 0;
+}
+
+mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
+{
+ if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
+ return NULL;
+ }
+
+ struct ast_state *state = get_ast_state();
+ if (state == NULL) {
+ return NULL;
+ }
+
+ if (PyAst_CheckMode(ast, mode) < 0) {
return NULL;
}
goto error;
if (is_ast) {
if ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST) {
+ if (PyAst_CheckMode(source, compile_mode) < 0) {
+ goto error;
+ }
// return an un-optimized AST
result = Py_NewRef(source);
}