diff --git a/docs/api.rst b/docs/api.rst index 08cf7f0..7a5ba70 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -74,8 +74,9 @@ Python 3.15 See `PyUnstable_SetImmortal() documentation `__. - Availability: Python 3.13 and newer, not available on PyPy, not available - with the limited C API. + Availability: Python 3.13 and newer. + + Not available on PyPy, and not on the limited C API. Python 3.14 ----------- @@ -278,13 +279,17 @@ Python 3.14 See `PyConfig_Get() documentation `__. - Not available on the limited C API. + Availability: Python 3.9 and newer. + + Not available on PyPy and not on the limited C API. .. c:function:: int PyConfig_GetInt(const char *name, int *value) See `PyConfig_GetInt() documentation `__. - Not available on the limited C API. + Availability: Python 3.9 and newer. + + Not available on PyPy and not on the limited C API. .. c:function:: int PyUnstable_Object_IsUniquelyReferenced(PyObject *op) @@ -633,39 +638,41 @@ Python 3.11 Pack a C double as the IEEE 754 binary16 half-precision format. - Availability: Python 3.6 and newer. Not available on PyPy nor on limited C - API 3.10 and older. + Availability: Python 3.6 and newer. + + Not available on PyPy nor on limited C API. .. c:function:: int PyFloat_Pack4(double x, unsigned char *p, int le) Pack a C double as the IEEE 754 binary32 single precision format. - Not available on PyPy nor on limited C API 3.10 and older. + Not available on PyPy nor on limited C API. .. c:function:: int PyFloat_Pack8(double x, unsigned char *p, int le) Pack a C double as the IEEE 754 binary64 double precision format. - Not available on PyPy nor on limited C API 3.10 and older. + Not available on PyPy nor on limited C API. .. c:function:: double PyFloat_Unpack2(const unsigned char *p, int le) Unpack the IEEE 754 binary16 half-precision format as a C double. - Availability: Python 3.6 and newer. Not available on PyPy nor on limited C - API 3.10 and older. + Availability: Python 3.6 and newer. + + Not available on PyPy nor on limited C API. .. c:function:: double PyFloat_Unpack4(const unsigned char *p, int le) Unpack the IEEE 754 binary32 single precision format as a C double. - Not available on PyPy nor on limited C API 3.10 and older. + Not available on PyPy nor on limited C API. .. c:function:: double PyFloat_Unpack8(const unsigned char *p, int le) Unpack the IEEE 754 binary64 double precision format as a C double. - Not available on PyPy nor on limited C API 3.10 and older. + Not available on PyPy nor on limited C API. .. c:function:: PyObject* PyType_GetName(PyTypeObject *type) @@ -797,7 +804,7 @@ PyThreadState See `PyThreadState_GetFrame() documentation `__. - Not available on PyPy + Availability: PyPy 3.11 and newer, and limited C API 3.9. .. c:function:: PyInterpreterState* PyThreadState_GetInterpreter(PyThreadState *tstate) diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index 0ab84e1..735ab24 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -24,7 +24,7 @@ extern "C" { #include // fclose() #include // memcpy() -// Python 3.11.0b4 added PyFrame_Back() to Python.h +// Python 3.11.0b4 added PyFrame_GetBack() to Python.h #if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION) # include "frameobject.h" // PyFrameObject, PyFrame_GetBack() #endif @@ -341,7 +341,7 @@ static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) #endif #if ((!defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000) \ - && !defined(PYPY_VERSION)) + && (!defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030B0000)) static inline PyFrameObject* _PyThreadState_GetFrameBorrow(PyThreadState *tstate) { @@ -432,7 +432,8 @@ static inline PyObject* PyObject_CallNoArgs(PyObject *func) // bpo-39245 made PyObject_CallOneArg() public (previously called // _PyObject_CallOneArg) in Python 3.9.0a4 // PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11 -#if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4 +#if (!defined(PyObject_CallOneArg) \ + && (PY_VERSION_HEX < 0x030900A4 || defined(Py_LIMITED_API))) static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg) { return PyObject_CallFunctionObjArgs(func, arg, NULL); @@ -471,8 +472,10 @@ PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value) // bpo-40024 added PyModule_AddType() to Python 3.9.0a5 // On Windows, PyModule_AddType() was added to limited C API 3.9. #if (PY_VERSION_HEX < 0x030900A5 \ - || (defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x03090000)) -static inline int PyModule_AddType(PyObject *module, PyTypeObject *type) + || (defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x03090000) \ + || (defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030A0000 && defined(MS_WINDOWS))) +static inline int +_PythonCAPICompat_Module_AddType(PyObject *module, PyTypeObject *type) { #ifndef Py_LIMITED_API const char *name, *dot; @@ -514,12 +517,23 @@ static inline int PyModule_AddType(PyObject *module, PyTypeObject *type) return res; #endif } + +#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030A0000 && defined(MS_WINDOWS) + // On Python 3.9, PyModule_AddType() is part of the limited C API, + // but the function is not exported in the stable ABI. +# define PyModule_AddType _PythonCAPICompat_Module_AddType +#else +static inline int PyModule_AddType(PyObject *module, PyTypeObject *type) +{ + return _PythonCAPICompat_Module_AddType(module, type); +} +#endif #endif // bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6. // bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2. -// On Windows, PyObject_GC_IsTracked() was only added to limited C API 3.10. +// On Windows, PyObject_GC_IsTracked() was only added to stable ABI 3.10. #if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) static inline int PyObject_GC_IsTracked(PyObject* obj) { @@ -529,7 +543,7 @@ static inline int PyObject_GC_IsTracked(PyObject* obj) // bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6. // bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final. -// On Windows, PyObject_GC_IsFinalized() was only added to limited C API 3.10. +// On Windows, PyObject_GC_IsFinalized() was only added to stable ABI 3.10. #if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) static inline int PyObject_GC_IsFinalized(PyObject *obj) { @@ -971,7 +985,7 @@ static inline int Py_IsFinalizing(void) // gh-108323 added PyDict_ContainsString() to Python 3.13.0a1 -#if PY_VERSION_HEX < 0x030D00A1 +#if PY_VERSION_HEX < 0x030D00A1 || defined(Py_LIMITED_API) static inline int PyDict_ContainsString(PyObject *op, const char *key) { PyObject *key_obj = PyUnicode_FromString(key); @@ -1076,6 +1090,7 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_ #endif { #if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030a0000 + // Limited C API 3.9 and older bytes = PyUnicode_AsUTF8String(unicode); if (bytes == NULL) { // Memory allocation failure. The API cannot report error, @@ -1086,7 +1101,8 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_ utf8 = PyBytes_AsString(bytes); len = PyBytes_Size(bytes); #else - // Python 3.10 added PyUnicode_AsUTF8AndSize() to the limited C API + // Python 3.12 and older, and limited C API 3.10 and newer. + // Python 3.10 added PyUnicode_AsUTF8AndSize() to the limited C API. utf8 = PyUnicode_AsUTF8AndSize(unicode, &len); if (utf8 == NULL) { // Memory allocation failure. The API cannot report error, @@ -1297,10 +1313,11 @@ static inline int PyTime_PerfCounter(PyTime_t *result) // gh-111389 added hash constants to Python 3.13.0a5. These constants were // added first as private macros to Python 3.4.0b1 and PyPy 7.3.8. -#if (!defined(PyHASH_BITS) \ - && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \ - || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \ - && PYPY_VERSION_NUM >= 0x07030800))) +#if ((!defined(PyHASH_BITS) \ + && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \ + || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \ + && PYPY_VERSION_NUM >= 0x07030800))) \ + && !defined(Py_LIMITED_API)) # define PyHASH_BITS _PyHASH_BITS # define PyHASH_MODULUS _PyHASH_MODULUS # define PyHASH_INF _PyHASH_INF @@ -1443,10 +1460,10 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value, #endif #if PY_VERSION_HEX < 0x030D00B3 -# define Py_BEGIN_CRITICAL_SECTION(op) { -# define Py_END_CRITICAL_SECTION() } -# define Py_BEGIN_CRITICAL_SECTION2(a, b) { -# define Py_END_CRITICAL_SECTION2() } +# define Py_BEGIN_CRITICAL_SECTION(op) { +# define Py_END_CRITICAL_SECTION() } +# define Py_BEGIN_CRITICAL_SECTION2(a, b) { +# define Py_END_CRITICAL_SECTION2() } #endif #if PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) @@ -1826,7 +1843,8 @@ static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len) || (defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030e0000)) static inline int PyIter_NextItem(PyObject *iter, PyObject **item) { -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 + // Limited API: PyType_GetSlot() only accepts all types since Python 3.10 +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000 iternextfunc tp_iternext; assert(iter != NULL); @@ -1835,7 +1853,6 @@ static inline int PyIter_NextItem(PyObject *iter, PyObject **item) #ifndef Py_LIMITED_API tp_iternext = Py_TYPE(iter)->tp_iternext; #else - // PyType_GetSlot() only accepts all types since Python 3.10 tp_iternext = _Py_CAST(iternextfunc, PyType_GetSlot(Py_TYPE(iter), Py_tp_iternext)); #endif if (tp_iternext == NULL) { @@ -1856,13 +1873,14 @@ static inline int PyIter_NextItem(PyObject *iter, PyObject **item) } return -1; #else + // Implementation for limited C API 3.9 and older + assert(iter != NULL); assert(item != NULL); // Cannot check if iter is an iterator: PyIter_Check() is only implemented // as a function since Python 3.8. - // Limited C API 3.2 and 3.3 *item = PyIter_Next(iter); if (*item != NULL) { return 1; @@ -2208,9 +2226,11 @@ static inline int Py_fclose(FILE *file) #endif -#if (0x03080000 <= PY_VERSION_HEX \ +#if (0x03090000 <= PY_VERSION_HEX \ && PY_VERSION_HEX < 0x030E0000 \ && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API)) + +// Use the internal C API added to Python 3.9 PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); static inline PyObject* @@ -2547,6 +2567,7 @@ static inline PyObject* PySys_GetAttr(PyObject *name) { #if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030a0000 + // Limited C API 3.9 and older PyObject *bytes, *result; bytes = PyUnicode_AsUTF8String(name); if (bytes == NULL) { @@ -2556,6 +2577,7 @@ PySys_GetAttr(PyObject *name) Py_DECREF(bytes); return result; #else + // Python 3.14 and newer, and limited C API 3.10 and newer #ifndef Py_LIMITED_API const char *name_str = PyUnicode_AsUTF8(name); #else @@ -2583,6 +2605,7 @@ static inline int PySys_GetOptionalAttr(PyObject *name, PyObject **value) { #if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030a0000 + // Limited C API 3.9 and older PyObject *bytes; int res; bytes = PyUnicode_AsUTF8String(name); @@ -2870,7 +2893,7 @@ PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) #endif // PY_VERSION_HEX < 0x030F00A1 -#if PY_VERSION_HEX < 0x030F00A1 +#if PY_VERSION_HEX < 0x030F00A1 || defined(Py_LIMITED_API) static inline PyObject* PyTuple_FromArray(PyObject *const *array, Py_ssize_t size) { diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index fd99a39..55e4e17 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -154,6 +154,7 @@ test_py_is(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) } +// PyFrame_GetVar() is not available on PyPy nor the limited C API #if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) static void test_frame_getvar(PyFrameObject *frame) @@ -192,8 +193,9 @@ test_frame_getvar(PyFrameObject *frame) // PyThreadState_GetFrame() needs limited C API 3.9 or newer +// PyPy 3.11 added PyCode_GetCode(). #if ((!defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000) \ - && !defined(PYPY_VERSION)) + && (!defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030B0000)) static PyObject * test_frame(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) { @@ -212,6 +214,8 @@ test_frame(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) assert(frame2 == frame); assert(Py_REFCNT(_PyObject_CAST(frame)) == frame_refcnt); + // Test issue: the current thread has no code on PyPy +#ifndef PYPY_VERSION // test PyFrame_GetCode() PyCodeObject *code = PyFrame_GetCode(frame); assert(code != _Py_NULL); @@ -225,8 +229,9 @@ test_frame(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) assert(code2 == code); assert(Py_REFCNT(_PyObject_CAST(code)) == code_refcnt); Py_DECREF(code); +#endif -#ifndef Py_LIMITED_API +#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) // PyFrame_GetBack() PyFrameObject* back = PyFrame_GetBack(frame); if (back != _Py_NULL) { @@ -318,7 +323,7 @@ test_thread_state(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) #endif #if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) - // PyThreadState_EnterTracing(), PyThreadState_LeaveTracing() + // test PyThreadState_EnterTracing() and PyThreadState_LeaveTracing() PyThreadState_EnterTracing(tstate); PyThreadState_LeaveTracing(tstate); #endif @@ -337,7 +342,7 @@ static PyObject * test_interpreter(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) { // On Windows,PyInterpreterState_Get() is not available in stable ABI 3.9, - // only in stable ABI 3.10. Don't test it in limited C API 3.9 on Unix to + // only in stable ABI 3.10. Don't test it on limited C API 3.9 on Unix to // make the test simpler. #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000 // test PyInterpreterState_Get() @@ -374,7 +379,6 @@ test_calls(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) assert(PyUnicode_Check(res)); Py_DECREF(res); -#ifndef Py_LIMITED_API // test PyObject_CallOneArg(): str(1) returns '1' PyObject *arg = PyLong_FromLong(1); if (arg == _Py_NULL) { @@ -387,13 +391,16 @@ test_calls(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) } assert(PyUnicode_Check(res)); Py_DECREF(res); -#endif Py_RETURN_NONE; } -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) && !defined(PYPY_VERSION) +// PyObject_GC_IsTracked() and PyObject_GC_IsFinalized() are part of the +// limited C API 3.9. But on Windows, the functions are only exported in stable +// ABI 3.10. Don't test the function in limited C API 3.9 on Unix to make the +// test simpler. +#if (!defined(Py_LIMITED_API) || PY_VERSION_HEX >= 0x030A0000) && !defined(PYPY_VERSION) static PyObject * test_gc(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) { @@ -433,7 +440,6 @@ check_module_attr(PyObject *module, const char *name, PyObject *expected) } -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) // test PyModule_AddType() static int test_module_add_type(PyObject *module) @@ -457,7 +463,6 @@ test_module_add_type(PyObject *module) ASSERT_REFCNT(Py_REFCNT(_PyObject_CAST(type)) == refcnt); return 0; } -#endif // !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) // test PyModule_AddObjectRef() @@ -541,11 +546,9 @@ test_module(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) } assert(PyModule_Check(module)); -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) if (test_module_add_type(module) < 0) { goto error; } -#endif if (test_module_addobjectref(module) < 0) { goto error; } @@ -619,17 +622,20 @@ test_float_pack(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) #endif -#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) +// PyPy 3.11 added PyFrame_GetCode() and PyCode_GetCode() +#if (!defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030B0000) && !defined(Py_LIMITED_API) static PyObject * test_code(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) { - PyThreadState *tstate = PyThreadState_Get(); - PyFrameObject *frame = PyThreadState_GetFrame(tstate); - if (frame == _Py_NULL) { - PyErr_SetString(PyExc_AssertionError, "PyThreadState_GetFrame failed"); - return _Py_NULL; + PyObject *func = PyImport_ImportModuleAttrString("colorsys", "rgb_to_yiq"); + if (func == NULL) { + return NULL; } - PyCodeObject *code = PyFrame_GetCode(frame); + PyObject *code_obj = PyObject_GetAttrString(func, "__code__"); + Py_DECREF(func); + + assert(PyCode_Check(code_obj)); + PyCodeObject *code = (PyCodeObject*)code_obj; // Test PyCode_GetCode() { @@ -667,7 +673,6 @@ test_code(PyObject *Py_UNUSED(module), PyObject* Py_UNUSED(ignored)) } Py_DECREF(code); - Py_DECREF(frame); Py_RETURN_NONE; } #endif @@ -881,7 +886,7 @@ test_weakref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030C0000) +#if !defined(Py_LIMITED_API) || PY_VERSION_HEX >= 0x030C0000 static void check_int(PyObject *obj, int value) { @@ -1040,7 +1045,7 @@ test_vectorcall(PyObject *module, PyObject *Py_UNUSED(args)) Py_DECREF(func_varargs); Py_RETURN_NONE; } -#endif // !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030C0000) +#endif // !defined(Py_LIMITED_API) || PY_VERSION_HEX >= 0x030C0000 static PyObject * @@ -1215,14 +1220,12 @@ test_dict_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) assert(PyDict_Contains(dict, key) == 1); assert(PyDict_Contains(dict, missing_key) == 0); -#ifndef Py_LIMITED_API // test PyDict_ContainsString() assert(PyDict_ContainsString(dict, "key") == 1); assert(PyDict_ContainsString(dict, "missing_key") == 0); assert(PyDict_ContainsString(dict, "\xff") == -1); assert(PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)); PyErr_Clear(); -#endif // test PyDict_GetItemRef(), key is present get_value = UNINITIALIZED_OBJ; @@ -1419,42 +1422,10 @@ test_dict_setdefault(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } -static PyObject * -test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) -{ - // test PyLong_AsInt() - assert(!PyErr_Occurred()); - PyObject *obj = PyLong_FromLong(123); - if (obj == NULL) { - return NULL; - } - int value = PyLong_AsInt(obj); - assert(value == 123); - assert(!PyErr_Occurred()); - Py_DECREF(obj); - - // test PyLong_AsInt() with overflow - PyObject *obj2 = PyLong_FromLongLong((long long)INT_MAX + 1); - if (obj2 == NULL) { - return NULL; - } - value = PyLong_AsInt(obj2); - assert(value == -1); - assert(PyErr_ExceptionMatches(PyExc_OverflowError)); - PyErr_Clear(); - Py_DECREF(obj2); - - // test PyLong_GetSign() - int sign = UNINITIALIZED_INT; - assert(PyLong_GetSign(obj, &sign) == 0); - assert(sign == 1); - - // test PyLong_IsPositive(), PyLong_IsNegative() and PyLong_IsZero() - assert(PyLong_IsPositive(obj) == 1); - assert(PyLong_IsNegative(obj) == 0); - assert(PyLong_IsZero(obj) == 0); - #if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) +static int +test_long_import_export() +{ // test import/export API digit *digits; PyLongWriter *writer; @@ -1462,23 +1433,24 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) writer = PyLongWriter_Create(1, 1, (void **)&digits); if (writer == NULL) { - return NULL; + return -1; } PyLongWriter_Discard(writer); writer = PyLongWriter_Create(1, 1, (void **)&digits); if (writer == NULL) { - return NULL; + return -1; } digits[0] = 123; - obj = PyLongWriter_Finish(writer); + + PyObject *obj = PyLongWriter_Finish(writer); if (obj == NULL) { - return NULL; + return -1; } check_int(obj, -123); if (PyLong_Export(obj, &long_export) < 0) { - return NULL; + return -1; } assert(long_export.value == -123); assert(long_export.digits == NULL); @@ -1487,7 +1459,7 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) writer = PyLongWriter_Create(0, 5, (void **)&digits); if (writer == NULL) { - return NULL; + return -1; } digits[0] = 1; digits[1] = 0; @@ -1496,11 +1468,11 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) digits[4] = 1; obj = PyLongWriter_Finish(writer); if (obj == NULL) { - return NULL; + return -1; } if (PyLong_Export(obj, &long_export) < 0) { - return NULL; + return -1; } assert(long_export.value == 0); digits = (digit*)long_export.digits; @@ -1515,6 +1487,50 @@ test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) const PyLongLayout *layout = PyLong_GetNativeLayout(); assert(layout->digits_order == -1); assert(layout->digit_size == sizeof(digit)); + return 0; +} +#endif + + +static PyObject * +test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + // test PyLong_AsInt() + assert(!PyErr_Occurred()); + PyObject *obj = PyLong_FromLong(123); + if (obj == NULL) { + return NULL; + } + int value = PyLong_AsInt(obj); + assert(value == 123); + assert(!PyErr_Occurred()); + Py_DECREF(obj); + + // test PyLong_AsInt() with overflow + PyObject *obj2 = PyLong_FromLongLong((long long)INT_MAX + 1); + if (obj2 == NULL) { + return NULL; + } + value = PyLong_AsInt(obj2); + assert(value == -1); + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_Clear(); + Py_DECREF(obj2); + + // test PyLong_GetSign() + int sign = UNINITIALIZED_INT; + assert(PyLong_GetSign(obj, &sign) == 0); + assert(sign == 1); + + // test PyLong_IsPositive(), PyLong_IsNegative() and PyLong_IsZero() + assert(PyLong_IsPositive(obj) == 1); + assert(PyLong_IsNegative(obj) == 0); + assert(PyLong_IsZero(obj) == 0); + +#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) + if (test_long_import_export() < 0) { + return NULL; + } #endif // !PYPY_VERSION Py_RETURN_NONE; @@ -2021,6 +2037,7 @@ test_unicodewriter_format(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) } #endif + #if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) static PyObject * test_uniquely_referenced(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) @@ -2043,6 +2060,7 @@ test_uniquely_referenced(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) } #endif // !PYPY_VERSION + static PyObject * test_bytes(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) { @@ -2074,7 +2092,6 @@ test_bytes(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) static PyObject * test_iter(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) { @@ -2105,9 +2122,9 @@ test_iter(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) assert(item == NULL); assert(!PyErr_Occurred()); - // Limited C API 3.2 and 3.3 implementation cannot check + // Limited C API 3.9 and older implementation cannot check // if the first argument is an iterator -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x03040000) +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000 // non-iterable object item = UNINITIALIZED_OBJ; assert(PyIter_NextItem(Py_None, &item) == -1); @@ -2119,7 +2136,6 @@ test_iter(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) Py_DECREF(iter); Py_RETURN_NONE; } -#endif // !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) static PyObject * @@ -2349,6 +2365,7 @@ test_sys(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } +// PyByteWriter is not available in the limited C API. #ifndef Py_LIMITED_API static int test_byteswriter_highlevel(void) @@ -2448,7 +2465,7 @@ test_byteswriter(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) #endif -#ifndef Py_LIMITED_API +// Test PyTuple_FromArray() static int test_tuple_fromarray(void) { @@ -2479,7 +2496,7 @@ test_tuple_fromarray(void) if (tuple == NULL) { return -1; } - assert(PyTuple_GET_SIZE(tuple) == 0); + assert(PyTuple_Size(tuple) == 0); Py_DECREF(tuple); return 0; @@ -2490,18 +2507,14 @@ test_tuple_fromarray(void) Py_DECREF(array[2]); return -1; } -#endif static PyObject* test_tuple(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) { -#ifndef Py_LIMITED_API if (test_tuple_fromarray() < 0) { return NULL; } -#endif - Py_RETURN_NONE; } @@ -2546,7 +2559,8 @@ test_try_incref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) assert(TryIncref_dealloc_called == 1); Py_RETURN_NONE; } -#endif // !PYPY_VERSION +#endif // !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) + #if 0x030D0000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) static PyObject * @@ -2633,7 +2647,7 @@ static struct PyMethodDef methods[] = { {"test_object", test_object, METH_NOARGS, _Py_NULL}, {"test_py_is", test_py_is, METH_NOARGS, _Py_NULL}, #if ((!defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000) \ - && !defined(PYPY_VERSION)) + && (!defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030B0000)) {"test_frame", test_frame, METH_NOARGS, _Py_NULL}, #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000 @@ -2641,7 +2655,7 @@ static struct PyMethodDef methods[] = { #endif {"test_interpreter", test_interpreter, METH_NOARGS, _Py_NULL}, {"test_calls", test_calls, METH_NOARGS, _Py_NULL}, -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) && !defined(PYPY_VERSION) +#if (!defined(Py_LIMITED_API) || PY_VERSION_HEX >= 0x030A0000) && !defined(PYPY_VERSION) {"test_gc", test_gc, METH_NOARGS, _Py_NULL}, #endif {"test_module", test_module, METH_NOARGS, _Py_NULL}, @@ -2649,7 +2663,7 @@ static struct PyMethodDef methods[] = { && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API)) {"test_float_pack", test_float_pack, METH_NOARGS, _Py_NULL}, #endif -#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) +#if (!defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030B0000) && !defined(Py_LIMITED_API) {"test_code", test_code, METH_NOARGS, _Py_NULL}, #endif {"test_api_casts", test_api_casts, METH_NOARGS, _Py_NULL}, @@ -2681,13 +2695,12 @@ static struct PyMethodDef methods[] = { {"test_unicodewriter_format", test_unicodewriter_format, METH_NOARGS, _Py_NULL}, #endif {"test_bytes", test_bytes, METH_NOARGS, _Py_NULL}, -#if !(defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x030A0000) {"test_iter", test_iter, METH_NOARGS, _Py_NULL}, -#endif {"test_long_stdint", test_long_stdint, METH_NOARGS, _Py_NULL}, {"test_structmember", test_structmember, METH_NOARGS, _Py_NULL}, {"test_file", test_file, METH_NOARGS, _Py_NULL}, -#if 0x03090000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) +#if (0x03090000 <= PY_VERSION_HEX \ + && !defined(PYPY_VERSION) && !defined(Py_LIMITED_API)) {"test_config", test_config, METH_NOARGS, _Py_NULL}, #endif {"test_sys", test_sys, METH_NOARGS, _Py_NULL}, @@ -2751,7 +2764,7 @@ module_exec(PyObject *module) } -// On Python 3.15 and newer, use PySlot API +// Use PySlot API on Python 3.15 and newer and on limited C API 3.15 and newer #if (PY_VERSION_HEX >= 0x030F0000 \ && (!defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030F0000)) @@ -2791,6 +2804,8 @@ INIT_FUNC(void) #elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +// Python 3.14 and newer, and limited 3.5 and newer + static PyModuleDef_Slot module_slots[] = { {Py_mod_exec, _Py_CAST(void*, module_exec)}, #if PY_VERSION_HEX >= 0x030D0000