mirror of https://github.com/python/cpython
bpo-40421: Add missing getters for frame object attributes to C-API. (GH-32114)
This commit is contained in:
parent
44e915028d
commit
74b95d86e0
|
@ -30,6 +30,17 @@ See also :ref:`Reflection <reflection>`.
|
|||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFrame_GetBuiltins(PyFrameObject *frame)
|
||||
|
||||
Get the *frame*'s ``f_builtins`` attribute.
|
||||
|
||||
Return a :term:`strong reference`. The result cannot be ``NULL``.
|
||||
|
||||
*frame* must not be ``NULL``.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
|
||||
|
||||
Get the *frame* code.
|
||||
|
@ -41,6 +52,30 @@ See also :ref:`Reflection <reflection>`.
|
|||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFrame_GetGenerator(PyFrameObject *frame)
|
||||
|
||||
Get the generator, coroutine, or async generator that owns this frame,
|
||||
or ``NULL`` if this frame is not owned by a generator.
|
||||
Does not raise an exception, even if the return value is ``NULL``.
|
||||
|
||||
Return a :term:`strong reference`, or ``NULL``.
|
||||
|
||||
*frame* must not be ``NULL``.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFrame_GetGlobals(PyFrameObject *frame)
|
||||
|
||||
Get the *frame*'s ``f_globals`` attribute.
|
||||
|
||||
Return a :term:`strong reference`. The result cannot be ``NULL``.
|
||||
|
||||
*frame* must not be ``NULL``.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame)
|
||||
|
||||
Get the *frame*'s ``f_locals`` attribute (:class:`dict`).
|
||||
|
|
|
@ -868,6 +868,9 @@ New Features
|
|||
:c:func:`PyFloat_Unpack8`.
|
||||
(Contributed by Victor Stinner in :issue:`46906`.)
|
||||
|
||||
* Add new functions to get frame object attributes:
|
||||
:c:func:`PyFrame_GetBuiltins`, :c:func:`PyFrame_GetGenerator`,
|
||||
:c:func:`PyFrame_GetGlobals`.
|
||||
|
||||
Porting to Python 3.11
|
||||
----------------------
|
||||
|
@ -985,13 +988,13 @@ Porting to Python 3.11
|
|||
|
||||
* ``f_back``: use :c:func:`PyFrame_GetBack`.
|
||||
* ``f_blockstack``: removed.
|
||||
* ``f_builtins``: use ``PyObject_GetAttrString((PyObject*)frame, "f_builtins")``.
|
||||
* ``f_builtins``: use :c:func:`PyFrame_GetBuiltins`.
|
||||
* ``f_code``: use :c:func:`PyFrame_GetCode`.
|
||||
* ``f_gen``: removed.
|
||||
* ``f_globals``: use ``PyObject_GetAttrString((PyObject*)frame, "f_globals")``.
|
||||
* ``f_gen``: use :c:func:`PyFrame_GetGenerator`.
|
||||
* ``f_globals``: use :c:func:`PyFrame_GetGlobals`.
|
||||
* ``f_iblock``: removed.
|
||||
* ``f_lasti``: use ``PyObject_GetAttrString((PyObject*)frame, "f_lasti")``.
|
||||
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` must use
|
||||
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` should use
|
||||
:c:func:`PyFrame_GetLineNumber` instead.
|
||||
* ``f_lineno``: use :c:func:`PyFrame_GetLineNumber`
|
||||
* ``f_locals``: use :c:func:`PyFrame_GetLocals`.
|
||||
|
|
|
@ -24,3 +24,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
|
|||
|
||||
PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
|
||||
PyAPI_FUNC(PyObject *) PyFrame_GetLocals(PyFrameObject *frame);
|
||||
|
||||
PyAPI_FUNC(PyObject *) PyFrame_GetGlobals(PyFrameObject *frame);
|
||||
PyAPI_FUNC(PyObject *) PyFrame_GetBuiltins(PyFrameObject *frame);
|
||||
|
||||
PyAPI_FUNC(PyObject *) PyFrame_GetGenerator(PyFrameObject *frame);
|
||||
|
|
|
@ -1087,5 +1087,25 @@ class Test_ModuleStateAccess(unittest.TestCase):
|
|||
self.assertIs(Subclass().get_defining_module(), self.module)
|
||||
|
||||
|
||||
class Test_FrameAPI(unittest.TestCase):
|
||||
|
||||
def getframe(self):
|
||||
return sys._getframe()
|
||||
|
||||
def getgenframe(self):
|
||||
yield sys._getframe()
|
||||
|
||||
def test_frame_getters(self):
|
||||
frame = self.getframe()
|
||||
self.assertEquals(frame.f_locals, _testcapi.frame_getlocals(frame))
|
||||
self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame))
|
||||
self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame))
|
||||
|
||||
def test_frame_get_generator(self):
|
||||
gen = self.getgenframe()
|
||||
frame = next(gen)
|
||||
self.assertIs(gen, _testcapi.frame_getgenerator(frame))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Add ``PyFrame_GetBuiltins``, ``PyFrame_GetGenerator`` and
|
||||
``PyFrame_GetGlobals`` C-API functions to access frame object attributes
|
||||
safely from C code.
|
|
@ -5853,6 +5853,46 @@ test_float_unpack(PyObject *self, PyObject *args)
|
|||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_getlocals(PyObject *self, PyObject *frame)
|
||||
{
|
||||
if (!PyFrame_Check(frame)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||
return NULL;
|
||||
}
|
||||
return PyFrame_GetLocals((PyFrameObject *)frame);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_getglobals(PyObject *self, PyObject *frame)
|
||||
{
|
||||
if (!PyFrame_Check(frame)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||
return NULL;
|
||||
}
|
||||
return PyFrame_GetGlobals((PyFrameObject *)frame);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_getgenerator(PyObject *self, PyObject *frame)
|
||||
{
|
||||
if (!PyFrame_Check(frame)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||
return NULL;
|
||||
}
|
||||
return PyFrame_GetGenerator((PyFrameObject *)frame);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_getbuiltins(PyObject *self, PyObject *frame)
|
||||
{
|
||||
if (!PyFrame_Check(frame)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||
return NULL;
|
||||
}
|
||||
return PyFrame_GetBuiltins((PyFrameObject *)frame);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *negative_dictoffset(PyObject *, PyObject *);
|
||||
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
|
||||
|
@ -6142,6 +6182,10 @@ static PyMethodDef TestMethods[] = {
|
|||
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
|
||||
{"float_pack", test_float_pack, METH_VARARGS, NULL},
|
||||
{"float_unpack", test_float_unpack, METH_VARARGS, NULL},
|
||||
{"frame_getlocals", frame_getlocals, METH_O, NULL},
|
||||
{"frame_getglobals", frame_getglobals, METH_O, NULL},
|
||||
{"frame_getgenerator", frame_getgenerator, METH_O, NULL},
|
||||
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -1134,6 +1134,28 @@ PyFrame_GetLocals(PyFrameObject *frame)
|
|||
return frame_getlocals(frame, NULL);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyFrame_GetGlobals(PyFrameObject *frame)
|
||||
{
|
||||
return frame_getglobals(frame, NULL);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyFrame_GetBuiltins(PyFrameObject *frame)
|
||||
{
|
||||
return frame_getbuiltins(frame, NULL);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyFrame_GetGenerator(PyFrameObject *frame)
|
||||
{
|
||||
if (frame->f_frame->owner != FRAME_OWNED_BY_GENERATOR) {
|
||||
return NULL;
|
||||
}
|
||||
PyGenObject *gen = _PyFrame_GetGenerator(frame->f_frame);
|
||||
return Py_NewRef(gen);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue