[Python-checkins] gh-94936: C getters: co_varnames, co_cellvars, co_freevars (GH-95008)
miss-islington
webhook-mailer at python.org
Thu Aug 4 10:16:58 EDT 2022
https://github.com/python/cpython/commit/f2926358d1cd70625222eaf4b541584d2f2a1272
commit: f2926358d1cd70625222eaf4b541584d2f2a1272
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-08-04T07:16:52-07:00
summary:
gh-94936: C getters: co_varnames, co_cellvars, co_freevars (GH-95008)
(cherry picked from commit 42b102bbf9a9ae6fae8f6710202fb7afeeac277c)
Co-authored-by: Ken Jin <28750310+Fidget-Spinner at users.noreply.github.com>
files:
A Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst
M Doc/c-api/code.rst
M Doc/whatsnew/3.11.rst
M Include/cpython/code.h
M Modules/_testcapimodule.c
M Objects/codeobject.c
diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst
index 7915b81b4637..d4a3c4ae35fa 100644
--- a/Doc/c-api/code.rst
+++ b/Doc/c-api/code.rst
@@ -90,3 +90,28 @@ bound into a function.
.. versionadded:: 3.11
+.. c:function:: PyObject* PyCode_GetVarnames(PyCodeObject *co)
+
+ Equivalent to the Python code ``getattr(co, 'co_varnames')``.
+ Returns a new reference to a :c:type:`PyTupleObject` containing the names of
+ the local variables. On error, ``NULL`` is returned and an exception
+ is raised.
+
+ .. versionadded:: 3.11
+
+.. c:function:: PyObject* PyCode_GetCellvars(PyCodeObject *co)
+
+ Equivalent to the Python code ``getattr(co, 'co_cellvars')``.
+ Returns a new reference to a :c:type:`PyTupleObject` containing the names of
+ the local variables that are referenced by nested functions. On error, ``NULL``
+ is returned and an exception is raised.
+
+ .. versionadded:: 3.11
+
+.. c:function:: PyObject* PyCode_GetFreevars(PyCodeObject *co)
+
+ Equivalent to the Python code ``getattr(co, 'co_freevars')``.
+ Returns a new reference to a :c:type:`PyTupleObject` containing the names of
+ the free variables. On error, ``NULL`` is returned and an exception is raised.
+
+ .. versionadded:: 3.11
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 1067982c3dc3..c57f8a0f3e9f 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -1724,10 +1724,13 @@ Porting to Python 3.11
To get a custom code object: create a code object using the compiler,
then get a modified version with the ``replace`` method.
-* :c:type:`PyCodeObject` no longer has a ``co_code`` field. Instead,
- use ``PyObject_GetAttrString(code_object, "co_code")`` or
- :c:func:`PyCode_GetCode` to get the underlying bytes object.
- (Contributed by Brandt Bucher in :issue:`46841` and Ken Jin in :gh:`92154`.)
+* :c:type:`PyCodeObject` no longer has the ``co_code``, ``co_varnames``,
+ ``co_cellvars`` and ``co_freevars`` fields. Instead, use
+ :c:func:`PyCode_GetCode`, :c:func:`PyCode_GetVarnames`,
+ :c:func:`PyCode_GetCellvars` and :c:func:`PyCode_GetFreevars` respectively
+ to access them via the C API.
+ (Contributed by Brandt Bucher in :issue:`46841` and Ken Jin in :gh:`92154`
+ and :gh:`94936`.)
* The old trashcan macros (``Py_TRASHCAN_SAFE_BEGIN``/``Py_TRASHCAN_SAFE_END``)
are now deprecated. They should be replaced by the new macros
diff --git a/Include/cpython/code.h b/Include/cpython/code.h
index ef8c6422046d..7006060cc760 100644
--- a/Include/cpython/code.h
+++ b/Include/cpython/code.h
@@ -209,6 +209,12 @@ PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
/* Equivalent to getattr(code, 'co_code') in Python.
Returns a strong reference to a bytes object. */
PyAPI_FUNC(PyObject *) PyCode_GetCode(PyCodeObject *code);
+/* Equivalent to getattr(code, 'co_varnames') in Python. */
+PyAPI_FUNC(PyObject *) PyCode_GetVarnames(PyCodeObject *code);
+/* Equivalent to getattr(code, 'co_cellvars') in Python. */
+PyAPI_FUNC(PyObject *) PyCode_GetCellvars(PyCodeObject *code);
+/* Equivalent to getattr(code, 'co_freevars') in Python. */
+PyAPI_FUNC(PyObject *) PyCode_GetFreevars(PyCodeObject *code);
typedef enum _PyCodeLocationInfoKind {
/* short forms are 0 to 9 */
diff --git a/Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst b/Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst
new file mode 100644
index 000000000000..abef9bb376c8
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2022-07-19-22-37-40.gh-issue-94936.LGlmKv.rst
@@ -0,0 +1,3 @@
+Added :c:func:`PyCode_GetVarnames`, :c:func:`PyCode_GetCellvars` and
+:c:func:`PyCode_GetFreevars` for accessing ``co_varnames``, ``co_cellvars``
+and ``co_freevars`` respectively via the C API.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index b0a4687a973d..961616dae63e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -5952,21 +5952,79 @@ test_code_api(PyObject *self, PyObject *Py_UNUSED(args))
if (co == NULL) {
return NULL;
}
- PyObject *co_code = PyCode_GetCode(co);
- if (co_code == NULL) {
- Py_DECREF(co);
- return NULL;
- }
- assert(PyBytes_CheckExact(co_code));
- if (PyObject_Length(co_code) == 0) {
- PyErr_SetString(PyExc_ValueError, "empty co_code");
- Py_DECREF(co);
+ /* co_code */
+ {
+ PyObject *co_code = PyCode_GetCode(co);
+ if (co_code == NULL) {
+ goto fail;
+ }
+ assert(PyBytes_CheckExact(co_code));
+ if (PyObject_Length(co_code) == 0) {
+ PyErr_SetString(PyExc_ValueError, "empty co_code");
+ Py_DECREF(co_code);
+ goto fail;
+ }
Py_DECREF(co_code);
- return NULL;
+ }
+ /* co_varnames */
+ {
+ PyObject *co_varnames = PyCode_GetVarnames(co);
+ if (co_varnames == NULL) {
+ goto fail;
+ }
+ if (!PyTuple_CheckExact(co_varnames)) {
+ PyErr_SetString(PyExc_TypeError, "co_varnames not tuple");
+ Py_DECREF(co_varnames);
+ goto fail;
+ }
+ if (PyTuple_GET_SIZE(co_varnames) != 0) {
+ PyErr_SetString(PyExc_ValueError, "non-empty co_varnames");
+ Py_DECREF(co_varnames);
+ goto fail;
+ }
+ Py_DECREF(co_varnames);
+ }
+ /* co_cellvars */
+ {
+ PyObject *co_cellvars = PyCode_GetCellvars(co);
+ if (co_cellvars == NULL) {
+ goto fail;
+ }
+ if (!PyTuple_CheckExact(co_cellvars)) {
+ PyErr_SetString(PyExc_TypeError, "co_cellvars not tuple");
+ Py_DECREF(co_cellvars);
+ goto fail;
+ }
+ if (PyTuple_GET_SIZE(co_cellvars) != 0) {
+ PyErr_SetString(PyExc_ValueError, "non-empty co_cellvars");
+ Py_DECREF(co_cellvars);
+ goto fail;
+ }
+ Py_DECREF(co_cellvars);
+ }
+ /* co_freevars */
+ {
+ PyObject *co_freevars = PyCode_GetFreevars(co);
+ if (co_freevars == NULL) {
+ goto fail;
+ }
+ if (!PyTuple_CheckExact(co_freevars)) {
+ PyErr_SetString(PyExc_TypeError, "co_freevars not tuple");
+ Py_DECREF(co_freevars);
+ goto fail;
+ }
+ if (PyTuple_GET_SIZE(co_freevars) != 0) {
+ PyErr_SetString(PyExc_ValueError, "non-empty co_freevars");
+ Py_DECREF(co_freevars);
+ goto fail;
+ }
+ Py_DECREF(co_freevars);
}
Py_DECREF(co);
- Py_DECREF(co_code);
Py_RETURN_NONE;
+fail:
+ Py_DECREF(co);
+ return NULL;
}
static int
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 970aa6116bfa..c0151434489a 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -1399,18 +1399,36 @@ _PyCode_GetVarnames(PyCodeObject *co)
return get_localsplus_names(co, CO_FAST_LOCAL, co->co_nlocals);
}
+PyObject *
+PyCode_GetVarnames(PyCodeObject *code)
+{
+ return _PyCode_GetVarnames(code);
+}
+
PyObject *
_PyCode_GetCellvars(PyCodeObject *co)
{
return get_localsplus_names(co, CO_FAST_CELL, co->co_ncellvars);
}
+PyObject *
+PyCode_GetCellvars(PyCodeObject *code)
+{
+ return _PyCode_GetCellvars(code);
+}
+
PyObject *
_PyCode_GetFreevars(PyCodeObject *co)
{
return get_localsplus_names(co, CO_FAST_FREE, co->co_nfreevars);
}
+PyObject *
+PyCode_GetFreevars(PyCodeObject *code)
+{
+ return _PyCode_GetFreevars(code);
+}
+
static void
deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
{
More information about the Python-checkins
mailing list