mirror of https://github.com/python/cpython
GH-96803: Document and test new unstable internal frame API functions (GH-104211)
Weaken contract of PyUnstable_InterpreterFrame_GetCode to return PyObject*.
This commit is contained in:
parent
68b5f08b72
commit
cfa517d5a6
|
@ -130,3 +130,38 @@ See also :ref:`Reflection <reflection>`.
|
||||||
.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
|
.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
|
||||||
|
|
||||||
Return the line number that *frame* is currently executing.
|
Return the line number that *frame* is currently executing.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Internal Frames
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Unless using :pep:`523`, you will not need this.
|
||||||
|
|
||||||
|
.. c:struct:: _PyInterpreterFrame
|
||||||
|
|
||||||
|
The interpreter's internal frame representation.
|
||||||
|
|
||||||
|
.. versionadded:: 3.11
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame);
|
||||||
|
|
||||||
|
Return a :term:`strong reference` to the code object for the frame.
|
||||||
|
|
||||||
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame);
|
||||||
|
|
||||||
|
Return the byte offset into the last executed instruction.
|
||||||
|
|
||||||
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame);
|
||||||
|
|
||||||
|
Return the currently executing line number, or -1 if there is no line number.
|
||||||
|
|
||||||
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
|
||||||
|
|
||||||
/* Returns the code object of the frame (strong reference).
|
/* Returns the code object of the frame (strong reference).
|
||||||
* Does not raise an exception. */
|
* Does not raise an exception. */
|
||||||
PyAPI_FUNC(PyCodeObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame);
|
PyAPI_FUNC(PyObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame);
|
||||||
|
|
||||||
/* Returns a byte ofsset into the last executed instruction.
|
/* Returns a byte ofsset into the last executed instruction.
|
||||||
* Does not raise an exception. */
|
* Does not raise an exception. */
|
||||||
|
|
|
@ -1744,6 +1744,30 @@ class Test_ModuleStateAccess(unittest.TestCase):
|
||||||
self.assertIs(Subclass().get_defining_module(), self.module)
|
self.assertIs(Subclass().get_defining_module(), self.module)
|
||||||
|
|
||||||
|
|
||||||
|
class TestInternalFrameApi(unittest.TestCase):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def func():
|
||||||
|
return sys._getframe()
|
||||||
|
|
||||||
|
def test_code(self):
|
||||||
|
frame = self.func()
|
||||||
|
code = _testinternalcapi.iframe_getcode(frame)
|
||||||
|
self.assertIs(code, self.func.__code__)
|
||||||
|
|
||||||
|
def test_lasti(self):
|
||||||
|
frame = self.func()
|
||||||
|
lasti = _testinternalcapi.iframe_getlasti(frame)
|
||||||
|
self.assertGreater(lasti, 0)
|
||||||
|
self.assertLess(lasti, len(self.func.__code__.co_code))
|
||||||
|
|
||||||
|
def test_line(self):
|
||||||
|
frame = self.func()
|
||||||
|
line = _testinternalcapi.iframe_getline(frame)
|
||||||
|
firstline = self.func.__code__.co_firstlineno
|
||||||
|
self.assertEqual(line, firstline + 2)
|
||||||
|
|
||||||
|
|
||||||
SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100
|
SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100
|
||||||
|
|
||||||
class Test_Pep523API(unittest.TestCase):
|
class Test_Pep523API(unittest.TestCase):
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#define PY_SSIZE_T_CLEAN
|
#define PY_SSIZE_T_CLEAN
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "frameobject.h"
|
||||||
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
|
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
|
||||||
#include "pycore_bitutils.h" // _Py_bswap32()
|
#include "pycore_bitutils.h" // _Py_bswap32()
|
||||||
#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble
|
#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble
|
||||||
|
@ -757,6 +758,38 @@ clear_extension(PyObject *self, PyObject *args)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
iframe_getcode(PyObject *self, PyObject *frame)
|
||||||
|
{
|
||||||
|
if (!PyFrame_Check(frame)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct _PyInterpreterFrame *f = ((PyFrameObject *)frame)->f_frame;
|
||||||
|
return PyUnstable_InterpreterFrame_GetCode(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
iframe_getline(PyObject *self, PyObject *frame)
|
||||||
|
{
|
||||||
|
if (!PyFrame_Check(frame)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct _PyInterpreterFrame *f = ((PyFrameObject *)frame)->f_frame;
|
||||||
|
return PyLong_FromLong(PyUnstable_InterpreterFrame_GetLine(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
iframe_getlasti(PyObject *self, PyObject *frame)
|
||||||
|
{
|
||||||
|
if (!PyFrame_Check(frame)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct _PyInterpreterFrame *f = ((PyFrameObject *)frame)->f_frame;
|
||||||
|
return PyLong_FromLong(PyUnstable_InterpreterFrame_GetLasti(f));
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef module_functions[] = {
|
static PyMethodDef module_functions[] = {
|
||||||
{"get_configs", get_configs, METH_NOARGS},
|
{"get_configs", get_configs, METH_NOARGS},
|
||||||
|
@ -781,6 +814,9 @@ static PyMethodDef module_functions[] = {
|
||||||
_TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF
|
_TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF
|
||||||
{"get_interp_settings", get_interp_settings, METH_VARARGS, NULL},
|
{"get_interp_settings", get_interp_settings, METH_VARARGS, NULL},
|
||||||
{"clear_extension", clear_extension, METH_VARARGS, NULL},
|
{"clear_extension", clear_extension, METH_VARARGS, NULL},
|
||||||
|
{"iframe_getcode", iframe_getcode, METH_O, NULL},
|
||||||
|
{"iframe_getline", iframe_getline, METH_O, NULL},
|
||||||
|
{"iframe_getlasti", iframe_getlasti, METH_O, NULL},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -146,10 +146,10 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
|
||||||
|
|
||||||
/* Unstable API functions */
|
/* Unstable API functions */
|
||||||
|
|
||||||
PyCodeObject *
|
PyObject *
|
||||||
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
|
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
|
||||||
{
|
{
|
||||||
PyCodeObject *code = frame->f_code;
|
PyObject *code = (PyObject *)frame->f_code;
|
||||||
Py_INCREF(code);
|
Py_INCREF(code);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue