diff --git a/docs/api.rst b/docs/api.rst index b4b8570..635e219 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -27,6 +27,12 @@ Latest version of the header file: Python 3.11 ----------- +.. c:function:: PyObject* PyCode_GetCode(PyObject *code) + + See `PyCode_GetCode() documentation `__. + + Not available on PyPy. + .. c:function:: PyObject* PyFrame_GetBuiltins(PyFrameObject *frame) See `PyFrame_GetBuiltins() documentation `__. diff --git a/docs/changelog.rst b/docs/changelog.rst index a27ee28..ecb5565 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* 2022-05-03: Add ``PyCode_GetCode()`` function. * 2022-04-26: Rename the project from ``pythoncapi_compat`` to ``pythoncapi-compat``: replace the underscore separator with a dash. * 2022-04-08: Add functions ``PyFrame_GetLocals()``, ``PyFrame_GetGlobals()`` diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index d42971f..aadc03d 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -185,7 +185,7 @@ _PyFrame_GetCodeBorrow(PyFrameObject *frame) } -// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1 #if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*) PyFrame_GetBack(PyFrameObject *frame) @@ -487,6 +487,15 @@ PyFloat_Unpack8(const char *p, int le) #endif +// gh-92154 added PyCode_GetCode() to Python 3.11.0b1 +#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION) +PyObject *PyCode_GetCode(PyCodeObject *code) +{ + return Py_NewRef(code->co_code); +} +#endif + + // Py_UNUSED() was added to Python 3.4.0b2. #if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED) # if defined(__GNUC__) || defined(__clang__) diff --git a/tests/test_pythoncapi_compat.py b/tests/test_pythoncapi_compat.py index ac10c21..ba79fa1 100644 --- a/tests/test_pythoncapi_compat.py +++ b/tests/test_pythoncapi_compat.py @@ -149,9 +149,9 @@ def main(): global VERBOSE VERBOSE = ("-v" in sys.argv[1:] or "--verbose" in sys.argv[1:]) - # Implementing PyFrame_GetLocals() requires the internal C API in Python - # 3.11 alpha versions - if 0x30b0000 <= sys.hexversion < 0x30b00a7: + # Implementing PyFrame_GetLocals() and PyCode_GetCode() require the + # internal C API in Python 3.11 alpha versions + if 0x30b0000 <= sys.hexversion < 0x30b00b1: version = sys.version.split()[0] print("SKIP TESTS: Python %s is not supported" % version) return diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 298c067..ac5408a 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -489,6 +489,30 @@ test_float_pack(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) #endif +#if !defined(PYPY_VERSION) +static PyObject * +test_code(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) +{ + PyThreadState *tstate = PyThreadState_Get(); + PyFrameObject *frame = PyThreadState_GetFrame(tstate); + if (frame == NULL) { + PyErr_SetString(PyExc_AssertionError, "PyThreadState_GetFrame failed"); + return NULL; + } + PyCodeObject *code = PyFrame_GetCode(frame); + + PyObject *co_code = PyCode_GetCode(code); + assert(co_code != NULL); + assert(PyBytes_Check(co_code)); + Py_DECREF(co_code); + + Py_DECREF(code); + Py_DECREF(frame); + Py_RETURN_NONE; +} +#endif + + static struct PyMethodDef methods[] = { {"test_object", test_object, METH_NOARGS, NULL}, {"test_py_is", test_py_is, METH_NOARGS, NULL}, @@ -503,6 +527,9 @@ static struct PyMethodDef methods[] = { {"test_module", test_module, METH_NOARGS, NULL}, #if (PY_VERSION_HEX <= 0x030B00A1 || 0x030B00A7 <= PY_VERSION_HEX) && !defined(PYPY_VERSION) {"test_float_pack", test_float_pack, METH_NOARGS, NULL}, +#endif +#if !defined(PYPY_VERSION) + {"test_code", test_code, METH_NOARGS, NULL}, #endif {NULL, NULL, 0, NULL} };