Skip to content

Commit fceb8c3

Browse files
authored
[3.12] gh-111495: Add more tests on PyEval C APIs (#122789) (#128987) (#129023)
* 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) (cherry picked from commit 430ccbc)
1 parent 6df22cb commit fceb8c3

File tree

8 files changed

+171
-45
lines changed

8 files changed

+171
-45
lines changed

Lib/test/test_capi/test_eval.py

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import sys
2+
import unittest
3+
from test.support import import_helper
4+
5+
_testcapi = import_helper.import_module('_testcapi')
6+
7+
8+
class Tests(unittest.TestCase):
9+
def test_eval_get_func_name(self):
10+
eval_get_func_name = _testcapi.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 = _testcapi.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(_testcapi.eval_getlocals(),
47+
{'self': self,
48+
'x': 1})
49+
50+
y = 2
51+
self.assertEqual(_testcapi.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(_testcapi.eval_getglobals(),
59+
globals())
60+
61+
def test_eval_getbuiltins(self):
62+
# Test PyEval_GetBuiltins()
63+
self.assertEqual(_testcapi.eval_getbuiltins(),
64+
globals()['__builtins__'])
65+
66+
def test_eval_getframe(self):
67+
# Test PyEval_GetFrame()
68+
self.assertEqual(_testcapi.eval_getframe(),
69+
sys._getframe())
70+
71+
def test_eval_get_recursion_limit(self):
72+
# Test Py_GetRecursionLimit()
73+
self.assertEqual(_testcapi.eval_get_recursion_limit(),
74+
sys.getrecursionlimit())
75+
76+
def test_eval_set_recursion_limit(self):
77+
# Test Py_SetRecursionLimit()
78+
old_limit = sys.getrecursionlimit()
79+
try:
80+
limit = old_limit + 123
81+
_testcapi.eval_set_recursion_limit(limit)
82+
self.assertEqual(sys.getrecursionlimit(), limit)
83+
finally:
84+
sys.setrecursionlimit(old_limit)
85+
86+
87+
if __name__ == "__main__":
88+
unittest.main()

Lib/test/test_capi/test_misc.py

-30
Original file line numberDiff line numberDiff line change
@@ -879,36 +879,6 @@ def __init__(self):
879879
_testcapi.clear_managed_dict(c)
880880
self.assertEqual(c.__dict__, {})
881881

882-
def test_eval_get_func_name(self):
883-
def function_example(): ...
884-
885-
class A:
886-
def method_example(self): ...
887-
888-
self.assertEqual(_testcapi.eval_get_func_name(function_example),
889-
"function_example")
890-
self.assertEqual(_testcapi.eval_get_func_name(A.method_example),
891-
"method_example")
892-
self.assertEqual(_testcapi.eval_get_func_name(A().method_example),
893-
"method_example")
894-
self.assertEqual(_testcapi.eval_get_func_name(sum), "sum") # c function
895-
self.assertEqual(_testcapi.eval_get_func_name(A), "type")
896-
897-
def test_eval_get_func_desc(self):
898-
def function_example(): ...
899-
900-
class A:
901-
def method_example(self): ...
902-
903-
self.assertEqual(_testcapi.eval_get_func_desc(function_example),
904-
"()")
905-
self.assertEqual(_testcapi.eval_get_func_desc(A.method_example),
906-
"()")
907-
self.assertEqual(_testcapi.eval_get_func_desc(A().method_example),
908-
"()")
909-
self.assertEqual(_testcapi.eval_get_func_desc(sum), "()") # c function
910-
self.assertEqual(_testcapi.eval_get_func_desc(A), " object")
911-
912882
def test_function_get_code(self):
913883
import types
914884

Modules/Setup.stdlib.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
169169
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
170170
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
171-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/pytime.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/pyos.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c _testcapi/import.c
171+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/pytime.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/pyos.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c _testcapi/import.c _testcapi/eval.c
172172
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
173173

174174
# Some testing modules MUST be built as shared libraries.

Modules/_testcapi/eval.c

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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_get_recursion_limit(PyObject *module, PyObject *Py_UNUSED(args))
42+
{
43+
int limit = Py_GetRecursionLimit();
44+
return PyLong_FromLong(limit);
45+
}
46+
47+
static PyObject *
48+
eval_set_recursion_limit(PyObject *module, PyObject *args)
49+
{
50+
int limit;
51+
if (!PyArg_ParseTuple(args, "i", &limit)) {
52+
return NULL;
53+
}
54+
Py_SetRecursionLimit(limit);
55+
Py_RETURN_NONE;
56+
}
57+
58+
static PyMethodDef test_methods[] = {
59+
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
60+
{"eval_get_func_desc", eval_get_func_desc, METH_O, NULL},
61+
{"eval_getlocals", eval_getlocals, METH_NOARGS},
62+
{"eval_getglobals", eval_getglobals, METH_NOARGS},
63+
{"eval_getbuiltins", eval_getbuiltins, METH_NOARGS},
64+
{"eval_getframe", eval_getframe, METH_NOARGS},
65+
{"eval_get_recursion_limit", eval_get_recursion_limit, METH_NOARGS},
66+
{"eval_set_recursion_limit", eval_set_recursion_limit, METH_VARARGS},
67+
{NULL},
68+
};
69+
70+
int
71+
_PyTestCapi_Init_Eval(PyObject *m)
72+
{
73+
return PyModule_AddFunctions(m, test_methods);
74+
}

Modules/_testcapi/parts.h

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ int _PyTestCapi_Init_Immortal(PyObject *module);
5656
int _PyTestCapi_Init_GC(PyObject *module);
5757
int _PyTestCapi_Init_Sys(PyObject *module);
5858
int _PyTestCapi_Init_Import(PyObject *module);
59+
int _PyTestCapi_Init_Eval(PyObject *module);
5960

6061
#ifdef LIMITED_API_AVAILABLE
6162
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);

Modules/_testcapimodule.c

+3-14
Original file line numberDiff line numberDiff line change
@@ -2797,18 +2797,6 @@ test_frame_getvarstring(PyObject *self, PyObject *args)
27972797
}
27982798

27992799

2800-
static PyObject *
2801-
eval_get_func_name(PyObject *self, PyObject *func)
2802-
{
2803-
return PyUnicode_FromString(PyEval_GetFuncName(func));
2804-
}
2805-
2806-
static PyObject *
2807-
eval_get_func_desc(PyObject *self, PyObject *func)
2808-
{
2809-
return PyUnicode_FromString(PyEval_GetFuncDesc(func));
2810-
}
2811-
28122800
static PyObject *
28132801
gen_get_code(PyObject *self, PyObject *gen)
28142802
{
@@ -3460,8 +3448,6 @@ static PyMethodDef TestMethods[] = {
34603448
{"frame_new", frame_new, METH_VARARGS, NULL},
34613449
{"frame_getvar", test_frame_getvar, METH_VARARGS, NULL},
34623450
{"frame_getvarstring", test_frame_getvarstring, METH_VARARGS, NULL},
3463-
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
3464-
{"eval_get_func_desc", eval_get_func_desc, METH_O, NULL},
34653451
{"gen_get_code", gen_get_code, METH_O, NULL},
34663452
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
34673453
{"test_code_api", test_code_api, METH_NOARGS, NULL},
@@ -4174,6 +4160,9 @@ PyInit__testcapi(void)
41744160
if (_PyTestCapi_Init_Import(m) < 0) {
41754161
return NULL;
41764162
}
4163+
if (_PyTestCapi_Init_Eval(m) < 0) {
4164+
return NULL;
4165+
}
41774166

41784167
#ifndef LIMITED_API_AVAILABLE
41794168
PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);

PCbuild/_testcapi.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
<ClCompile Include="..\Modules\_testcapi\immortal.c" />
129129
<ClCompile Include="..\Modules\_testcapi\gc.c" />
130130
<ClCompile Include="..\Modules\_testcapi\run.c" />
131+
<ClCompile Include="..\Modules\_testcapi\eval.c" />
131132
</ItemGroup>
132133
<ItemGroup>
133134
<ResourceCompile Include="..\PC\python_nt.rc" />

PCbuild/_testcapi.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@
111111
<ClCompile Include="..\Modules\_testcapi\import.c">
112112
<Filter>Source Files</Filter>
113113
</ClCompile>
114+
<ClCompile Include="..\Modules\_testcapi\eval.c">
115+
<Filter>Source Files</Filter>
116+
</ClCompile>
114117
</ItemGroup>
115118
<ItemGroup>
116119
<ResourceCompile Include="..\PC\python_nt.rc">

0 commit comments

Comments
 (0)