Skip to content

Commit 430ccbc

Browse files
authored
[3.13] gh-111495: Add more tests on PyEval C APIs (#122789) (#128987)
* gh-111495: Add more tests on PyEval C APIs (#122789) * Add Lib/test/test_capi/test_eval.py * Add Modules/_testlimitedcapi/eval.c (cherry picked from commit bf8b374) * gh-111495: Fix refleaks in test_capi.test_eval tests (#122851) (cherry picked from commit b4a3160)
1 parent fff334e commit 430ccbc

File tree

9 files changed

+205
-65
lines changed

9 files changed

+205
-65
lines changed

Lib/test/test_capi/test_eval.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import sys
2+
import unittest
3+
from test.support import import_helper
4+
5+
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
6+
7+
8+
class Tests(unittest.TestCase):
9+
def test_eval_get_func_name(self):
10+
eval_get_func_name = _testlimitedcapi.eval_get_func_name
11+
12+
def function_example(): ...
13+
14+
class A:
15+
def method_example(self): ...
16+
17+
self.assertEqual(eval_get_func_name(function_example),
18+
"function_example")
19+
self.assertEqual(eval_get_func_name(A.method_example),
20+
"method_example")
21+
self.assertEqual(eval_get_func_name(A().method_example),
22+
"method_example")
23+
self.assertEqual(eval_get_func_name(sum), "sum") # c function
24+
self.assertEqual(eval_get_func_name(A), "type")
25+
26+
def test_eval_get_func_desc(self):
27+
eval_get_func_desc = _testlimitedcapi.eval_get_func_desc
28+
29+
def function_example(): ...
30+
31+
class A:
32+
def method_example(self): ...
33+
34+
self.assertEqual(eval_get_func_desc(function_example),
35+
"()")
36+
self.assertEqual(eval_get_func_desc(A.method_example),
37+
"()")
38+
self.assertEqual(eval_get_func_desc(A().method_example),
39+
"()")
40+
self.assertEqual(eval_get_func_desc(sum), "()") # c function
41+
self.assertEqual(eval_get_func_desc(A), " object")
42+
43+
def test_eval_getlocals(self):
44+
# Test PyEval_GetLocals()
45+
x = 1
46+
self.assertEqual(_testlimitedcapi.eval_getlocals(),
47+
{'self': self,
48+
'x': 1})
49+
50+
y = 2
51+
self.assertEqual(_testlimitedcapi.eval_getlocals(),
52+
{'self': self,
53+
'x': 1,
54+
'y': 2})
55+
56+
def test_eval_getglobals(self):
57+
# Test PyEval_GetGlobals()
58+
self.assertEqual(_testlimitedcapi.eval_getglobals(),
59+
globals())
60+
61+
def test_eval_getbuiltins(self):
62+
# Test PyEval_GetBuiltins()
63+
self.assertEqual(_testlimitedcapi.eval_getbuiltins(),
64+
globals()['__builtins__'])
65+
66+
def test_eval_getframe(self):
67+
# Test PyEval_GetFrame()
68+
self.assertEqual(_testlimitedcapi.eval_getframe(),
69+
sys._getframe())
70+
71+
def test_eval_getframe_builtins(self):
72+
# Test PyEval_GetFrameBuiltins()
73+
self.assertEqual(_testlimitedcapi.eval_getframe_builtins(),
74+
sys._getframe().f_builtins)
75+
76+
def test_eval_getframe_globals(self):
77+
# Test PyEval_GetFrameGlobals()
78+
self.assertEqual(_testlimitedcapi.eval_getframe_globals(),
79+
sys._getframe().f_globals)
80+
81+
def test_eval_getframe_locals(self):
82+
# Test PyEval_GetFrameLocals()
83+
self.assertEqual(_testlimitedcapi.eval_getframe_locals(),
84+
sys._getframe().f_locals)
85+
86+
def test_eval_get_recursion_limit(self):
87+
# Test Py_GetRecursionLimit()
88+
self.assertEqual(_testlimitedcapi.eval_get_recursion_limit(),
89+
sys.getrecursionlimit())
90+
91+
def test_eval_set_recursion_limit(self):
92+
# Test Py_SetRecursionLimit()
93+
old_limit = sys.getrecursionlimit()
94+
try:
95+
limit = old_limit + 123
96+
_testlimitedcapi.eval_set_recursion_limit(limit)
97+
self.assertEqual(sys.getrecursionlimit(), limit)
98+
finally:
99+
sys.setrecursionlimit(old_limit)
100+
101+
102+
if __name__ == "__main__":
103+
unittest.main()

Lib/test/test_capi/test_misc.py

-43
Original file line numberDiff line numberDiff line change
@@ -892,36 +892,6 @@ def __init__(self):
892892
_testcapi.clear_managed_dict(c)
893893
self.assertEqual(c.__dict__, {})
894894

895-
def test_eval_get_func_name(self):
896-
def function_example(): ...
897-
898-
class A:
899-
def method_example(self): ...
900-
901-
self.assertEqual(_testcapi.eval_get_func_name(function_example),
902-
"function_example")
903-
self.assertEqual(_testcapi.eval_get_func_name(A.method_example),
904-
"method_example")
905-
self.assertEqual(_testcapi.eval_get_func_name(A().method_example),
906-
"method_example")
907-
self.assertEqual(_testcapi.eval_get_func_name(sum), "sum") # c function
908-
self.assertEqual(_testcapi.eval_get_func_name(A), "type")
909-
910-
def test_eval_get_func_desc(self):
911-
def function_example(): ...
912-
913-
class A:
914-
def method_example(self): ...
915-
916-
self.assertEqual(_testcapi.eval_get_func_desc(function_example),
917-
"()")
918-
self.assertEqual(_testcapi.eval_get_func_desc(A.method_example),
919-
"()")
920-
self.assertEqual(_testcapi.eval_get_func_desc(A().method_example),
921-
"()")
922-
self.assertEqual(_testcapi.eval_get_func_desc(sum), "()") # c function
923-
self.assertEqual(_testcapi.eval_get_func_desc(A), " object")
924-
925895
def test_function_get_code(self):
926896
import types
927897

@@ -1180,19 +1150,6 @@ def genf(): yield
11801150
gen = genf()
11811151
self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code)
11821152

1183-
def test_pyeval_getlocals(self):
1184-
# Test PyEval_GetLocals()
1185-
x = 1
1186-
self.assertEqual(_testcapi.pyeval_getlocals(),
1187-
{'self': self,
1188-
'x': 1})
1189-
1190-
y = 2
1191-
self.assertEqual(_testcapi.pyeval_getlocals(),
1192-
{'self': self,
1193-
'x': 1,
1194-
'y': 2})
1195-
11961153

11971154
@requires_limited_api
11981155
class TestHeapTypeRelative(unittest.TestCase):

Modules/Setup.stdlib.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
165165
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
166166
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c
167-
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
167+
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
168168
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
169169
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
170170

Modules/_testcapimodule.c

-21
Original file line numberDiff line numberDiff line change
@@ -2646,18 +2646,6 @@ test_frame_getvarstring(PyObject *self, PyObject *args)
26462646
}
26472647

26482648

2649-
static PyObject *
2650-
eval_get_func_name(PyObject *self, PyObject *func)
2651-
{
2652-
return PyUnicode_FromString(PyEval_GetFuncName(func));
2653-
}
2654-
2655-
static PyObject *
2656-
eval_get_func_desc(PyObject *self, PyObject *func)
2657-
{
2658-
return PyUnicode_FromString(PyEval_GetFuncDesc(func));
2659-
}
2660-
26612649
static PyObject *
26622650
gen_get_code(PyObject *self, PyObject *gen)
26632651
{
@@ -3286,12 +3274,6 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args))
32863274
Py_RETURN_NONE;
32873275
}
32883276

3289-
static PyObject *
3290-
pyeval_getlocals(PyObject *module, PyObject *Py_UNUSED(args))
3291-
{
3292-
return Py_XNewRef(PyEval_GetLocals());
3293-
}
3294-
32953277
struct atexit_data {
32963278
int called;
32973279
PyThreadState *tstate;
@@ -3462,8 +3444,6 @@ static PyMethodDef TestMethods[] = {
34623444
{"frame_new", frame_new, METH_VARARGS, NULL},
34633445
{"frame_getvar", test_frame_getvar, METH_VARARGS, NULL},
34643446
{"frame_getvarstring", test_frame_getvarstring, METH_VARARGS, NULL},
3465-
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
3466-
{"eval_get_func_desc", eval_get_func_desc, METH_O, NULL},
34673447
{"gen_get_code", gen_get_code, METH_O, NULL},
34683448
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
34693449
{"test_code_api", test_code_api, METH_NOARGS, NULL},
@@ -3483,7 +3463,6 @@ static PyMethodDef TestMethods[] = {
34833463
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
34843464
{"function_set_warning", function_set_warning, METH_NOARGS},
34853465
{"test_critical_sections", test_critical_sections, METH_NOARGS},
3486-
{"pyeval_getlocals", pyeval_getlocals, METH_NOARGS},
34873466
{"test_atexit", test_atexit, METH_NOARGS},
34883467
{NULL, NULL} /* sentinel */
34893468
};

Modules/_testlimitedcapi.c

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ PyInit__testlimitedcapi(void)
4444
if (_PyTestLimitedCAPI_Init_Dict(mod) < 0) {
4545
return NULL;
4646
}
47+
if (_PyTestLimitedCAPI_Init_Eval(mod) < 0) {
48+
return NULL;
49+
}
4750
if (_PyTestLimitedCAPI_Init_Float(mod) < 0) {
4851
return NULL;
4952
}

Modules/_testlimitedcapi/eval.c

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include "parts.h"
2+
#include "util.h"
3+
4+
static PyObject *
5+
eval_get_func_name(PyObject *self, PyObject *func)
6+
{
7+
return PyUnicode_FromString(PyEval_GetFuncName(func));
8+
}
9+
10+
static PyObject *
11+
eval_get_func_desc(PyObject *self, PyObject *func)
12+
{
13+
return PyUnicode_FromString(PyEval_GetFuncDesc(func));
14+
}
15+
16+
static PyObject *
17+
eval_getlocals(PyObject *module, PyObject *Py_UNUSED(args))
18+
{
19+
return Py_XNewRef(PyEval_GetLocals());
20+
}
21+
22+
static PyObject *
23+
eval_getglobals(PyObject *module, PyObject *Py_UNUSED(args))
24+
{
25+
return Py_XNewRef(PyEval_GetGlobals());
26+
}
27+
28+
static PyObject *
29+
eval_getbuiltins(PyObject *module, PyObject *Py_UNUSED(args))
30+
{
31+
return Py_XNewRef(PyEval_GetBuiltins());
32+
}
33+
34+
static PyObject *
35+
eval_getframe(PyObject *module, PyObject *Py_UNUSED(args))
36+
{
37+
return Py_XNewRef(PyEval_GetFrame());
38+
}
39+
40+
static PyObject *
41+
eval_getframe_builtins(PyObject *module, PyObject *Py_UNUSED(args))
42+
{
43+
return PyEval_GetFrameBuiltins();
44+
}
45+
46+
static PyObject *
47+
eval_getframe_globals(PyObject *module, PyObject *Py_UNUSED(args))
48+
{
49+
return PyEval_GetFrameGlobals();
50+
}
51+
52+
static PyObject *
53+
eval_getframe_locals(PyObject *module, PyObject *Py_UNUSED(args))
54+
{
55+
return PyEval_GetFrameLocals();
56+
}
57+
58+
static PyObject *
59+
eval_get_recursion_limit(PyObject *module, PyObject *Py_UNUSED(args))
60+
{
61+
int limit = Py_GetRecursionLimit();
62+
return PyLong_FromLong(limit);
63+
}
64+
65+
static PyObject *
66+
eval_set_recursion_limit(PyObject *module, PyObject *args)
67+
{
68+
int limit;
69+
if (!PyArg_ParseTuple(args, "i", &limit)) {
70+
return NULL;
71+
}
72+
Py_SetRecursionLimit(limit);
73+
Py_RETURN_NONE;
74+
}
75+
76+
static PyMethodDef test_methods[] = {
77+
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
78+
{"eval_get_func_desc", eval_get_func_desc, METH_O, NULL},
79+
{"eval_getlocals", eval_getlocals, METH_NOARGS},
80+
{"eval_getglobals", eval_getglobals, METH_NOARGS},
81+
{"eval_getbuiltins", eval_getbuiltins, METH_NOARGS},
82+
{"eval_getframe", eval_getframe, METH_NOARGS},
83+
{"eval_getframe_builtins", eval_getframe_builtins, METH_NOARGS},
84+
{"eval_getframe_globals", eval_getframe_globals, METH_NOARGS},
85+
{"eval_getframe_locals", eval_getframe_locals, METH_NOARGS},
86+
{"eval_get_recursion_limit", eval_get_recursion_limit, METH_NOARGS},
87+
{"eval_set_recursion_limit", eval_set_recursion_limit, METH_VARARGS},
88+
{NULL},
89+
};
90+
91+
int
92+
_PyTestLimitedCAPI_Init_Eval(PyObject *m)
93+
{
94+
return PyModule_AddFunctions(m, test_methods);
95+
}

Modules/_testlimitedcapi/parts.h

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ int _PyTestLimitedCAPI_Init_ByteArray(PyObject *module);
2727
int _PyTestLimitedCAPI_Init_Bytes(PyObject *module);
2828
int _PyTestLimitedCAPI_Init_Complex(PyObject *module);
2929
int _PyTestLimitedCAPI_Init_Dict(PyObject *module);
30+
int _PyTestLimitedCAPI_Init_Eval(PyObject *module);
3031
int _PyTestLimitedCAPI_Init_Float(PyObject *module);
3132
int _PyTestLimitedCAPI_Init_HeaptypeRelative(PyObject *module);
3233
int _PyTestLimitedCAPI_Init_Import(PyObject *module);

PCbuild/_testlimitedcapi.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
<ClCompile Include="..\Modules\_testlimitedcapi\bytes.c" />
100100
<ClCompile Include="..\Modules\_testlimitedcapi\complex.c" />
101101
<ClCompile Include="..\Modules\_testlimitedcapi\dict.c" />
102+
<ClCompile Include="..\Modules\_testlimitedcapi\eval.c" />
102103
<ClCompile Include="..\Modules\_testlimitedcapi\float.c" />
103104
<ClCompile Include="..\Modules\_testlimitedcapi\heaptype_relative.c" />
104105
<ClCompile Include="..\Modules\_testlimitedcapi\import.c" />

PCbuild/_testlimitedcapi.vcxproj.filters

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<ClCompile Include="..\Modules\_testlimitedcapi\bytes.c" />
1515
<ClCompile Include="..\Modules\_testlimitedcapi\complex.c" />
1616
<ClCompile Include="..\Modules\_testlimitedcapi\dict.c" />
17+
<ClCompile Include="..\Modules\_testlimitedcapi\eval.c" />
1718
<ClCompile Include="..\Modules\_testlimitedcapi\float.c" />
1819
<ClCompile Include="..\Modules\_testlimitedcapi\heaptype_relative.c" />
1920
<ClCompile Include="..\Modules\_testlimitedcapi\import.c" />

0 commit comments

Comments
 (0)