mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
[3.12] gh-117694: Improve tests for PyEval_EvalCodeEx() (GH-117695) (GH-117884)
(cherry picked from commit 57bdb75975
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
a00dd31ee7
commit
50b94b150e
2 changed files with 114 additions and 91 deletions
|
@ -1,11 +1,16 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
import builtins
|
||||||
|
from collections import UserDict
|
||||||
|
|
||||||
from test.support import import_helper
|
from test.support import import_helper
|
||||||
|
from test.support import swap_attr
|
||||||
|
|
||||||
|
|
||||||
# Skip this test if the _testcapi module isn't available.
|
# Skip this test if the _testcapi module isn't available.
|
||||||
_testcapi = import_helper.import_module('_testcapi')
|
_testcapi = import_helper.import_module('_testcapi')
|
||||||
|
|
||||||
|
NULL = None
|
||||||
|
|
||||||
|
|
||||||
class PyEval_EvalCodeExTests(unittest.TestCase):
|
class PyEval_EvalCodeExTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -13,43 +18,108 @@ class PyEval_EvalCodeExTests(unittest.TestCase):
|
||||||
def f():
|
def f():
|
||||||
return a
|
return a
|
||||||
|
|
||||||
self.assertEqual(_testcapi.eval_code_ex(f.__code__, dict(a=1)), 1)
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
code = f.__code__
|
||||||
|
self.assertEqual(eval_code_ex(code, dict(a=1)), 1)
|
||||||
|
|
||||||
# Need to force the compiler to use LOAD_NAME
|
self.assertRaises(NameError, eval_code_ex, code, {})
|
||||||
# def test_custom_locals(self):
|
self.assertRaises(SystemError, eval_code_ex, code, UserDict(a=1))
|
||||||
# def f():
|
self.assertRaises(SystemError, eval_code_ex, code, [])
|
||||||
# return
|
self.assertRaises(SystemError, eval_code_ex, code, 1)
|
||||||
|
# CRASHES eval_code_ex(code, NULL)
|
||||||
|
# CRASHES eval_code_ex(1, {})
|
||||||
|
# CRASHES eval_code_ex(NULL, {})
|
||||||
|
|
||||||
|
def test_custom_locals(self):
|
||||||
|
# Monkey-patch __build_class__ to get a class code object.
|
||||||
|
code = None
|
||||||
|
def build_class(func, name, /, *bases, **kwds):
|
||||||
|
nonlocal code
|
||||||
|
code = func.__code__
|
||||||
|
|
||||||
|
with swap_attr(builtins, '__build_class__', build_class):
|
||||||
|
class A:
|
||||||
|
# Uses LOAD_NAME for a
|
||||||
|
r[:] = [a]
|
||||||
|
|
||||||
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
results = []
|
||||||
|
g = dict(a=1, r=results)
|
||||||
|
self.assertIsNone(eval_code_ex(code, g))
|
||||||
|
self.assertEqual(results, [1])
|
||||||
|
self.assertIsNone(eval_code_ex(code, g, dict(a=2)))
|
||||||
|
self.assertEqual(results, [2])
|
||||||
|
self.assertIsNone(eval_code_ex(code, g, UserDict(a=3)))
|
||||||
|
self.assertEqual(results, [3])
|
||||||
|
self.assertIsNone(eval_code_ex(code, g, {}))
|
||||||
|
self.assertEqual(results, [1])
|
||||||
|
self.assertIsNone(eval_code_ex(code, g, NULL))
|
||||||
|
self.assertEqual(results, [1])
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, g, [])
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, g, 1)
|
||||||
|
self.assertRaises(NameError, eval_code_ex, code, dict(r=results), {})
|
||||||
|
self.assertRaises(NameError, eval_code_ex, code, dict(r=results), NULL)
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, dict(r=results), [])
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, dict(r=results), 1)
|
||||||
|
|
||||||
def test_with_args(self):
|
def test_with_args(self):
|
||||||
def f(a, b, c):
|
def f(a, b, c):
|
||||||
return a
|
return a
|
||||||
|
|
||||||
self.assertEqual(_testcapi.eval_code_ex(f.__code__, {}, {}, (1, 2, 3)), 1)
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
code = f.__code__
|
||||||
|
self.assertEqual(eval_code_ex(code, {}, {}, (1, 2, 3)), 1)
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (1, 2))
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (1, 2, 3, 4))
|
||||||
|
|
||||||
def test_with_kwargs(self):
|
def test_with_kwargs(self):
|
||||||
def f(a, b, c):
|
def f(a, b, c):
|
||||||
return a
|
return a
|
||||||
|
|
||||||
self.assertEqual(_testcapi.eval_code_ex(f.__code__, {}, {}, (), dict(a=1, b=2, c=3)), 1)
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
code = f.__code__
|
||||||
|
self.assertEqual(eval_code_ex(code, {}, {}, (), dict(a=1, b=2, c=3)), 1)
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (), dict(a=1, b=2))
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (), dict(a=1, b=2))
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (), dict(a=1, b=2, c=3, d=4))
|
||||||
|
|
||||||
def test_with_default(self):
|
def test_with_default(self):
|
||||||
def f(a):
|
def f(a):
|
||||||
return a
|
return a
|
||||||
|
|
||||||
self.assertEqual(_testcapi.eval_code_ex(f.__code__, {}, {}, (), {}, (1,)), 1)
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
code = f.__code__
|
||||||
|
self.assertEqual(eval_code_ex(code, {}, {}, (), {}, (1,)), 1)
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (), {}, ())
|
||||||
|
|
||||||
def test_with_kwarg_default(self):
|
def test_with_kwarg_default(self):
|
||||||
def f(*, a):
|
def f(*, a):
|
||||||
return a
|
return a
|
||||||
|
|
||||||
self.assertEqual(_testcapi.eval_code_ex(f.__code__, {}, {}, (), {}, (), dict(a=1)), 1)
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
code = f.__code__
|
||||||
|
self.assertEqual(eval_code_ex(code, {}, {}, (), {}, (), dict(a=1)), 1)
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (), {}, (), {})
|
||||||
|
self.assertRaises(TypeError, eval_code_ex, code, {}, {}, (), {}, (), NULL)
|
||||||
|
self.assertRaises(SystemError, eval_code_ex, code, {}, {}, (), {}, (), UserDict(a=1))
|
||||||
|
self.assertRaises(SystemError, eval_code_ex, code, {}, {}, (), {}, (), [])
|
||||||
|
self.assertRaises(SystemError, eval_code_ex, code, {}, {}, (), {}, (), 1)
|
||||||
|
|
||||||
def test_with_closure(self):
|
def test_with_closure(self):
|
||||||
a = 1
|
a = 1
|
||||||
|
b = 2
|
||||||
def f():
|
def f():
|
||||||
|
b
|
||||||
return a
|
return a
|
||||||
|
|
||||||
self.assertEqual(_testcapi.eval_code_ex(f.__code__, {}, {}, (), {}, (), {}, f.__closure__), 1)
|
eval_code_ex = _testcapi.eval_code_ex
|
||||||
|
code = f.__code__
|
||||||
|
self.assertEqual(eval_code_ex(code, {}, {}, (), {}, (), {}, f.__closure__), 1)
|
||||||
|
self.assertEqual(eval_code_ex(code, {}, {}, (), {}, (), {}, f.__closure__[::-1]), 2)
|
||||||
|
|
||||||
|
# CRASHES eval_code_ex(code, {}, {}, (), {}, (), {}, ()), 1)
|
||||||
|
# CRASHES eval_code_ex(code, {}, {}, (), {}, (), {}, NULL), 1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -2826,107 +2826,60 @@ eval_eval_code_ex(PyObject *mod, PyObject *pos_args)
|
||||||
|
|
||||||
PyObject **c_kwargs = NULL;
|
PyObject **c_kwargs = NULL;
|
||||||
|
|
||||||
if (!PyArg_UnpackTuple(pos_args,
|
if (!PyArg_ParseTuple(pos_args,
|
||||||
"eval_code_ex",
|
"OO|OO!O!O!OO:eval_code_ex",
|
||||||
2,
|
&code,
|
||||||
8,
|
&globals,
|
||||||
&code,
|
&locals,
|
||||||
&globals,
|
&PyTuple_Type, &args,
|
||||||
&locals,
|
&PyDict_Type, &kwargs,
|
||||||
&args,
|
&PyTuple_Type, &defaults,
|
||||||
&kwargs,
|
&kw_defaults,
|
||||||
&defaults,
|
&closure))
|
||||||
&kw_defaults,
|
|
||||||
&closure))
|
|
||||||
{
|
{
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyCode_Check(code)) {
|
NULLABLE(code);
|
||||||
PyErr_SetString(PyExc_TypeError,
|
NULLABLE(globals);
|
||||||
"code must be a Python code object");
|
NULLABLE(locals);
|
||||||
goto exit;
|
NULLABLE(kw_defaults);
|
||||||
}
|
NULLABLE(closure);
|
||||||
|
|
||||||
if (!PyDict_Check(globals)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "globals must be a dict");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (locals && !PyMapping_Check(locals)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "locals must be a mapping");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (locals == Py_None) {
|
|
||||||
locals = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject **c_args = NULL;
|
PyObject **c_args = NULL;
|
||||||
Py_ssize_t c_args_len = 0;
|
Py_ssize_t c_args_len = 0;
|
||||||
|
if (args) {
|
||||||
if (args)
|
c_args = &PyTuple_GET_ITEM(args, 0);
|
||||||
{
|
c_args_len = PyTuple_Size(args);
|
||||||
if (!PyTuple_Check(args)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "args must be a tuple");
|
|
||||||
goto exit;
|
|
||||||
} else {
|
|
||||||
c_args = &PyTuple_GET_ITEM(args, 0);
|
|
||||||
c_args_len = PyTuple_Size(args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_ssize_t c_kwargs_len = 0;
|
Py_ssize_t c_kwargs_len = 0;
|
||||||
|
if (kwargs) {
|
||||||
if (kwargs)
|
c_kwargs_len = PyDict_Size(kwargs);
|
||||||
{
|
if (c_kwargs_len > 0) {
|
||||||
if (!PyDict_Check(kwargs)) {
|
c_kwargs = PyMem_NEW(PyObject*, 2 * c_kwargs_len);
|
||||||
PyErr_SetString(PyExc_TypeError, "keywords must be a dict");
|
if (!c_kwargs) {
|
||||||
goto exit;
|
PyErr_NoMemory();
|
||||||
} else {
|
goto exit;
|
||||||
c_kwargs_len = PyDict_Size(kwargs);
|
|
||||||
if (c_kwargs_len > 0) {
|
|
||||||
c_kwargs = PyMem_NEW(PyObject*, 2 * c_kwargs_len);
|
|
||||||
if (!c_kwargs) {
|
|
||||||
PyErr_NoMemory();
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_ssize_t i = 0;
|
|
||||||
Py_ssize_t pos = 0;
|
|
||||||
|
|
||||||
while (PyDict_Next(kwargs,
|
|
||||||
&pos,
|
|
||||||
&c_kwargs[i],
|
|
||||||
&c_kwargs[i + 1]))
|
|
||||||
{
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
c_kwargs_len = i / 2;
|
|
||||||
/* XXX This is broken if the caller deletes dict items! */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_ssize_t i = 0;
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
while (PyDict_Next(kwargs, &pos, &c_kwargs[i], &c_kwargs[i + 1])) {
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
c_kwargs_len = i / 2;
|
||||||
|
/* XXX This is broken if the caller deletes dict items! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject **c_defaults = NULL;
|
PyObject **c_defaults = NULL;
|
||||||
Py_ssize_t c_defaults_len = 0;
|
Py_ssize_t c_defaults_len = 0;
|
||||||
|
if (defaults) {
|
||||||
if (defaults && PyTuple_Check(defaults)) {
|
|
||||||
c_defaults = &PyTuple_GET_ITEM(defaults, 0);
|
c_defaults = &PyTuple_GET_ITEM(defaults, 0);
|
||||||
c_defaults_len = PyTuple_Size(defaults);
|
c_defaults_len = PyTuple_Size(defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kw_defaults && !PyDict_Check(kw_defaults)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "kw_defaults must be a dict");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closure && !PyTuple_Check(closure)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "closure must be a tuple of cells");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
result = PyEval_EvalCodeEx(
|
result = PyEval_EvalCodeEx(
|
||||||
code,
|
code,
|
||||||
globals,
|
globals,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue