From 8c5c8584e49d51fa7d2182e1d87ecad4e884155e Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Fri, 8 Nov 2024 13:28:41 +0100 Subject: [PATCH] Update CPyCppyy to use InterOp API This updates converter creation, templateproxy, dispatcher, cppdatamember, cppinstance and cppenum to enable parts of the API that required modifications to work with CppInterOp --- src/CPPDataMember.cxx | 5 ----- src/CPPEnum.cxx | 35 +++++++++++++++++++---------------- src/CPPInstance.cxx | 6 ------ src/Converters.cxx | 3 +-- src/Dispatcher.cxx | 14 +++++++------- src/Executors.cxx | 6 ++---- src/Pythonize.cxx | 4 ++-- src/TemplateProxy.cxx | 5 ----- 8 files changed, 31 insertions(+), 47 deletions(-) diff --git a/src/CPPDataMember.cxx b/src/CPPDataMember.cxx index 8fc6971..0fa7351 100644 --- a/src/CPPDataMember.cxx +++ b/src/CPPDataMember.cxx @@ -48,10 +48,6 @@ static PyObject* dm_get(CPPDataMember* dm, CPPInstance* pyobj, PyObject* /* kls } } -// non-initialized or public data accesses through class (e.g. by help()) - void* address = dm->GetAddress(pyobj); - if (!address || (intptr_t)address == -1 /* Cling error */) - return nullptr; if (dm->fFlags & (kIsEnumPrep | kIsEnumType)) { if (dm->fFlags & kIsEnumPrep) { @@ -92,7 +88,6 @@ static PyObject* dm_get(CPPDataMember* dm, CPPInstance* pyobj, PyObject* /* kls return pyval_from_enum(Cppyy::ResolveEnum(dm->fScope), nullptr, nullptr, dm->fScope); } } - // non-initialized or public data accesses through class (e.g. by help()) void* address = dm->GetAddress(pyobj); if (!address || (intptr_t)address == -1 /* Cling error */) diff --git a/src/CPPEnum.cxx b/src/CPPEnum.cxx index 45a453a..65f4f4b 100644 --- a/src/CPPEnum.cxx +++ b/src/CPPEnum.cxx @@ -19,9 +19,9 @@ static PyObject* pytype_from_enum_type(const std::string& enum_type) } //---------------------------------------------------------------------------- -static PyObject* pyval_from_enum(const std::string& enum_type, PyObject* pytype, - PyObject* btype, Cppyy::TCppEnum_t etype, Cppyy::TCppIndex_t idata) { - long long llval = Cppyy::GetEnumDataValue(etype, idata); +PyObject* CPyCppyy::pyval_from_enum(const std::string& enum_type, PyObject* pytype, + PyObject* btype, Cppyy::TCppScope_t enum_constant) { + long long llval = Cppyy::GetEnumDataValue(enum_constant); if (enum_type == "bool") { PyObject* result = (bool)llval ? Py_True : Py_False; @@ -38,14 +38,15 @@ static PyObject* pyval_from_enum(const std::string& enum_type, PyObject* pytype, else bval = PyLong_FromLongLong(llval); + if (pytype && btype) { PyObject* args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, bval); - PyObject* result = ((PyTypeObject*)btype)->tp_new((PyTypeObject*)pytype, args, nullptr); + bval = ((PyTypeObject*)btype)->tp_new((PyTypeObject*)pytype, args, nullptr); Py_DECREF(args); - return result; + } + return bval; } - //- enum methods ------------------------------------------------------------- static int enum_setattro(PyObject* /* pyclass */, PyObject* /* pyname */, PyObject* /* pyval */) { @@ -59,6 +60,8 @@ static PyObject* enum_repr(PyObject* self) { using namespace CPyCppyy; + PyObject* kls_scope = PyObject_GetAttr((PyObject*)Py_TYPE(self), PyStrings::gThisModule); + if (!kls_scope) PyErr_Clear(); PyObject* kls_cppname = PyObject_GetAttr((PyObject*)Py_TYPE(self), PyStrings::gCppName); if (!kls_cppname) PyErr_Clear(); PyObject* obj_cppname = PyObject_GetAttr(self, PyStrings::gCppName); @@ -67,7 +70,7 @@ static PyObject* enum_repr(PyObject* self) PyObject* repr = nullptr; if (kls_cppname && obj_cppname && obj_str) { - const std::string resolved = Cppyy::ResolveEnum(CPyCppyy_PyText_AsString(kls_cppname)); + const std::string resolved = Cppyy::ResolveEnum(PyLong_AsVoidPtr(kls_scope)); repr = CPyCppyy_PyText_FromFormat("(%s::%s) : (%s) %s", CPyCppyy_PyText_AsString(kls_cppname), CPyCppyy_PyText_AsString(obj_cppname), resolved.c_str(), CPyCppyy_PyText_AsString(obj_str)); @@ -137,12 +140,12 @@ CPyCppyy::CPPEnum* CPyCppyy::CPPEnum_New(const std::string& name, Cppyy::TCppSco CPPEnum* pyenum = nullptr; - const std::string& ename = scope == Cppyy::gGlobalScope ? name : Cppyy::GetScopedFinalName(scope)+"::"+name; - Cppyy::TCppEnum_t etype = Cppyy::GetEnum(scope, name); + Cppyy::TCppScope_t etype = scope; + const std::string& ename = Cppyy::GetScopedFinalName(scope); if (etype) { // create new enum type with labeled values in place, with a meta-class // to make sure the enum values are read-only - const std::string& resolved = Cppyy::ResolveEnum(ename); + const std::string& resolved = Cppyy::ResolveEnum(etype); PyObject* pyside_type = pytype_from_enum_type(resolved); PyObject* pymetabases = PyTuple_New(1); PyObject* btype = (PyObject*)Py_TYPE(pyside_type); @@ -169,7 +172,7 @@ CPyCppyy::CPPEnum* CPyCppyy::CPPEnum_New(const std::string& name, Cppyy::TCppSco PyObject* pyresolved = CPyCppyy_PyText_FromString(resolved.c_str()); PyDict_SetItem(dct, PyStrings::gUnderlying, pyresolved); Py_DECREF(pyresolved); - + // add the __module__ to allow pickling std::string modname = TypeManip::extract_namespace(ename); TypeManip::cppscope_to_pyscope(modname); // :: -> . @@ -191,10 +194,10 @@ CPyCppyy::CPPEnum* CPyCppyy::CPPEnum_New(const std::string& name, Cppyy::TCppSco ((PyTypeObject*)pyenum)->tp_str = ((PyTypeObject*)pyside_type)->tp_repr; // collect the enum values - Cppyy::TCppIndex_t ndata = Cppyy::GetNumEnumData(etype); - for (Cppyy::TCppIndex_t idata = 0; idata < ndata; ++idata) { - PyObject* val = pyval_from_enum(resolved, pyenum, pyside_type, etype, idata); - PyObject* pydname = CPyCppyy_PyText_FromString(Cppyy::GetEnumDataName(etype, idata).c_str()); + std::vector econstants = Cppyy::GetEnumConstants(etype); + for (auto *econstant : econstants) { + PyObject* val = pyval_from_enum(resolved, pyenum, pyside_type, econstant); + PyObject* pydname = CPyCppyy_PyText_FromString(Cppyy::GetFinalName(econstant).c_str()); PyObject_SetAttr(pyenum, pydname, val); PyObject_SetAttr(val, PyStrings::gCppName, pydname); Py_DECREF(pydname); @@ -215,4 +218,4 @@ CPyCppyy::CPPEnum* CPyCppyy::CPPEnum_New(const std::string& name, Cppyy::TCppSco } return pyenum; -} +} \ No newline at end of file diff --git a/src/CPPInstance.cxx b/src/CPPInstance.cxx index f990661..9d7830e 100644 --- a/src/CPPInstance.cxx +++ b/src/CPPInstance.cxx @@ -358,10 +358,6 @@ static PyObject* op_item(CPPInstance* self, Py_ssize_t idx) return nullptr; } - Py_ssize_t idx = PyInt_AsSsize_t(pyidx); - if (idx == (Py_ssize_t)-1 && PyErr_Occurred()) - return nullptr; - if (idx < 0) { // this is debatable, and probably should not care, but the use case is pretty // circumscribed anyway, so might as well keep the functionality simple @@ -413,8 +409,6 @@ static PyMethodDef op_methods[] = { (char*)"dispatch to selected overload"}, {(char*)"__smartptr__", (PyCFunction)op_get_smartptr, METH_NOARGS, (char*)"get associated smart pointer, if any"}, - {(char*)"__getitem__", (PyCFunction)op_getitem, METH_O, - (char*)"pointer dereferencing"}, {(char*)"__reshape__", (PyCFunction)op_reshape, METH_O, (char*)"cast pointer to 1D array type"}, {(char*)nullptr, nullptr, 0, nullptr} diff --git a/src/Converters.cxx b/src/Converters.cxx index 0b5bd87..a5494c3 100644 --- a/src/Converters.cxx +++ b/src/Converters.cxx @@ -3370,8 +3370,7 @@ CPyCppyy::Converter* CPyCppyy::CreateConverter(Cppyy::TCppType_t type, cdims_t d } else cnv = CreateConverter(value_type); if (cnv || use_byte_cnv) - return new InitializerListConverter(Cppyy::GetScopeFromType(realType), - CreateConverter(value_type), cnv, Cppyy::SizeOf(value_type)); + return new InitializerListConverter(Cppyy::GetScopeFromType(realType), value_type); } //-- still nothing? use a generalized converter diff --git a/src/Dispatcher.cxx b/src/Dispatcher.cxx index ad627e3..287c166 100644 --- a/src/Dispatcher.cxx +++ b/src/Dispatcher.cxx @@ -146,11 +146,11 @@ namespace { using namespace Cppyy; static inline -std::vector FindBaseMethod(TCppScope_t tbase, const std::string mtCppName) +std::vector FindBaseMethod(TCppScope_t tbase, const std::string mtCppName) { // Recursively walk the inheritance tree to find the overloads of the named method - std::vector result; - result = GetMethodIndicesFromName(tbase, mtCppName); + std::vector result; + result = GetMethodsFromName(tbase, mtCppName); if (result.empty()) { for (TCppIndex_t ibase = 0; ibase < GetNumBases(tbase); ++ibase) { TCppScope_t b = GetScope(GetBaseName(tbase, ibase)); @@ -366,10 +366,10 @@ bool CPyCppyy::InsertDispatcher(CPPScope* klass, PyObject* bases, PyObject* dct, // TODO: should probably invert this looping; but that makes handling overloads clunky PyObject* key = PyList_GET_ITEM(keys, i); std::string mtCppName = CPyCppyy_PyText_AsString(key); - const auto& v = FindBaseMethod(tbase, mtCppName); - for (auto idx : v) - InjectMethod(Cppyy::GetMethod(tbase, idx), mtCppName, code); - if (!v.empty()) { + const auto& methods = FindBaseMethod(tbase, mtCppName); + for (auto method : methods) + InjectMethod(method, mtCppName, code); + if (!methods.empty()) { if (PyDict_DelItem(clbs, key) != 0) PyErr_Clear(); } } diff --git a/src/Executors.cxx b/src/Executors.cxx index d5b7227..14f9b01 100644 --- a/src/Executors.cxx +++ b/src/Executors.cxx @@ -809,10 +809,8 @@ CPyCppyy::Executor* CPyCppyy::CreateExecutor(const std::string& fullType, cdims_ // // If all fails, void is used, which will cause the return type to be ignored on use - // FIXME: - //assert(!fullType.empty() && "This routine assumes non-empty fullType"); - if (fullType.empty()) - return nullptr; + if (fullType.empty()) + return nullptr; // an exactly matching executor is best ExecFactories_t::iterator h = gExecFactories.find(fullType); diff --git a/src/Pythonize.cxx b/src/Pythonize.cxx index d6e43eb..d809a6b 100644 --- a/src/Pythonize.cxx +++ b/src/Pythonize.cxx @@ -568,9 +568,9 @@ static PyObject* vector_iter(PyObject* v) { if (!vi->vi_klass) { // look for a special case of pointer to a class type (which is a builtin, but it // is more useful to treat it polymorphically by allowing auto-downcasts) - const std::string& clean_type = TypeManip::clean_type(value_type, false, false); + const std::string& clean_type = TypeManip::clean_type(Cppyy::GetTypeAsString(value_type), false, false); Cppyy::TCppScope_t c = Cppyy::GetScope(clean_type); - if (c && TypeManip::compound(value_type) == "*") { + if (c && TypeManip::compound(Cppyy::GetTypeAsString(value_type)) == "*") { vi->vi_klass = c; vi->vi_flags = vectoriterobject::kIsPolymorphic; } diff --git a/src/TemplateProxy.cxx b/src/TemplateProxy.cxx index 0285725..df9bd2c 100644 --- a/src/TemplateProxy.cxx +++ b/src/TemplateProxy.cxx @@ -856,11 +856,6 @@ static PyObject* tpp_overload(TemplateProxy* pytmpl, PyObject* args) PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0; PyErr_Fetch(&pytype, &pyvalue, &pytrace); - std::string proto = Utility::ConstructTemplateArgs(nullptr, args); - Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType; - Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate( - scope, pytmpl->fTI->fCppName, proto.substr(1, proto.size()-2)); - if (!cppmeth) { PyErr_Restore(pytype, pyvalue, pytrace); return nullptr;