Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 75b43a6

Browse files
authored
Add PyFrame_GetVar() (#46)
1 parent b079cc4 commit 75b43a6

4 files changed

Lines changed: 112 additions & 0 deletions

File tree

docs/api.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ Latest version of the header file:
2424
`pythoncapi_compat.h <https://raw.githubusercontent.com/python/pythoncapi-compat/master/pythoncapi_compat.h>`_.
2525

2626

27+
Python 3.12
28+
-----------
29+
30+
.. c:function:: PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
31+
32+
See `PyFrame_GetVar() documentation <https://docs.python.org/dev/c-api/frame.html#c.PyFrame_GetVar>`__.
33+
34+
Not available on PyPy.
35+
36+
.. c:function:: PyObject* PyFrame_GetVarString(PyFrameObject *frame, const char *name)
37+
38+
See `PyFrame_GetVarString() documentation <https://docs.python.org/dev/c-api/frame.html#c.PyFrame_GetVarString>`__.
39+
40+
Not available on PyPy.
41+
42+
2743
Python 3.11
2844
-----------
2945

docs/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Changelog
22
=========
33

4+
* 2022-11-04: Add ``PyFrame_GetVar()`` and ``PyFrame_GetVarString()``
5+
functions.
46
* 2022-08-04: Add ``PyCode_GetVarnames()``, ``PyCode_GetFreevars()``
57
and ``PyCode_GetCellvars()`` functions.
68
* 2022-06-14: Fix compatibility with C++ older than C++11.

pythoncapi_compat.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,57 @@ PyFrame_GetLasti(PyFrameObject *frame)
242242
#endif
243243

244244

245+
// gh-91248 added PyFrame_GetVar() to Python 3.12.0a2
246+
#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
247+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
248+
PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
249+
{
250+
PyObject *locals, *value;
251+
252+
locals = PyFrame_GetLocals(frame);
253+
if (locals == NULL) {
254+
return NULL;
255+
}
256+
#if PY_VERSION_HEX >= 0x03000000
257+
value = PyDict_GetItemWithError(locals, name);
258+
#else
259+
value = PyDict_GetItem(locals, name);
260+
#endif
261+
Py_DECREF(locals);
262+
263+
if (value == NULL) {
264+
if (PyErr_Occurred()) {
265+
return NULL;
266+
}
267+
#if PY_VERSION_HEX >= 0x03000000
268+
PyErr_Format(PyExc_NameError, "variable %R does not exist", name);
269+
#else
270+
PyErr_SetString(PyExc_NameError, "variable does not exist");
271+
#endif
272+
return NULL;
273+
}
274+
return Py_NewRef(value);
275+
}
276+
#endif
277+
278+
279+
// gh-91248 added PyFrame_GetVarString() to Python 3.12.0a2
280+
#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
281+
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
282+
PyFrame_GetVarString(PyFrameObject *frame, const char *name)
283+
{
284+
PyObject *name_obj, *value;
285+
name_obj = PyUnicode_FromString(name);
286+
if (name_obj == NULL) {
287+
return NULL;
288+
}
289+
value = PyFrame_GetVar(frame, name_obj);
290+
Py_DECREF(name_obj);
291+
return value;
292+
}
293+
#endif
294+
295+
245296
// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
246297
#if PY_VERSION_HEX < 0x030900A5
247298
PYCAPI_COMPAT_STATIC_INLINE(PyInterpreterState *)

tests/test_pythoncapi_compat_cext.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
#include "pythoncapi_compat.h"
55

6+
#ifdef NDEBUG
7+
# error "assertions must be enabled"
8+
#endif
9+
610
#ifdef Py_LIMITED_API
711
# error "Py_LIMITED_API is not supported"
812
#endif
@@ -138,6 +142,41 @@ test_py_is(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored))
138142

139143

140144
#if !defined(PYPY_VERSION)
145+
static void
146+
test_frame_getvar(PyFrameObject *frame)
147+
{
148+
// Make the assumption that test_frame_getvar() is only called by
149+
// _run_tests() of test_pythoncapi_compat.py and so that the "name"
150+
// variable exists.
151+
152+
// test PyFrame_GetVar() and PyFrame_GetVarString()
153+
PyObject *attr = PyUnicode_FromString("name");
154+
assert(attr != NULL);
155+
PyObject *name1 = PyFrame_GetVar(frame, attr);
156+
Py_DECREF(attr);
157+
assert(name1 != NULL);
158+
Py_DECREF(name1);
159+
160+
PyObject *name2 = PyFrame_GetVarString(frame, "name");
161+
assert(name2 != NULL);
162+
Py_DECREF(name2);
163+
164+
// test PyFrame_GetVar() and PyFrame_GetVarString() NameError
165+
PyObject *attr3 = PyUnicode_FromString("dontexist");
166+
assert(attr3 != NULL);
167+
PyObject *name3 = PyFrame_GetVar(frame, attr3);
168+
Py_DECREF(attr3);
169+
assert(name3 == NULL);
170+
assert(PyErr_ExceptionMatches(PyExc_NameError));
171+
PyErr_Clear();
172+
173+
PyObject *name4 = PyFrame_GetVarString(frame, "dontexist");
174+
assert(name4 == NULL);
175+
assert(PyErr_ExceptionMatches(PyExc_NameError));
176+
PyErr_Clear();
177+
}
178+
179+
141180
static PyObject *
142181
test_frame(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored))
143182
{
@@ -214,6 +253,10 @@ test_frame(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored))
214253
int lasti = PyFrame_GetLasti(frame);
215254
assert(lasti >= 0);
216255

256+
// test PyFrame_GetVar() and PyFrame_GetVarString()
257+
test_frame_getvar(frame);
258+
259+
// done
217260
Py_DECREF(frame);
218261
Py_RETURN_NONE;
219262
}

0 commit comments

Comments
 (0)