8000 bpo-40421: Add new PyFrame_GetLasti C-API function by markshannon · Pull Request #32413 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-40421: Add new PyFrame_GetLasti C-API function #32413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump 8000 to file
Failed to load files.
Loading
Diff view
Diff view
Add new PyFrame_GetLasti C-API function
  • Loading branch information
markshannon committed Apr 8, 2022
commit 1197d25f1844fbf128fe7429dd559c585d97c57b
11 changes: 11 additions & 0 deletions Doc/c-api/frame.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ See also :ref:`Reflection <reflection>`.
.. versionadded:: 3.11


.. c:function:: int PyFrame_GetLasti(PyFrameObject *frame)

Get the *frame*'s ``f_lasti`` attribute (:class:`dict`).

Returns -1 if ``frame.f_lasti`` is ``None``.

*frame* must not be ``NULL``.

.. versionadded:: 3.11


.. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame)

Get the *frame*'s ``f_locals`` attribute (:class:`dict`).
Expand Down
6 changes: 3 additions & 3 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ New Features

* Add new functions to get frame object attributes:
:c:func:`PyFrame_GetBuiltins`, :c:func:`PyFrame_GetGenerator`,
:c:func:`PyFrame_GetGlobals`.
:c:func:`PyFrame_GetGlobals`, :c:func:`PyFrame_GetLasti`.

Porting to Python 3.11
----------------------
Expand Down Expand Up @@ -1246,9 +1246,9 @@ Porting to Python 3.11
* ``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")``.
* ``f_lasti``: use :c:func:`PyFrame_GetLasti`.
Code using ``f_lasti`` with ``PyCode_Addr2Line()`` should use
:c:func:`PyFrame_GetLineNumber` instead.
:c:func:`PyFrame_GetLineNumber` instead; it may be faster.
* ``f_lineno``: use :c:func:`PyFrame_GetLineNumber`
* ``f_locals``: use :c:func:`PyFrame_GetLocals`.
* ``f_stackdepth``: removed.
Expand Down
1 change: 1 addition & 0 deletions Include/cpython/frameobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ PyAPI_FUNC(PyObject *) PyFrame_GetGlobals(PyFrameObject *frame);
PyAPI_FUNC(PyObject *) PyFrame_GetBuiltins(PyFrameObject *frame);

PyAPI_FUNC(PyObject *) PyFrame_GetGenerator(PyFrameObject *frame);
PyAPI_FUNC(int) PyFrame_GetLasti(PyFrameObject *frame);
1 change: 1 addition & 0 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,7 @@ def test_frame_getters(self):
self.assertEqual(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))
self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame))

def test_frame_get_generator(self):
gen = self.getgenframe()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add ``PyFrame_GetLasti`` C-API function to access frame object's ``lasti``
attribute safely from C code.
16 changes: 16 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5893,6 +5893,21 @@ frame_getbuiltins(PyObject *self, PyObject *frame)
return PyFrame_GetBuiltins((PyFrameObject *)frame);
}

static PyObject *
frame_getlasti(PyObject *self, PyObject *frame)
{
if (!PyFrame_Check(frame)) {
PyErr_SetString(PyExc_TypeError, "argument must be a frame");
return NULL;
}
int lasti = PyFrame_GetLasti((PyFrameObject *)frame);
if (lasti < 0) {
assert(lasti == -1);
Py_RETURN_NONE;
}
return PyLong_FromLong(lasti);
}


static PyObject *negative_dictoffset(PyObject *, PyObject *);
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
Expand Down Expand Up @@ -6186,6 +6201,7 @@ static PyMethodDef TestMethods[] = {
{"frame_getglobals", frame_getglobals, METH_O, NULL},
{"frame_getgenerator", frame_getgenerator, METH_O, NULL},
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
{"frame_getlasti", frame_getlasti, METH_O, NULL},
{NULL, NULL} /* sentinel */
};

Expand Down
12 changes: 11 additions & 1 deletion Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
// This only works when opcode is a non-quickened form:
assert(_PyOpcode_Deopt[opcode] == opcode);
int check_oparg = 0;
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code);
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code);
instruction < frame->prev_instr; instruction++)
{
int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)];
Expand Down Expand Up @@ -1135,6 +1135,16 @@ PyFrame_GetBuiltins(PyFrameObject *frame)
return frame_getbuiltins(frame, NULL);
}

int
PyFrame_GetLasti(PyFrameObject *frame)
{
int lasti = _PyInterpreterFrame_LASTI(frame->f_frame);
if (lasti < 0) {
return -1;
}
return lasti*2;
}

PyObject *
PyFrame_GetGenerator(PyFrameObject *frame)
{
Expand Down
0