From 07693d05ad785d495a9c1d5af27399481b43c3f5 Mon Sep 17 00:00:00 2001 From: Mattias Ellert Date: Fri, 1 Jul 2022 06:50:31 +0200 Subject: [PATCH] Python 3.11 support - backported from CPyCppyy --- bindings/pyroot/cppyy/CPyCppyy/src/API.cxx | 11 ++++++++++- .../pyroot/cppyy/CPyCppyy/src/CPPInstance.cxx | 1 - .../pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx | 8 +++++--- bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyy.h | 5 ++++- .../cppyy/CPyCppyy/src/CPyCppyyModule.cxx | 19 +++++++++++++++++++ .../cppyy/CPyCppyy/src/MemoryRegulator.cxx | 2 +- .../pyroot/cppyy/CPyCppyy/src/Utility.cxx | 2 ++ bindings/pyroot/cppyy/CPyCppyy/src/Utility.h | 2 ++ 8 files changed, 43 insertions(+), 7 deletions(-) diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/API.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/API.cxx index 0cc4c8247b..4c17f54bb0 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/API.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/API.cxx @@ -49,7 +49,14 @@ static bool Initialize() #if PY_VERSION_HEX < 0x03020000 PyEval_InitThreads(); #endif +#if PY_VERSION_HEX < 0x03080000 Py_Initialize(); +#else + PyConfig config; + PyConfig_InitPythonConfig(&config); + PyConfig_SetString(&config, &config.program_name, L"cppyy"); + Py_InitializeFromConfig(&config); +#endif #if PY_VERSION_HEX >= 0x03020000 #if PY_VERSION_HEX < 0x03090000 PyEval_InitThreads(); @@ -66,10 +73,12 @@ static bool Initialize() // set the command line arguments on python's sys.argv #if PY_VERSION_HEX < 0x03000000 char* argv[] = {const_cast("cppyy")}; -#else +#elif PY_VERSION_HEX < 0x03080000 wchar_t* argv[] = {const_cast(L"cppyy")}; #endif +#if PY_VERSION_HEX < 0x03080000 PySys_SetArgv(sizeof(argv)/sizeof(argv[0]), argv); +#endif // force loading of the cppyy module PyRun_SimpleString(const_cast("import cppyy")); diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPInstance.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPPInstance.cxx index 73fb8099b5..f2eea396af 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/CPPInstance.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPPInstance.cxx @@ -764,7 +764,6 @@ PyTypeObject CPPInstance_Type = { 0, // tp_as_buffer Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, // tp_flags (char*)"cppyy object proxy (internal)", // tp_doc 0, // tp_traverse diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx index 28bbd635c2..7eb2de8b01 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx @@ -1,11 +1,13 @@ // Bindings #include "CPyCppyy.h" #include "structmember.h" // from Python -#if PY_VERSION_HEX < 0x02050000 -#include "compile.h" // from Python -#elif PY_VERSION_HEX < 0x030b0000 +#if PY_VERSION_HEX >= 0x02050000 +#if PY_VERSION_HEX < 0x030b0000 #include "code.h" // from Python #endif +#else +#include "compile.h" // from Python +#endif #ifndef CO_NOFREE // python2.2 does not have CO_NOFREE defined #define CO_NOFREE 0x0040 diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyy.h b/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyy.h index 11221cd7ef..35af3c8a56 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyy.h +++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyy.h @@ -68,7 +68,10 @@ typedef dim_t* dims_t; #if PY_VERSION_HEX < 0x03030000 typedef PyDictEntry* (*dict_lookup_func)(PyDictObject*, PyObject*, long); #else -#if PY_VERSION_HEX >= 0x03060000 +#if PY_VERSION_HEX >= 0x030b0000 + typedef Py_ssize_t (*dict_lookup_func)( + PyDictObject*, PyObject*, Py_hash_t, PyObject**); +#elif PY_VERSION_HEX >= 0x03060000 typedef Py_ssize_t (*dict_lookup_func)( PyDictObject*, PyObject*, Py_hash_t, PyObject***, Py_ssize_t*); #else diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyyModule.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyyModule.cxx index 411a57a862..7a32ab365f 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyyModule.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPyCppyyModule.cxx @@ -26,6 +26,11 @@ #include +// Note: as of py3.11, dictionary objects no longer carry a function pointer for +// the lookup, so it can no longer be shimmed and "from cppyy.interactive import *" +// thus no longer works. +#if PY_VERSION_HEX < 0x030b0000 + //- from Python's dictobject.c ------------------------------------------------- #if PY_VERSION_HEX >= 0x03030000 typedef struct PyDictKeyEntry { @@ -65,6 +70,8 @@ #endif +#endif // PY_VERSION_HEX < 0x030b0000 + //- data ----------------------------------------------------------------------- static PyObject* nullptr_repr(PyObject*) { @@ -177,7 +184,9 @@ namespace { using namespace CPyCppyy; + //---------------------------------------------------------------------------- +#if PY_VERSION_HEX < 0x030b0000 namespace { class GblGetter { @@ -330,9 +339,12 @@ PyDictEntry* CPyCppyyLookDictString(PyDictObject* mp, PyObject* key, long hash) return ep; } +#endif // PY_VERSION_HEX < 0x030b0000 + //---------------------------------------------------------------------------- static PyObject* SetCppLazyLookup(PyObject*, PyObject* args) { +#if PY_VERSION_HEX < 0x030b0000 // Modify the given dictionary to install the lookup function that also // tries the global C++ namespace before failing. Called on a module's dictionary, // this allows for lazy lookups. This works fine for p3.2 and earlier, but should @@ -343,6 +355,11 @@ static PyObject* SetCppLazyLookup(PyObject*, PyObject* args) return nullptr; CPYCPPYY_GET_DICT_LOOKUP(dict) = CPyCppyyLookDictString; +#else +// As of py3.11, there is no longer a lookup function pointer in the dict object +// to replace. Since this feature is not widely advertised, it's simply droped + PyErr_Warn(PyExc_RuntimeWarning, (char*)"lazy lookup is no longer supported"); +#endif Py_RETURN_NONE; } @@ -813,6 +830,7 @@ LIBCPPYY_INIT_FUNCTION(extern "C" void initlibcppyy, PY_MAJOR_VERSION, _, PY_MIN PyEval_InitThreads(); #endif +#if PY_VERSION_HEX < 0x030b0000 // prepare for lazyness (the insert is needed to capture the most generic lookup // function, just in case ...) PyObject* dict = PyDict_New(); @@ -825,6 +843,7 @@ LIBCPPYY_INIT_FUNCTION(extern "C" void initlibcppyy, PY_MAJOR_VERSION, _, PY_MIN gDictLookupOrg = (dict_lookup_func)((PyDictObject*)dict)->ma_lookup; #endif Py_DECREF(dict); +#endif // PY_VERSION_HEX < 0x030b0000 // setup this module #if PY_VERSION_HEX >= 0x03000000 diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/MemoryRegulator.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/MemoryRegulator.cxx index f9e92f9c8c..5da48364ac 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/MemoryRegulator.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/MemoryRegulator.cxx @@ -45,7 +45,7 @@ struct InitCPyCppyy_NoneType_t { ((PyVarObject&)CPyCppyy_NoneType).ob_size = 0; CPyCppyy_NoneType.tp_name = const_cast("CPyCppyy_NoneType"); - CPyCppyy_NoneType.tp_flags = Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_HAVE_GC; + CPyCppyy_NoneType.tp_flags = Py_TPFLAGS_HAVE_RICHCOMPARE; CPyCppyy_NoneType.tp_traverse = (traverseproc)0; CPyCppyy_NoneType.tp_clear = (inquiry)0; diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Utility.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/Utility.cxx index 14ea1b83e8..1cf8f89bd2 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/Utility.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/Utility.cxx @@ -24,8 +24,10 @@ //- data _____________________________________________________________________ +#if PY_VERSION_HEX < 0x030b0000 dict_lookup_func CPyCppyy::gDictLookupOrg = 0; bool CPyCppyy::gDictLookupActive = false; +#endif typedef std::map TC2POperatorMapping_t; static TC2POperatorMapping_t gC2POperatorMapping; diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Utility.h b/bindings/pyroot/cppyy/CPyCppyy/src/Utility.h index 6bc9314b99..2db76b31b0 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/Utility.h +++ b/bindings/pyroot/cppyy/CPyCppyy/src/Utility.h @@ -10,8 +10,10 @@ namespace CPyCppyy { class PyCallable; +#if PY_VERSION_HEX < 0x030b0000 extern dict_lookup_func gDictLookupOrg; extern bool gDictLookupActive; +#endif // additional converter functions unsigned long PyLongOrInt_AsULong(PyObject* pyobject); -- 2.36.1