From a1991a8d2b31c587f723a7397ee838a2271d02af Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 22 Oct 2021 10:12:06 +0200 Subject: [PATCH] bpo-43795: Add a test for Stable ABI symbol availability using ctypes (GH-26354) This is a cross-platform check that the symbols are actually exported in the ABI, not e.g. hidden in a macro. Caveat: PyModule_Create2 & PyModule_FromDefAndSpec2 are skipped. These aren't exported on some of our buildbots. This is a bug (bpo-44133). This test now makes sure all the others don't regress. (cherry picked from commit 276468dddb46c54980c782c09cdb53bd90755752) Co-authored-by: Petr Viktorin --- Lib/test/test_stable_abi_ctypes.py | 843 +++++++++++++++++++++++++++++ Tools/scripts/stable_abi.py | 38 ++ 2 files changed, 881 insertions(+) create mode 100644 Lib/test/test_stable_abi_ctypes.py diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py new file mode 100644 index 00000000000000..750aa18108327e --- /dev/null +++ b/Lib/test/test_stable_abi_ctypes.py @@ -0,0 +1,843 @@ + +# Generated by Tools/scripts/stable_abi.py + +"""Test that all symbols of the Stable ABI are accessible using ctypes +""" + +import unittest +from test.support.import_helper import import_module + +ctypes_test = import_module('ctypes') + +class TestStableABIAvailability(unittest.TestCase): + def test_available_symbols(self): + for symbol_name in SYMBOL_NAMES: + with self.subTest(symbol_name): + ctypes_test.pythonapi[symbol_name] + +SYMBOL_NAMES = ( + + "PyAIter_Check", + "PyArg_Parse", + "PyArg_ParseTuple", + "PyArg_ParseTupleAndKeywords", + "PyArg_UnpackTuple", + "PyArg_VaParse", + "PyArg_VaParseTupleAndKeywords", + "PyArg_ValidateKeywordArguments", + "PyBaseObject_Type", + "PyBool_FromLong", + "PyBool_Type", + "PyByteArrayIter_Type", + "PyByteArray_AsString", + "PyByteArray_Concat", + "PyByteArray_FromObject", + "PyByteArray_FromStringAndSize", + "PyByteArray_Resize", + "PyByteArray_Size", + "PyByteArray_Type", + "PyBytesIter_Type", + "PyBytes_AsString", + "PyBytes_AsStringAndSize", + "PyBytes_Concat", + "PyBytes_ConcatAndDel", + "PyBytes_DecodeEscape", + "PyBytes_FromFormat", + "PyBytes_FromFormatV", + "PyBytes_FromObject", + "PyBytes_FromString", + "PyBytes_FromStringAndSize", + "PyBytes_Repr", + "PyBytes_Size", + "PyBytes_Type", + "PyCFunction_Call", + "PyCFunction_GetFlags", + "PyCFunction_GetFunction", + "PyCFunction_GetSelf", + "PyCFunction_New", + "PyCFunction_NewEx", + "PyCFunction_Type", + "PyCMethod_New", + "PyCallIter_New", + "PyCallIter_Type", + "PyCallable_Check", + "PyCapsule_GetContext", + "PyCapsule_GetDestructor", + "PyCapsule_GetName", + "PyCapsule_GetPointer", + "PyCapsule_Import", + "PyCapsule_IsValid", + "PyCapsule_New", + "PyCapsule_SetContext", + "PyCapsule_SetDestructor", + "PyCapsule_SetName", + "PyCapsule_SetPointer", + "PyCapsule_Type", + "PyClassMethodDescr_Type", + "PyCodec_BackslashReplaceErrors", + "PyCodec_Decode", + "PyCodec_Decoder", + "PyCodec_Encode", + "PyCodec_Encoder", + "PyCodec_IgnoreErrors", + "PyCodec_IncrementalDecoder", + "PyCodec_IncrementalEncoder", + "PyCodec_KnownEncoding", + "PyCodec_LookupError", + "PyCodec_NameReplaceErrors", + "PyCodec_Register", + "PyCodec_RegisterError", + "PyCodec_ReplaceErrors", + "PyCodec_StreamReader", + "PyCodec_StreamWriter", + "PyCodec_StrictErrors", + "PyCodec_Unregister", + "PyCodec_XMLCharRefReplaceErrors", + "PyComplex_FromDoubles", + "PyComplex_ImagAsDouble", + "PyComplex_RealAsDouble", + "PyComplex_Type", + "PyDescr_NewClassMethod", + "PyDescr_NewGetSet", + "PyDescr_NewMember", + "PyDescr_NewMethod", + "PyDictItems_Type", + "PyDictIterItem_Type", + "PyDictIterKey_Type", + "PyDictIterValue_Type", + "PyDictKeys_Type", + "PyDictProxy_New", + "PyDictProxy_Type", + "PyDictRevIterItem_Type", + "PyDictRevIterKey_Type", + "PyDictRevIterValue_Type", + "PyDictValues_Type", + "PyDict_Clear", + "PyDict_Contains", + "PyDict_Copy", + "PyDict_DelItem", + "PyDict_DelItemString", + "PyDict_GetItem", + "PyDict_GetItemString", + "PyDict_GetItemWithError", + "PyDict_Items", + "PyDict_Keys", + "PyDict_Merge", + "PyDict_MergeFromSeq2", + "PyDict_New", + "PyDict_Next", + "PyDict_SetItem", + "PyDict_SetItemString", + "PyDict_Size", + "PyDict_Type", + "PyDict_Update", + "PyDict_Values", + "PyEllipsis_Type", + "PyEnum_Type", + "PyErr_BadArgument", + "PyErr_BadInternalCall", + "PyErr_CheckSignals", + "PyErr_Clear", + "PyErr_Display", + "PyErr_ExceptionMatches", + "PyErr_Fetch", + "PyErr_Format", + "PyErr_FormatV", + "PyErr_GetExcInfo", + "PyErr_GivenExceptionMatches", + "PyErr_NewException", + "PyErr_NewExceptionWithDoc", + "PyErr_NoMemory", + "PyErr_NormalizeException", + "PyErr_Occurred", + "PyErr_Print", + "PyErr_PrintEx", + "PyErr_ProgramText", + "PyErr_ResourceWarning", + "PyErr_Restore", + "PyErr_SetExcInfo", + "PyErr_SetFromErrno", + "PyErr_SetFromErrnoWithFilename", + "PyErr_SetFromErrnoWithFilenameObject", + "PyErr_SetFromErrnoWithFilenameObjects", + "PyErr_SetImportError", + "PyErr_SetImportErrorSubclass", + "PyErr_SetInterrupt", + "PyErr_SetInterruptEx", + "PyErr_SetNone", + "PyErr_SetObject", + "PyErr_SetString", + "PyErr_SyntaxLocation", + "PyErr_SyntaxLocationEx", + "PyErr_WarnEx", + "PyErr_WarnExplicit", + "PyErr_WarnFormat", + "PyErr_WriteUnraisable", + "PyEval_AcquireLock", + "PyEval_AcquireThread", + "PyEval_CallFunction", + "PyEval_CallMethod", + "PyEval_CallObjectWithKeywords", + "PyEval_EvalCode", + "PyEval_EvalCodeEx", + "PyEval_EvalFrame", + "PyEval_EvalFrameEx", + "PyEval_GetBuiltins", + "PyEval_GetFrame", + "PyEval_GetFuncDesc", + "PyEval_GetFuncName", + "PyEval_GetGlobals", + "PyEval_GetLocals", + "PyEval_InitThreads", + "PyEval_ReleaseLock", + "PyEval_ReleaseThread", + "PyEval_RestoreThread", + "PyEval_SaveThread", + "PyEval_ThreadsInitialized", + "PyExc_ArithmeticError", + "PyExc_AssertionError", + "PyExc_AttributeError", + "PyExc_BaseException", + "PyExc_BlockingIOError", + "PyExc_BrokenPipeError", + "PyExc_BufferError", + "PyExc_BytesWarning", + "PyExc_ChildProcessError", + "PyExc_ConnectionAbortedError", + "PyExc_ConnectionError", + "PyExc_ConnectionRefusedError", + "PyExc_ConnectionResetError", + "PyExc_DeprecationWarning", + "PyExc_EOFError", + "PyExc_EncodingWarning", + "PyExc_EnvironmentError", + "PyExc_Exception", + "PyExc_FileExistsError", + "PyExc_FileNotFoundError", + "PyExc_FloatingPointError", + "PyExc_FutureWarning", + "PyExc_GeneratorExit", + "PyExc_IOError", + "PyExc_ImportError", + "PyExc_ImportWarning", + "PyExc_IndentationError", + "PyExc_IndexError", + "PyExc_InterruptedError", + "PyExc_IsADirectoryError", + "PyExc_KeyError", + "PyExc_KeyboardInterrupt", + "PyExc_LookupError", + "PyExc_MemoryError", + "PyExc_ModuleNotFoundError", + "PyExc_NameError", + "PyExc_NotADirectoryError", + "PyExc_NotImplementedError", + "PyExc_OSError", + "PyExc_OverflowError", + "PyExc_PendingDeprecationWarning", + "PyExc_PermissionError", + "PyExc_ProcessLookupError", + "PyExc_RecursionError", + "PyExc_ReferenceError", + "PyExc_ResourceWarning", + "PyExc_RuntimeError", + "PyExc_RuntimeWarning", + "PyExc_StopAsyncIteration", + "PyExc_StopIteration", + "PyExc_SyntaxError", + "PyExc_SyntaxWarning", + "PyExc_SystemError", + "PyExc_SystemExit", + "PyExc_TabError", + "PyExc_TimeoutError", + "PyExc_TypeError", + "PyExc_UnboundLocalError", + "PyExc_UnicodeDecodeError", + "PyExc_UnicodeEncodeError", + "PyExc_UnicodeError", + "PyExc_UnicodeTranslateError", + "PyExc_UnicodeWarning", + "PyExc_UserWarning", + "PyExc_ValueError", + "PyExc_Warning", + "PyExc_ZeroDivisionError", + "PyExceptionClass_Name", + "PyException_GetCause", + "PyException_GetContext", + "PyException_GetTraceback", + "PyException_SetCause", + "PyException_SetContext", + "PyException_SetTraceback", + "PyFile_FromFd", + "PyFile_GetLine", + "PyFile_WriteObject", + "PyFile_WriteString", + "PyFilter_Type", + "PyFloat_AsDouble", + "PyFloat_FromDouble", + "PyFloat_FromString", + "PyFloat_GetInfo", + "PyFloat_GetMax", + "PyFloat_GetMin", + "PyFloat_Type", + "PyFrame_GetCode", + "PyFrame_GetLineNumber", + "PyFrozenSet_New", + "PyFrozenSet_Type", + "PyGC_Collect", + "PyGC_Disable", + "PyGC_Enable", + "PyGC_IsEnabled", + "PyGILState_Ensure", + "PyGILState_GetThisThreadState", + "PyGILState_Release", + "PyGetSetDescr_Type", + "PyImport_AddModule", + "PyImport_AddModuleObject", + "PyImport_AppendInittab", + "PyImport_ExecCodeModule", + "PyImport_ExecCodeModuleEx", + "PyImport_ExecCodeModuleObject", + "PyImport_ExecCodeModuleWithPathnames", + "PyImport_GetImporter", + "PyImport_GetMagicNumber", + "PyImport_GetMagicTag", + "PyImport_GetModule", + "PyImport_GetModuleDict", + "PyImport_Import", + "PyImport_ImportFrozenModule", + "PyImport_ImportFrozenModuleObject", + "PyImport_ImportModule", + "PyImport_ImportModuleLevel", + "PyImport_ImportModuleLevelObject", + "PyImport_ImportModuleNoBlock", + "PyImport_ReloadModule", + "PyIndex_Check", + "PyInterpreterState_Clear", + "PyInterpreterState_Delete", + "PyInterpreterState_Get", + "PyInterpreterState_GetDict", + "PyInterpreterState_GetID", + "PyInterpreterState_New", + "PyIter_Check", + "PyIter_Next", + "PyIter_Send", + "PyListIter_Type", + "PyListRevIter_Type", + "PyList_Append", + "PyList_AsTuple", + "PyList_GetItem", + "PyList_GetSlice", + "PyList_Insert", + "PyList_New", + "PyList_Reverse", + "PyList_SetItem", + "PyList_SetSlice", + "PyList_Size", + "PyList_Sort", + "PyList_Type", + "PyLongRangeIter_Type", + "PyLong_AsDouble", + "PyLong_AsLong", + "PyLong_AsLongAndOverflow", + "PyLong_AsLongLong", + "PyLong_AsLongLongAndOverflow", + "PyLong_AsSize_t", + "PyLong_AsSsize_t", + "PyLong_AsUnsignedLong", + "PyLong_AsUnsignedLongLong", + "PyLong_AsUnsignedLongLongMask", + "PyLong_AsUnsignedLongMask", + "PyLong_AsVoidPtr", + "PyLong_FromDouble", + "PyLong_FromLong", + "PyLong_FromLongLong", + "PyLong_FromSize_t", + "PyLong_FromSsize_t", + "PyLong_FromString", + "PyLong_FromUnsignedLong", + "PyLong_FromUnsignedLongLong", + "PyLong_FromVoidPtr", + "PyLong_GetInfo", + "PyLong_Type", + "PyMap_Type", + "PyMapping_Check", + "PyMapping_GetItemString", + "PyMapping_HasKey", + "PyMapping_HasKeyString", + "PyMapping_Items", + "PyMapping_Keys", + "PyMapping_Length", + "PyMapping_SetItemString", + "PyMapping_Size", + "PyMapping_Values", + "PyMarshal_ReadObjectFromString", + "PyMarshal_WriteObjectToString", + "PyMem_Calloc", + "PyMem_Free", + "PyMem_Malloc", + "PyMem_Realloc", + "PyMemberDescr_Type", + "PyMember_GetOne", + "PyMember_SetOne", + "PyMemoryView_FromMemory", + "PyMemoryView_FromObject", + "PyMemoryView_GetContiguous", + "PyMemoryView_Type", + "PyMethodDescr_Type", + "PyModuleDef_Init", + "PyModuleDef_Type", + "PyModule_AddFunctions", + "PyModule_AddIntConstant", + "PyModule_AddObject", + "PyModule_AddObjectRef", + "PyModule_AddStringConstant", + "PyModule_AddType", + "PyModule_ExecDef", + "PyModule_GetDef", + "PyModule_GetDict", + "PyModule_GetFilename", + "PyModule_GetFilenameObject", + "PyModule_GetName", + "PyModule_GetNameObject", + "PyModule_GetState", + "PyModule_New", + "PyModule_NewObject", + "PyModule_SetDocString", + "PyModule_Type", + "PyNumber_Absolute", + "PyNumber_Add", + "PyNumber_And", + "PyNumber_AsSsize_t", + "PyNumber_Check", + "PyNumber_Divmod", + "PyNumber_Float", + "PyNumber_FloorDivide", + "PyNumber_InPlaceAdd", + "PyNumber_InPlaceAnd", + "PyNumber_InPlaceFloorDivide", + "PyNumber_InPlaceLshift", + "PyNumber_InPlaceMatrixMultiply", + "PyNumber_InPlaceMultiply", + "PyNumber_InPlaceOr", + "PyNumber_InPlacePower", + "PyNumber_InPlaceRemainder", + "PyNumber_InPlaceRshift", + "PyNumber_InPlaceSubtract", + "PyNumber_InPlaceTrueDivide", + "PyNumber_InPlaceXor", + "PyNumber_Index", + "PyNumber_Invert", + "PyNumber_Long", + "PyNumber_Lshift", + "PyNumber_MatrixMultiply", + "PyNumber_Multiply", + "PyNumber_Negative", + "PyNumber_Or", + "PyNumber_Positive", + "PyNumber_Power", + "PyNumber_Remainder", + "PyNumber_Rshift", + "PyNumber_Subtract", + "PyNumber_ToBase", + "PyNumber_TrueDivide", + "PyNumber_Xor", + "PyOS_FSPath", + "PyOS_InputHook", + "PyOS_InterruptOccurred", + "PyOS_double_to_string", + "PyOS_getsig", + "PyOS_mystricmp", + "PyOS_mystrnicmp", + "PyOS_setsig", + "PyOS_snprintf", + "PyOS_string_to_double", + "PyOS_strtol", + "PyOS_strtoul", + "PyOS_vsnprintf", + "PyObject_ASCII", + "PyObject_AsCharBuffer", + "PyObject_AsFileDescriptor", + "PyObject_AsReadBuffer", + "PyObject_AsWriteBuffer", + "PyObject_Bytes", + "PyObject_Call", + "PyObject_CallFunction", + "PyObject_CallFunctionObjArgs", + "PyObject_CallMethod", + "PyObject_CallMethodObjArgs", + "PyObject_CallNoArgs", + "PyObject_CallObject", + "PyObject_Calloc", + "PyObject_CheckReadBuffer", + "PyObject_ClearWeakRefs", + "PyObject_DelItem", + "PyObject_DelItemString", + "PyObject_Dir", + "PyObject_Format", + "PyObject_Free", + "PyObject_GC_Del", + "PyObject_GC_IsFinalized", + "PyObject_GC_IsTracked", + "PyObject_GC_Track", + "PyObject_GC_UnTrack", + "PyObject_GenericGetAttr", + "PyObject_GenericGetDict", + "PyObject_GenericSetAttr", + "PyObject_GenericSetDict", + "PyObject_GetAIter", + "PyObject_GetAttr", + "PyObject_GetAttrString", + "PyObject_GetItem", + "PyObject_GetIter", + "PyObject_HasAttr", + "PyObject_HasAttrString", + "PyObject_Hash", + "PyObject_HashNotImplemented", + "PyObject_Init", + "PyObject_InitVar", + "PyObject_IsInstance", + "PyObject_IsSubclass", + "PyObject_IsTrue", + "PyObject_Length", + "PyObject_Malloc", + "PyObject_Not", + "PyObject_Realloc", + "PyObject_Repr", + "PyObject_RichCompare", + "PyObject_RichCompareBool", + "PyObject_SelfIter", + "PyObject_SetAttr", + "PyObject_SetAttrString", + "PyObject_SetItem", + "PyObject_Size", + "PyObject_Str", + "PyObject_Type", + "PyProperty_Type", + "PyRangeIter_Type", + "PyRange_Type", + "PyReversed_Type", + "PySeqIter_New", + "PySeqIter_Type", + "PySequence_Check", + "PySequence_Concat", + "PySequence_Contains", + "PySequence_Count", + "PySequence_DelItem", + "PySequence_DelSlice", + "PySequence_Fast", + "PySequence_GetItem", + "PySequence_GetSlice", + "PySequence_In", + "PySequence_InPlaceConcat", + "PySequence_InPlaceRepeat", + "PySequence_Index", + "PySequence_Length", + "PySequence_List", + "PySequence_Repeat", + "PySequence_SetItem", + "PySequence_SetSlice", + "PySequence_Size", + "PySequence_Tuple", + "PySetIter_Type", + "PySet_Add", + "PySet_Clear", + "PySet_Contains", + "PySet_Discard", + "PySet_New", + "PySet_Pop", + "PySet_Size", + "PySet_Type", + "PySlice_AdjustIndices", + "PySlice_GetIndices", + "PySlice_GetIndicesEx", + "PySlice_New", + "PySlice_Type", + "PySlice_Unpack", + "PyState_AddModule", + "PyState_FindModule", + "PyState_RemoveModule", + "PyStructSequence_GetItem", + "PyStructSequence_New", + "PyStructSequence_NewType", + "PyStructSequence_SetItem", + "PyStructSequence_UnnamedField", + "PySuper_Type", + "PySys_AddWarnOption", + "PySys_AddWarnOptionUnicode", + "PySys_AddXOption", + "PySys_FormatStderr", + "PySys_FormatStdout", + "PySys_GetObject", + "PySys_GetXOptions", + "PySys_HasWarnOptions", + "PySys_ResetWarnOptions", + "PySys_SetArgv", + "PySys_SetArgvEx", + "PySys_SetObject", + "PySys_SetPath", + "PySys_WriteStderr", + "PySys_WriteStdout", + "PyThreadState_Clear", + "PyThreadState_Delete", + "PyThreadState_DeleteCurrent", + "PyThreadState_Get", + "PyThreadState_GetDict", + "PyThreadState_GetFrame", + "PyThreadState_GetID", + "PyThreadState_GetInterpreter", + "PyThreadState_New", + "PyThreadState_SetAsyncExc", + "PyThreadState_Swap", + "PyThread_GetInfo", + "PyThread_ReInitTLS", + "PyThread_acquire_lock", + "PyThread_acquire_lock_timed", + "PyThread_allocate_lock", + "PyThread_create_key", + "PyThread_delete_key", + "PyThread_delete_key_value", + "PyThread_exit_thread", + "PyThread_free_lock", + "PyThread_get_key_value", + "PyThread_get_stacksize", + "PyThread_get_thread_ident", + "PyThread_get_thread_native_id", + "PyThread_init_thread", + "PyThread_release_lock", + "PyThread_set_key_value", + "PyThread_set_stacksize", + "PyThread_start_new_thread", + "PyThread_tss_alloc", + "PyThread_tss_create", + "PyThread_tss_delete", + "PyThread_tss_free", + "PyThread_tss_get", + "PyThread_tss_is_created", + "PyThread_tss_set", + "PyTraceBack_Here", + "PyTraceBack_Print", + "PyTraceBack_Type", + "PyTupleIter_Type", + "PyTuple_GetItem", + "PyTuple_GetSlice", + "PyTuple_New", + "PyTuple_Pack", + "PyTuple_SetItem", + "PyTuple_Size", + "PyTuple_Type", + "PyType_ClearCache", + "PyType_FromModuleAndSpec", + "PyType_FromSpec", + "PyType_FromSpecWithBases", + "PyType_GenericAlloc", + "PyType_GenericNew", + "PyType_GetFlags", + "PyType_GetModule", + "PyType_GetModuleState", + "PyType_GetName", + "PyType_GetQualName", + "PyType_GetSlot", + "PyType_IsSubtype", + "PyType_Modified", + "PyType_Ready", + "PyType_Type", + "PyUnicodeDecodeError_Create", + "PyUnicodeDecodeError_GetEncoding", + "PyUnicodeDecodeError_GetEnd", + "PyUnicodeDecodeError_GetObject", + "PyUnicodeDecodeError_GetReason", + "PyUnicodeDecodeError_GetStart", + "PyUnicodeDecodeError_SetEnd", + "PyUnicodeDecodeError_SetReason", + "PyUnicodeDecodeError_SetStart", + "PyUnicodeEncodeError_GetEncoding", + "PyUnicodeEncodeError_GetEnd", + "PyUnicodeEncodeError_GetObject", + "PyUnicodeEncodeError_GetReason", + "PyUnicodeEncodeError_GetStart", + "PyUnicodeEncodeError_SetEnd", + "PyUnicodeEncodeError_SetReason", + "PyUnicodeEncodeError_SetStart", + "PyUnicodeIter_Type", + "PyUnicodeTranslateError_GetEnd", + "PyUnicodeTranslateError_GetObject", + "PyUnicodeTranslateError_GetReason", + "PyUnicodeTranslateError_GetStart", + "PyUnicodeTranslateError_SetEnd", + "PyUnicodeTranslateError_SetReason", + "PyUnicodeTranslateError_SetStart", + "PyUnicode_Append", + "PyUnicode_AppendAndDel", + "PyUnicode_AsASCIIString", + "PyUnicode_AsCharmapString", + "PyUnicode_AsDecodedObject", + "PyUnicode_AsDecodedUnicode", + "PyUnicode_AsEncodedObject", + "PyUnicode_AsEncodedString", + "PyUnicode_AsEncodedUnicode", + "PyUnicode_AsLatin1String", + "PyUnicode_AsRawUnicodeEscapeString", + "PyUnicode_AsUCS4", + "PyUnicode_AsUCS4Copy", + "PyUnicode_AsUTF16String", + "PyUnicode_AsUTF32String", + "PyUnicode_AsUTF8AndSize", + "PyUnicode_AsUTF8String", + "PyUnicode_AsUnicodeEscapeString", + "PyUnicode_AsWideChar", + "PyUnicode_AsWideCharString", + "PyUnicode_BuildEncodingMap", + "PyUnicode_Compare", + "PyUnicode_CompareWithASCIIString", + "PyUnicode_Concat", + "PyUnicode_Contains", + "PyUnicode_Count", + "PyUnicode_Decode", + "PyUnicode_DecodeASCII", + "PyUnicode_DecodeCharmap", + "PyUnicode_DecodeFSDefault", + "PyUnicode_DecodeFSDefaultAndSize", + "PyUnicode_DecodeLatin1", + "PyUnicode_DecodeLocale", + "PyUnicode_DecodeLocaleAndSize", + "PyUnicode_DecodeRawUnicodeEscape", + "PyUnicode_DecodeUTF16", + "PyUnicode_DecodeUTF16Stateful", + "PyUnicode_DecodeUTF32", + "PyUnicode_DecodeUTF32Stateful", + "PyUnicode_DecodeUTF7", + "PyUnicode_DecodeUTF7Stateful", + "PyUnicode_DecodeUTF8", + "PyUnicode_DecodeUTF8Stateful", + "PyUnicode_DecodeUnicodeEscape", + "PyUnicode_EncodeFSDefault", + "PyUnicode_EncodeLocale", + "PyUnicode_FSConverter", + "PyUnicode_FSDecoder", + "PyUnicode_Find", + "PyUnicode_FindChar", + "PyUnicode_Format", + "PyUnicode_FromEncodedObject", + "PyUnicode_FromFormat", + "PyUnicode_FromFormatV", + "PyUnicode_FromObject", + "PyUnicode_FromOrdinal", + "PyUnicode_FromString", + "PyUnicode_FromStringAndSize", + "PyUnicode_FromWideChar", + "PyUnicode_GetDefaultEncoding", + "PyUnicode_GetLength", + "PyUnicode_GetSize", + "PyUnicode_InternFromString", + "PyUnicode_InternImmortal", + "PyUnicode_InternInPlace", + "PyUnicode_IsIdentifier", + "PyUnicode_Join", + "PyUnicode_Partition", + "PyUnicode_RPartition", + "PyUnicode_RSplit", + "PyUnicode_ReadChar", + "PyUnicode_Replace", + "PyUnicode_Resize", + "PyUnicode_RichCompare", + "PyUnicode_Split", + "PyUnicode_Splitlines", + "PyUnicode_Substring", + "PyUnicode_Tailmatch", + "PyUnicode_Translate", + "PyUnicode_Type", + "PyUnicode_WriteChar", + "PyWeakref_GetObject", + "PyWeakref_NewProxy", + "PyWeakref_NewRef", + "PyWrapperDescr_Type", + "PyWrapper_New", + "PyZip_Type", + "Py_AddPendingCall", + "Py_AtExit", + "Py_BuildValue", + "Py_BytesMain", + "Py_CompileString", + "Py_DecRef", + "Py_DecodeLocale", + "Py_EncodeLocale", + "Py_EndInterpreter", + "Py_EnterRecursiveCall", + "Py_Exit", + "Py_FatalError", + "Py_FileSystemDefaultEncodeErrors", + "Py_FileSystemDefaultEncoding", + "Py_Finalize", + "Py_FinalizeEx", + "Py_GenericAlias", + "Py_GenericAliasType", + "Py_GetArgcArgv", + "Py_GetBuildInfo", + "Py_GetCompiler", + "Py_GetCopyright", + "Py_GetExecPrefix", + "Py_GetPath", + "Py_GetPlatform", + "Py_GetPrefix", + "Py_GetProgramFullPath", + "Py_GetProgramName", + "Py_GetPythonHome", + "Py_GetRecursionLimit", + "Py_GetVersion", + "Py_HasFileSystemDefaultEncoding", + "Py_IncRef", + "Py_Initialize", + "Py_InitializeEx", + "Py_Is", + "Py_IsFalse", + "Py_IsInitialized", + "Py_IsNone", + "Py_IsTrue", + "Py_LeaveRecursiveCall", + "Py_Main", + "Py_MakePendingCalls", + "Py_NewInterpreter", + "Py_NewRef", + "Py_ReprEnter", + "Py_ReprLeave", + "Py_SetPath", + "Py_SetProgramName", + "Py_SetPythonHome", + "Py_SetRecursionLimit", + "Py_UTF8Mode", + "Py_VaBuildValue", + "Py_XNewRef", + "_PyArg_ParseTupleAndKeywords_SizeT", + "_PyArg_ParseTuple_SizeT", + "_PyArg_Parse_SizeT", + "_PyArg_VaParseTupleAndKeywords_SizeT", + "_PyArg_VaParse_SizeT", + "_PyErr_BadInternalCall", + "_PyObject_CallFunction_SizeT", + "_PyObject_CallMethod_SizeT", + "_PyObject_GC_Malloc", + "_PyObject_GC_New", + "_PyObject_GC_NewVar", + "_PyObject_GC_Resize", + "_PyObject_New", + "_PyObject_NewVar", + "_PyState_AddModule", + "_PyThreadState_Init", + "_PyThreadState_Prealloc", + "_PyWeakref_CallableProxyType", + "_PyWeakref_ProxyType", + "_PyWeakref_RefType", + "_Py_BuildValue_SizeT", + "_Py_CheckRecursiveCall", + "_Py_Dealloc", + "_Py_DecRef", + "_Py_EllipsisObject", + "_Py_FalseStruct", + "_Py_IncRef", + "_Py_NoneStruct", + "_Py_NotImplementedStruct", + "_Py_SwappedOp", + "_Py_TrueStruct", + "_Py_VaBuildValue_SizeT", +) diff --git a/Tools/scripts/stable_abi.py b/Tools/scripts/stable_abi.py index 6d7034090f8819..d0058155e22721 100755 --- a/Tools/scripts/stable_abi.py +++ b/Tools/scripts/stable_abi.py @@ -259,6 +259,44 @@ def gen_doc_annotations(manifest, args, outfile): 'added': item.added, 'ifdef_note': ifdef_note}) +@generator("ctypes_test", 'Lib/test/test_stable_abi_ctypes.py') +def gen_ctypes_test(manifest, args, outfile): + """Generate/check the ctypes-based test for exported symbols""" + write = partial(print, file=outfile) + write(textwrap.dedent(''' + # Generated by Tools/scripts/stable_abi.py + + """Test that all symbols of the Stable ABI are accessible using ctypes + """ + + import unittest + from test.support.import_helper import import_module + + ctypes_test = import_module('ctypes') + + class TestStableABIAvailability(unittest.TestCase): + def test_available_symbols(self): + for symbol_name in SYMBOL_NAMES: + with self.subTest(symbol_name): + ctypes_test.pythonapi[symbol_name] + + SYMBOL_NAMES = ( + ''')) + items = manifest.select( + {'function', 'data'}, + include_abi_only=True, + ifdef=set()) + for item in items: + if item.name in ( + # Some symbols aren't exported on all platforms. + # This is a bug: https://bugs.python.org/issue44133 + 'PyModule_Create2', 'PyModule_FromDefAndSpec2', + ): + continue + write(f' "{item.name}",') + write(")") + + def generate_or_check(manifest, args, path, func): """Generate/check a file with a single generator