8000 gh-94936: C getters: co_varnames, co_cellvars, co_freevars (#95008) · python/cpython@42b102b · GitHub
[go: up one dir, main page]

Skip to content

Commit 42b102b

Browse files
gh-94936: C getters: co_varnames, co_cellvars, co_freevars (#95008)
1 parent 0342c93 commit 42b102b

File tree

6 files changed

+128
-15
lines changed

6 files changed

+128
-15
lines changed

Doc/c-api/code.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,28 @@ bound into a function.
9090
9191
.. versionadded:: 3.11
9292
93+
.. c:function:: PyObject* PyCode_GetVarnames(PyCodeObject *co)
94+
95+
Equivalent to the Python code ``getattr(co, 'co_varnames')``.
96+
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
97+
the local variables. On error, ``NULL`` is returned and an exception
98+
is raised.
99+
100+
.. versionadded:: 3.11
101+
102+
.. c:function:: PyObject* PyCode_GetCellvars(PyCodeObject *co)
103+
104+
Equivalent to the Python code ``getattr(co, 'co_cellvars')``.
105+
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
106+
the local variables that are referenced by nested functions. On error, ``NULL``
107+
is returned and an exception is raised.
108+
109+
.. versionadded:: 3.11
110+
111+
.. c:function:: PyObject* PyCode_GetFreevars(PyCodeObject *co)
112+
113+
Equivalent to the Python code ``getattr(co, 'co_freevars')``.
114+
Returns a new reference to a :c:type:`PyTupleObject` containing the names of
115+
the free variables. On error, ``NULL`` is returned and an exception is raised.
116+
117+
.. versionadded:: 3.11

Doc/whatsnew/3.11.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,10 +1719,13 @@ Porting to Python 3.11
17191719
To get a custom code object: create a code object using the compiler,
17201720
then get a modified version with the ``replace`` method.
17211721

1722-
* :c:type:`PyCodeObject` no longer has a ``co_code`` field. Instead,
1723-
use ``PyObject_GetAttrString(code_object, "co_code")`` or
1724-
:c:func:`PyCode_GetCode` to get the underlying bytes object.
1725-
(Contributed by Brandt Bucher in :issue:`46841` and Ken Jin in :gh:`92154`.)
1722+
* :c:type:`PyCodeObject` no longer has the ``co_code``, ``co_varnames``,
1723+
``co_cellvars`` and ``co_freevars`` fields. Instead, use
1724+
:c:func:`PyCode_GetCode`, :c:func:`PyCode_GetVarnames`,
1725+
:c:func:`PyCode_GetCellvars` and :c:func:`PyCode_GetFreevars` respectively
1726+
to access them via the C API.
1727+
(Contributed by Brandt Bucher in :issue:`46841` and Ken Jin in :gh:`92154`
1728+
and :gh:`94936`.)
17261729

17271730
* The old trashcan macros (``Py_TRASHCAN_SAFE_BEGIN``/``Py_TRASHCAN_SAFE_END``)
17281731
are now deprecated. They should be replaced by the new macros

Include/cpython/code.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
210210
/* Equivalent to getattr(code, 'co_code') in Python.
211211
Returns a strong reference to a bytes object. */
212212
PyAPI_FUNC(PyObject *) PyCode_GetCode(PyCodeObject *code);
213+
/* Equivalent to getattr(code, 'co_varnames') in Python. */
214+
PyAPI_FUNC(PyObject *) PyCode_GetVarnames(PyCodeObject *code);
215+
/* Equivalent to getattr(code, 'co_cellvars') in Python. */
216+
PyAPI_FUNC(PyObject *) PyCode_GetCellvars(PyCodeObject *code);
217+
/* Equivalent to getattr(code, 'co_freevars') in Python. */
218+
PyAPI_FUNC(PyObject *) PyCode_GetFreevars(PyCodeObject *code);
213219

214220
typedef enum _PyCodeLocationInfoKind {
215221
/* short forms are 0 to 9 */
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added :c:func:`PyCode_GetVarnames`, :c:func:`PyCode_GetCellvars` and
2+
:c:func:`PyCode_GetFreevars` for accessing ``co_varnames``, ``co_cellvars``
3+
and ``co_freevars`` respectively via the C API.

Modules/_testcapimodule.c

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5600,21 +5600,79 @@ test_code_api(PyObject *self, PyObject *Py_UNUSED(args))
56005600
if (co == NULL) {
56015601
return NULL;
56025602
}
5603-
PyObject *co_code = PyCode_GetCode(co);
5604-
if (co_code == NULL) {
5605-
Py_DECREF(co);
5606-
return NULL;
5607-
}
5608-
assert(PyBytes_CheckExact(co_code));
5609-
if (PyObject_Length(co_code) == 0) {
5610-
PyErr_SetString(PyExc_ValueError, "empty co_code");
5611-
Py_DECREF(co);
5603+
/* co_code */
5604+
{
5605+
PyObject *co_code = PyCode_GetCode(co);
5606+
if (co_code == NULL) {
5607+
goto fail;
5608+
}
5609+
assert(PyBytes_CheckExact(co_code));
5610+
if (PyObject_Length(co_code) == 0) {
5611+
PyErr_SetString(PyExc_ValueError, "empty co_code");
5612+
Py_DECREF(co_code);
5613+
goto fail;
5614+
}
56125615
Py_DECREF(co_code);
5613-
return NULL;
5616+
}
5617+
/* co_varnames */
5618+
{
5619+
PyObject *co_varnames = PyCode_GetVarnames(co);
5620+
if (co_varnames == NULL) {
5621+
goto fail;
5622+
}
5623+
if (!PyTuple_CheckExact(co_varnames)) {
5624+
PyErr_SetString(PyExc_TypeError, "co_varnames not tuple");
5625+
Py_DECREF(co_varnames);
5626+
goto fail;
5627+
}
5628+
if (PyTuple_GET_SIZE(co_varnames) != 0) {
5629+
PyErr_SetString(PyExc_ValueError, "non-empty co_varnames");
5630+
Py_DECREF(co_varnames);
5631+
goto fail;
5632+
}
5633+
Py_DECREF(co_varnames);
5634+
}
5635+
/* co_cellvars */
5636+
{
5637+
PyObject *co_cellvars = PyCode_GetCellvars(co);
5638+
if (co_cellvars == NULL) {
5639+
10000 goto fail;
5640+
}
5641+
if (!PyTuple_CheckExact(co_cellvars)) {
5642+
PyErr_SetString(PyExc_TypeError, "co_cellvars not tuple");
5643+
Py_DECREF(co_cellvars);
5644+
goto fail;
5645+
}
5646+
if (PyTuple_GET_SIZE(co_cellvars) != 0) {
5647+
PyErr_SetString(PyExc_ValueError, "non-empty co_cellvars");
5648+
Py_DECREF(co_cellvars);
5649+
goto fail;
5650+
}
5651+
Py_DECREF(co_cellvars);
5652+
}
5653+
/* co_freevars */
5654+
{
5655+
PyObject *co_freevars = PyCode_GetFreevars(co);
5656+
if (co_freevars == NULL) {
5657+
goto fail;
5658+
}
5659+
if (!PyTuple_CheckExact(co_freevars)) {
5660+
PyErr_SetString(PyExc_TypeError, "co_freevars not tuple");
5661+
Py_DECREF(co_freevars);
5662+
goto fail;
5663+
}
5664+
if (PyTuple_GET_SIZE(co_freevars) != 0) {
5665+
PyErr_SetString(PyExc_ValueError, "non-empty co_freevars");
5666+
Py_DECREF(co_freevars);
5667+
goto fail;
5668+
}
5669+
Py_DECREF(co_freevars);
56145670
}
56155671
Py_DECREF(co);
5616-
Py_DECREF(co_code);
56175672
Py_RETURN_NONE;
5673+
fail:
5674+
Py_DECREF(co);
5675+
return NULL;
56185676
}
56195677

56205678
static int

Objects/codeobject.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,18 +1401,36 @@ _PyCode_GetVarnames(PyCodeObject *co)
14011401
return get_localsplus_names(co, CO_FAST_LOCAL, co->co_nlocals);
14021402
}
14031403

1404+
PyObject *
1405+
PyCode_GetVarnames(PyCodeObject *code)
1406+
{
1407+
return _PyCode_GetVarnames(code);
1408+
}
1409+
14041410
PyObject *
14051411
_PyCode_GetCellvars(PyCodeObject *co)
14061412
{
14071413
return get_localsplus_names(co, CO_FAST_CELL, co->co_ncellvars);
14081414
}
14091415

1416+
PyObject *
1417+
PyCode_GetCellvars(PyCodeObject *code)
1418+
{
1419+
return _PyCode_GetCellvars(code);
1420+
}
1421+
14101422
PyObject *
14111423
_PyCode_GetFreevars(PyCodeObject *co)
14121424
{
14131425
return get_localsplus_names(co, CO_FAST_FREE, co->co_nfreevars);
14141426
}
14151427

1428+
PyObject *
1429+
PyCode_GetFreevars(PyCodeObject *code)
1430+
{
1431+
return _PyCode_GetFreevars(code);
1432+
}
1433+
14161434
static void
14171435
deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
14181436
{

0 commit comments

Comments
 (0)
0