Skip to content

Commit

Permalink
gh-92154: Expose PyCode_GetCode in the C API (GH-92168)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fidget-Spinner committed May 3, 2022
1 parent 1d4a9a4 commit 6c7249f
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Doc/c-api/code.rst
Expand Up @@ -76,3 +76,17 @@ bound into a function.
information is not available for any particular element.
Returns ``1`` if the function succeeds and 0 otherwise.
.. c:function:: PyObject* PyCode_GetCode(PyCodeObject *co)
Equivalent to the Python code ``getattr(co, 'co_code')``.
Returns a strong reference to a :c:type:`PyBytesObject` representing the
bytecode in a code object. On error, ``NULL`` is returned and an exception
is raised.
This ``PyBytesObject`` may be created on-demand by the interpreter and does
not necessarily represent the bytecode actually executed by CPython. The
primary use case for this function is debuggers and profilers.
.. versionadded:: 3.11
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.11.rst
Expand Up @@ -1412,6 +1412,11 @@ C API Changes
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`.)

New Features
------------

Expand Down
3 changes: 3 additions & 0 deletions Include/cpython/code.h
Expand Up @@ -202,6 +202,9 @@ PyAPI_FUNC(int) _PyCode_GetExtra(PyObject *code, Py_ssize_t index,
PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
void *extra);

/* Equivalent to getattr(code, 'co_code') in Python.
Returns a strong reference to a bytes object. */
PyAPI_FUNC(PyObject *) PyCode_GetCode(PyCodeObject *code);

typedef enum _PyCodeLocationInfoKind {
/* short forms are 0 to 9 */
Expand Down
@@ -0,0 +1,2 @@
Added the :c:func:`PyCode_GetCode` function. This function does the
equivalent of the Python code ``getattr(code_object, 'co_code')``.
24 changes: 24 additions & 0 deletions Modules/_testcapimodule.c
Expand Up @@ -5931,6 +5931,29 @@ get_feature_macros(PyObject *self, PyObject *Py_UNUSED(args))
return result;
}

static PyObject *
test_code_api(PyObject *self, PyObject *Py_UNUSED(args))
{
PyCodeObject *co = PyCode_NewEmpty("_testcapi", "dummy", 1);
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);
Py_DECREF(co_code);
return NULL;
}
Py_DECREF(co);
Py_DECREF(co_code);
Py_RETURN_NONE;
}

static PyObject *negative_dictoffset(PyObject *, PyObject *);
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
Expand Down Expand Up @@ -6227,6 +6250,7 @@ static PyMethodDef TestMethods[] = {
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
{"frame_getlasti", frame_getlasti, METH_O, NULL},
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
{"test_code_api", test_code_api, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};

Expand Down
5 changes: 5 additions & 0 deletions Objects/codeobject.c
Expand Up @@ -1370,6 +1370,11 @@ _PyCode_GetCode(PyCodeObject *co)
return code;
}

PyObject *
PyCode_GetCode(PyCodeObject *co)
{
return _PyCode_GetCode(co);
}

/******************
* PyCode_Type
Expand Down

0 comments on commit 6c7249f

Please sign in to comment.