Skip to content

Commit 5075201

Browse files
Update PyUnstable_InterpreterFrame_GetLocal to follow PyDict_GetItemRef convention
1 parent f7f33ad commit 5075201

4 files changed

Lines changed: 34 additions & 23 deletions

File tree

‎Doc/c-api/frame.rst‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,15 @@ Unless using :pep:`523`, you will not need this.
245245
.. versionadded:: 3.12
246246
247247
248-
.. c:function:: PyObject* PyUnstable_InterpreterFrame_GetLocal(struct _PyInterpreterFrame *frame, Py_ssize_t index)
248+
.. c:function:: int PyUnstable_InterpreterFrame_GetLocal(struct _PyInterpreterFrame *frame, Py_ssize_t index, PyObject **result)
249249
250-
Return a new :term:`strong reference` to the local variable at *index* in the
251-
frame's localsplus array, with cell and free variables unboxed to their
252-
contents. Free variables are resolved from the function closure, so this
253-
also works on a frame that has not started executing.
250+
Retrieve the local variable at *index* in the frame's localsplus array, with
251+
cell and free variables unboxed to their contents. Free variables are
252+
resolved from the function closure, so this also works on a frame that has
253+
not started executing.
254254
255-
*index* must be in range ``[0, co_nlocalsplus)``. Return ``NULL`` with an
256-
:exc:`IndexError` set if it is out of range, or ``NULL`` without an exception
257-
set if the slot is unset or hidden.
255+
* On success, store a new :term:`strong reference` in *result* and return ``1``.
256+
* If the slot is unset or hidden, store ``NULL`` in *result* and return ``0``.
257+
* On error, raise an exception, store ``NULL`` in *result* and return ``-1``.
258258
259259
.. versionadded:: next

‎Include/cpython/pyframe.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,5 @@ PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *
3838

3939
/* Returns a new (strong) reference to the local variable at `index` in the
4040
* frame's localsplus array. */
41-
PyAPI_FUNC(PyObject *) PyUnstable_InterpreterFrame_GetLocal(
42-
struct _PyInterpreterFrame *frame, Py_ssize_t index);
41+
PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLocal(
42+
struct _PyInterpreterFrame *frame, Py_ssize_t index, PyObject **result);

‎Modules/_testinternalcapi.c‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,12 +1533,13 @@ get_frame_locals(PyObject *self, PyObject *Py_UNUSED(ignored))
15331533
return NULL;
15341534
}
15351535
for (Py_ssize_t i = 0; i < n; i++) {
1536-
PyObject *value = PyUnstable_InterpreterFrame_GetLocal(frame, i);
1537-
if (value == NULL) {
1538-
if (PyErr_Occurred()) {
1539-
Py_DECREF(dict);
1540-
return NULL;
1541-
}
1536+
PyObject *value;
1537+
int rc = PyUnstable_InterpreterFrame_GetLocal(frame, i, &value);
1538+
if (rc < 0) {
1539+
Py_DECREF(dict);
1540+
return NULL;
1541+
}
1542+
if (rc == 0) {
15421543
continue; // unset or hidden slot
15431544
}
15441545
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);

‎Objects/frameobject.c‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,29 +2247,34 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject *co, int i,
22472247
}
22482248

22492249

2250-
PyObject *
2250+
int
22512251
PyUnstable_InterpreterFrame_GetLocal(_PyInterpreterFrame *frame,
2252-
Py_ssize_t index)
2252+
Py_ssize_t index, PyObject **result)
22532253
{
22542254
PyCodeObject *co = _PyFrame_GetCode(frame);
2255+
*result = NULL;
22552256
if (index < 0 || index >= co->co_nlocalsplus) {
22562257
PyErr_Format(
22572258
PyExc_IndexError,
22582259
"PyUnstable_InterpreterFrame_GetLocal: index %zd out of range [0, %d)",
22592260
index, co->co_nlocalsplus);
2260-
return NULL;
2261+
return -1;
22612262
}
22622263

22632264
int offset = PyUnstable_Code_GetFirstFree(co); // co_nlocalsplus - co_nfreevars
22642265
if (index < offset) {
22652266
// Local or cell variable. frame_get_var unboxes cells and copes with
22662267
// not-yet-started frames and arguments not yet promoted by MAKE_CELL.
22672268
if (_PyLocals_GetKind(co->co_localspluskinds, (int)index) & CO_FAST_HIDDEN) {
2268-
return NULL;
2269+
return 0;
22692270
}
22702271
PyObject *value = NULL;
22712272
frame_get_var(frame, co, (int)index, &value);
2272-
return value; // strong reference, or NULL if unset
2273+
if (value == NULL) {
2274+
return 0;
2275+
}
2276+
*result = value; // strong reference
2277+
return 1;
22732278
}
22742279

22752280
// Free variable: read from the function closure rather than localsplus.
@@ -2278,9 +2283,14 @@ PyUnstable_InterpreterFrame_GetLocal(_PyInterpreterFrame *frame,
22782283
{
22792284
PyFunctionObject *func = _PyFrame_GetFunction(frame);
22802285
PyObject *cell = PyTuple_GET_ITEM(func->func_closure, index - offset);
2281-
return PyCell_GetRef((PyCellObject *)cell);
2286+
PyObject *value = PyCell_GetRef((PyCellObject *)cell);
2287+
if (value == NULL) {
2288+
return 0;
2289+
}
2290+
*result = value;
2291+
return 1;
22822292
}
2283-
return NULL;
2293+
return 0;
22842294
}
22852295

22862296

0 commit comments

Comments
 (0)