Skip to content

Commit 2ab4ec1

Browse files
committed
Unstable C API tier: Add a test for the code API
1 parent 7ce874a commit 2ab4ec1

File tree

6 files changed

+124
-1
lines changed

6 files changed

+124
-1
lines changed

Modules/Setup.stdlib.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
170170
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
171171
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
172-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.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/structmember.c
172+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.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/structmember.c _testcapi/code.c
173173
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
174174

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

Modules/_testcapi/code.c

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "parts.h"
2+
3+
static Py_ssize_t
4+
get_code_extra_index(PyInterpreterState* interp) {
5+
Py_ssize_t result = -1;
6+
7+
static const char *key = "_testcapi.frame_evaluation.code_index";
8+
9+
PyObject *interp_dict = PyInterpreterState_GetDict(interp); // borrowed
10+
assert(interp_dict); // real users would handle missing dict... somehow
11+
12+
PyObject *index_obj = PyDict_GetItemString(interp_dict, key); // borrowed
13+
Py_ssize_t index = 0;
14+
if (!index_obj) {
15+
if (PyErr_Occurred()) {
16+
goto finally;
17+
}
18+
index = PyUnstable_Eval_RequestCodeExtraIndex(NULL);
19+
if (index < 0 || PyErr_Occurred()) {
20+
goto finally;
21+
}
22+
index_obj = PyLong_FromSsize_t(index); // strong ref
23+
if (!index_obj) {
24+
goto finally;
25+
}
26+
int res = PyDict_SetItemString(interp_dict, key, index_obj);
27+
Py_DECREF(index_obj);
28+
if (res < 0) {
29+
goto finally;
30+
}
31+
}
32+
else {
33+
index = PyLong_AsSsize_t(index_obj);
34+
if (index == -1 && PyErr_Occurred()) {
35+
goto finally;
36+
}
37+
}
38+
39+
result = index;
40+
finally:
41+
return result;
42+
}
43+
44+
static PyObject *
45+
test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable))
46+
{
47+
PyObject *result = NULL;
48+
PyObject *test_module = NULL;
49+
PyObject *test_func = NULL;
50+
51+
// Get or initialize interpreter-specific code object storage index
52+
PyInterpreterState *interp = PyInterpreterState_Get();
53+
if (!interp) {
54+
return NULL;
55+
}
56+
Py_ssize_t code_extra_index = get_code_extra_index(interp);
57+
if (PyErr_Occurred()) {
58+
goto finally;
59+
}
60+
61+
// Get a function to test with
62+
// This can be any Python function. Use `test.test_misc.testfunction`.
63+
test_module = PyImport_ImportModule("test.test_capi.test_misc");
64+
if (!test_module) {
65+
goto finally;
66+
}
67+
test_func = PyObject_GetAttrString(test_module, "testfunction");
68+
if (!test_func) {
69+
goto finally;
70+
}
71+
PyObject *test_func_code = PyFunction_GetCode(test_func); // borrowed
72+
if (!test_func_code) {
73+
goto finally;
74+
}
75+
76+
// Check the value is initially NULL
77+
void *extra;
78+
int res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra);
79+
if (res < 0) {
80+
goto finally;
81+
}
82+
assert (extra == NULL);
83+
84+
// Set another code extra value
85+
res = PyUnstable_Code_SetExtra(test_func_code, code_extra_index, (void*)(uintptr_t)77);
86+
if (res < 0) {
87+
goto finally;
88+
}
89+
// Assert it was set correctly
90+
res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra);
91+
if (res < 0) {
92+
goto finally;
93+
}
94+
assert ((uintptr_t)extra == 77);
95+
96+
result = Py_NewRef(Py_None);
97+
finally:
98+
Py_XDECREF(test_module);
99+
Py_XDECREF(test_func);
100+
return result;
101+
}
102+
103+
static PyMethodDef TestMethods[] = {
104+
{"test_code_extra", test_code_extra, METH_NOARGS},
105+
{NULL},
106+
};
107+
108+
int
109+
_PyTestCapi_Init_Code(PyObject *m) {
110+
if (PyModule_AddFunctions(m, TestMethods) < 0) {
111+
return -1;
112+
}
113+
114+
return 0;
115+
}

Modules/_testcapi/parts.h

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ int _PyTestCapi_Init_Watchers(PyObject *module);
3636
int _PyTestCapi_Init_Long(PyObject *module);
3737
int _PyTestCapi_Init_Float(PyObject *module);
3838
int _PyTestCapi_Init_Structmember(PyObject *module);
39+
int _PyTestCapi_Init_Code(PyObject *module);
3940

4041
#ifdef LIMITED_API_AVAILABLE
4142
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);

Modules/_testcapimodule.c

+3
Original file line numberDiff line numberDiff line change
@@ -4075,6 +4075,9 @@ PyInit__testcapi(void)
40754075
if (_PyTestCapi_Init_Structmember(m) < 0) {
40764076
return NULL;
40774077
}
4078+
if (_PyTestCapi_Init_Code(m) < 0) {
4079+
return NULL;
4080+
}
40784081

40794082
#ifndef LIMITED_API_AVAILABLE
40804083
PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);

PCbuild/_testcapi.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
<ClCompile Include="..\Modules\_testcapi\float.c" />
108108
<ClCompile Include="..\Modules\_testcapi\long.c" />
109109
<ClCompile Include="..\Modules\_testcapi\structmember.c" />
110+
<ClCompile Include="..\Modules\_testcapi\code.c" />
110111
</ItemGroup>
111112
<ItemGroup>
112113
<ResourceCompile Include="..\PC\python_nt.rc" />

PCbuild/_testcapi.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
<ClCompile Include="..\Modules\_testcapi\structmember.c">
5252
<Filter>Source Files</Filter>
5353
</ClCompile>
54+
<ClCompile Include="..\Modules\_testcapi\code.c">
55+
<Filter>Source Files</Filter>
56+
</ClCompile>
5457
</ItemGroup>
5558
<ItemGroup>
5659
<ResourceCompile Include="..\PC\python_nt.rc">

0 commit comments

Comments
 (0)