.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
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
+
+
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
class Test_Pep523API(unittest.TestCase):
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "frameobject.h"
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
#include "pycore_bitutils.h" // _Py_bswap32()
#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble
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[] = {
{"get_configs", get_configs, METH_NOARGS},
_TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF
{"get_interp_settings", get_interp_settings, 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 */
};