diff options
Diffstat (limited to 'sources/shiboken2/libshiboken/basewrapper.cpp')
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.cpp | 503 |
1 files changed, 407 insertions, 96 deletions
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 000035627..dca5631bc 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -44,6 +44,7 @@ #include "sbkconverter.h" #include "sbkenum.h" #include "sbkstring.h" +#include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" #include "autodecref.h" #include "gilstate.h" @@ -55,9 +56,14 @@ #include <algorithm> #include "threadstatesaver.h" #include "signature.h" -#include "qapp_macro.h" #include "voidptr.h" +#include <iostream> + +#if defined(__APPLE__) +#include <dlfcn.h> +#endif + namespace { void _destroyParentInfo(SbkObject *obj, bool keepReference); } @@ -74,30 +80,102 @@ static void callDestructor(const Shiboken::DtorAccumulatorVisitor::DestructorEnt extern "C" { +// PYSIDE-939: A general replacement for object_dealloc. +void Sbk_object_dealloc(PyObject *self) +{ + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(self)); + } + Py_TYPE(self)->tp_free(self); +} + static void SbkObjectTypeDealloc(PyObject *pyObj); static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds); +static SelectableFeatureHook SelectFeatureSet = nullptr; +static DestroyQAppHook DestroyQApplication = nullptr; + +// PYSIDE-1470: Provide a hook to kill an Application from Shiboken. +void setDestroyQApplication(DestroyQAppHook func) +{ + DestroyQApplication = func; +} + +static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context); // forward + +static int +check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name) +{ + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "can't set %s.%s", type->tp_name, name); + return 0; + } + if (!value) { + PyErr_Format(PyExc_TypeError, + "can't delete %s.%s", type->tp_name, name); + return 0; + } + return 1; +} + +// PYSIDE-1177: Add a setter to allow setting type doc. +static int +type_set_doc(PyTypeObject *type, PyObject *value, void *context) +{ + if (!check_set_special_type_attr(type, value, "__doc__")) + return -1; + PyType_Modified(type); + return PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::doc(), value); +} + // PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to // explicitly pass __doc__. For __signature__ it _did_ actually work, because // it was not existing before. We add them both for clarity. static PyGetSetDef SbkObjectType_Type_getsetlist[] = { {const_cast<char *>("__signature__"), (getter)Sbk_TypeGet___signature__}, - {const_cast<char *>("__doc__"), (getter)Sbk_TypeGet___doc__}, + {const_cast<char *>("__doc__"), (getter)Sbk_TypeGet___doc__, (setter)type_set_doc}, + {const_cast<char *>("__dict__"), (getter)Sbk_TypeGet___dict__}, {nullptr} // Sentinel }; +#if PY_VERSION_HEX < 0x03000000 + +static PyObject *SbkObjectType_repr(PyObject *type) +{ + Shiboken::AutoDecRef mod(PyObject_GetAttr(type, Shiboken::PyMagicName::module())); + if (mod.isNull()) + return nullptr; + Shiboken::AutoDecRef name(PyObject_GetAttr(type, Shiboken::PyMagicName::qualname())); + if (name.isNull()) + return nullptr; + return PyString_FromFormat("<class '%s.%s'>", + PyString_AS_STRING(mod.object()), + PyString_AS_STRING(name.object())); +} + +#endif // PY_VERSION_HEX < 0x03000000 + +static PyObject *(*type_getattro)(PyObject *type, PyObject *name); // forward +static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name); // forward + static PyType_Slot SbkObjectType_Type_slots[] = { {Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectTypeDealloc)}, - {Py_tp_setattro, reinterpret_cast<void *>(PyObject_GenericSetAttr)}, + {Py_tp_getattro, reinterpret_cast<void *>(mangled_type_getattro)}, {Py_tp_base, static_cast<void *>(&PyType_Type)}, {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)}, {Py_tp_new, reinterpret_cast<void *>(SbkObjectTypeTpNew)}, {Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)}, {Py_tp_getset, reinterpret_cast<void *>(SbkObjectType_Type_getsetlist)}, +#if PY_VERSION_HEX < 0x03000000 + {Py_tp_repr, reinterpret_cast<void *>(SbkObjectType_repr)}, +#endif {0, nullptr} }; static PyType_Spec SbkObjectType_Type_spec = { - "Shiboken.ObjectType", + "1:Shiboken.ObjectType", 0, // basicsize (inserted later) sizeof(PyMemberDef), Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, @@ -197,9 +275,12 @@ PyTypeObject *SbkObjectType_TypeF(void) { static PyTypeObject *type = nullptr; if (!type) { + // PYSIDE-1019: Insert the default tp_getattro explicitly here + // so we can overwrite it a bit. + type_getattro = PyType_Type.tp_getattro; SbkObjectType_Type_spec.basicsize = PepHeapType_SIZE + sizeof(SbkObjectTypePrivate); - type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec)); + type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&SbkObjectType_Type_spec)); #if PY_VERSION_HEX < 0x03000000 if (patch_tp_new_wrapper(type) < 0) return nullptr; @@ -244,6 +325,11 @@ static int SbkObject_traverse(PyObject *self, visitproc visit, void *arg) if (sbkSelf->ob_dict) Py_VISIT(sbkSelf->ob_dict); + +#if PY_VERSION_HEX >= 0x03090000 + // This was not needed before Python 3.9 (Python issue 35810 and 40217) + Py_VISIT(Py_TYPE(self)); +#endif return 0; } @@ -263,7 +349,12 @@ static int SbkObject_clear(PyObject *self) return 0; } +static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name); +static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value); + static PyType_Slot SbkObject_Type_slots[] = { + {Py_tp_getattro, reinterpret_cast<void *>(SbkObject_GenericGetAttr)}, + {Py_tp_setattro, reinterpret_cast<void *>(SbkObject_GenericSetAttr)}, {Py_tp_dealloc, reinterpret_cast<void *>(SbkDeallocWrapperWithPrivateDtor)}, {Py_tp_traverse, reinterpret_cast<void *>(SbkObject_traverse)}, {Py_tp_clear, reinterpret_cast<void *>(SbkObject_clear)}, @@ -273,7 +364,7 @@ static PyType_Slot SbkObject_Type_slots[] = { {0, nullptr} }; static PyType_Spec SbkObject_Type_spec = { - "Shiboken.Object", + "1:Shiboken.Object", sizeof(SbkObject), 0, Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, @@ -285,7 +376,7 @@ SbkObjectType *SbkObject_TypeF(void) { static PyTypeObject *type = nullptr; if (!type) { - type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObject_Type_spec)); + type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&SbkObject_Type_spec)); Py_TYPE(type) = SbkObjectType_TypeF(); Py_INCREF(Py_TYPE(type)); type->tp_weaklistoffset = offsetof(SbkObject, weakreflist); @@ -309,8 +400,32 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete) // Need to decref the type if this is the dealloc func; if type // is subclassed, that dealloc func will decref (see subtype_dealloc // in typeobject.c in the python sources) - bool needTypeDecref = (PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper + bool needTypeDecref = (false + || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapperWithPrivateDtor); + if (PepRuntime_38_flag) { + // PYSIDE-939: Additional rule: Also when a subtype is heap allocated, + // then the subtype_dealloc deref will be suppressed, and we need again + // to supply a decref. + needTypeDecref |= (pyType->tp_base->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0; + } + +#if defined(__APPLE__) + // Just checking once that our assumptions are right. + if (false) { + void *p = PyType_GetSlot(pyType, Py_tp_dealloc); + Dl_info dl_info; + dladdr(p, &dl_info); + fprintf(stderr, "tp_dealloc is %s\n", dl_info.dli_sname); + } + // Gives one of our functions + // "Sbk_object_dealloc" + // "SbkDeallocWrapperWithPrivateDtor" + // "SbkDeallocQAppWrapper" + // "SbkDeallocWrapper" + // but for typedealloc_test.py we get + // "subtype_dealloc" +#endif // Ensure that the GC is no longer tracking this object to avoid a // possible reentrancy problem. Since there are multiple steps involved @@ -318,9 +433,7 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete) // be invoked and it trying to delete this object while it is still in // progress from the first time around, resulting in a double delete and a // crash. - // PYSIDE-571: Some objects do not use GC, so check this! - if (PyObject_IS_GC(pyObj)) - PyObject_GC_UnTrack(pyObj); + PyObject_GC_UnTrack(pyObj); // Check that Python is still initialized as sometimes this is called by a static destructor // after Python interpeter is shutdown. @@ -348,6 +461,11 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete) } } + PyObject *error_type, *error_value, *error_traceback; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + if (canDelete) { if (sotp->is_multicpp) { Shiboken::DtorAccumulatorVisitor visitor(sbkObj); @@ -367,8 +485,16 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete) Shiboken::Object::deallocData(sbkObj, true); } + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + if (needTypeDecref) Py_DECREF(pyType); + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(pyType); + } } void SbkDeallocWrapper(PyObject *pyObj) @@ -380,7 +506,7 @@ void SbkDeallocQAppWrapper(PyObject *pyObj) { SbkDeallocWrapper(pyObj); // PYSIDE-571: make sure to create a singleton deleted qApp. - MakeSingletonQAppWrapper(nullptr); + Py_DECREF(MakeQAppWrapper(nullptr)); } void SbkDeallocWrapperWithPrivateDtor(PyObject *self) @@ -412,9 +538,149 @@ void SbkObjectTypeDealloc(PyObject *pyObj) #ifndef Py_LIMITED_API Py_TRASHCAN_SAFE_END(pyObj); #endif + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(pyObj)); + } +} + +//////////////////////////////////////////////////////////////////////////// +// +// Support for the qApp macro. +// +// qApp is a macro in Qt5. In Python, we simulate that a little by a +// variable that monitors Q*Application.instance(). +// This variable is also able to destroy the app by qApp.shutdown(). +// + +PyObject *MakeQAppWrapper(PyTypeObject *type) +{ + static PyObject *qApp_last = nullptr; + + // protecting from multiple application instances + if (!(type == nullptr || qApp_last == Py_None)) { + const char *res_name = PepType_GetNameStr(Py_TYPE(qApp_last)); + const char *type_name = PepType_GetNameStr(type); + PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before" + " creating a new %s instance.", res_name, type_name); + return nullptr; + } + + // monitoring the last application state + PyObject *qApp_curr = type != nullptr ? PyObject_GC_New(PyObject, type) : Py_None; + static PyObject *builtins = PyEval_GetBuiltins(); + if (PyDict_SetItem(builtins, Shiboken::PyName::qApp(), qApp_curr) < 0) + return nullptr; + qApp_last = qApp_curr; + // Note: This Py_INCREF would normally be wrong because the qApp + // object already has a reference from PyObject_GC_New. But this is + // exactly the needed reference that keeps qApp alive from alone! + Py_INCREF(qApp_curr); + // PYSIDE-1470: As a side effect, the interactive "_" variable tends to + // create reference cycles. It was found when using gc.collect(). But using + // PyGC_collect() inside the C code had no effect in the interactive shell. + // The cycle exists only in the eval loop of the interpreter! + if (PyDict_GetItem(builtins, Shiboken::PyName::underscore())) + PyDict_SetItem(builtins, Shiboken::PyName::underscore(), Py_None); + return qApp_curr; +} + +////////////////////////////////////////////////////////////////////////////// +// +// PYSIDE-1019: Support switchable extensions +// +// We simply exchange the complete class dicts. +// +// This is done in which replaces +// --------------- -------------- +// mangled_type_getattro type_getattro +// Sbk_TypeGet___dict__ type_dict +// SbkObject_GenericGetAttr PyObject_GenericGetAttr +// SbkObject_GenericSetAttr PyObject_GenericSetAttr +// + +SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func) +{ + auto ret = SelectFeatureSet; + SelectFeatureSet = func; + return ret; +} + +static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name) +{ + /* + * Note: This `type_getattro` version is only the default that comes + * from `PyType_Type.tp_getattro`. This does *not* interfere in any way + * with the complex `tp_getattro` of `QObject` and other instances. + * What we change here is the meta class of `QObject`. + */ + if (SelectFeatureSet != nullptr) + type->tp_dict = SelectFeatureSet(type); + return type_getattro(reinterpret_cast<PyObject *>(type), name); +} + +static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context) +{ + /* + * This is the override for getting a dict. + */ + auto dict = type->tp_dict; + if (dict == nullptr) + Py_RETURN_NONE; + if (SelectFeatureSet != nullptr) + dict = SelectFeatureSet(type); + return PyDictProxy_New(dict); +} + +// These functions replace the standard PyObject_Generic(Get|Set)Attr functions. +// They provide the default that "object" inherits. +// Everything else is directly handled by cppgenerator that calls `Feature::Select`. +static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name) +{ + auto type = Py_TYPE(obj); + if (SelectFeatureSet != nullptr) + type->tp_dict = SelectFeatureSet(type); + return PyObject_GenericGetAttr(obj, name); +} + +static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) +{ + auto type = Py_TYPE(obj); + if (SelectFeatureSet != nullptr) + type->tp_dict = SelectFeatureSet(type); + return PyObject_GenericSetAttr(obj, name, value); } -PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds) +// Caching the select Id. +int SbkObjectType_GetReserved(PyTypeObject *type) +{ + auto ptr = PepType_SOTP(reinterpret_cast<SbkObjectType *>(type)); + // PYSIDE-1019: During import PepType_SOTP is still zero. + if (ptr == nullptr) + return -1; + return ptr->pyside_reserved_bits; +} + +void SbkObjectType_SetReserved(PyTypeObject *type, int value) +{ + PepType_SOTP(reinterpret_cast<SbkObjectType *>(type))->pyside_reserved_bits = value; +} + +const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type) +{ + return PepType_SOTP(type)->propertyStrings; +} + +void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings) +{ + PepType_SOTP(reinterpret_cast<SbkObjectType *>(type))->propertyStrings = strings; +} + +// +////////////////////////////////////////////////////////////////////////////// + +static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { // Check if all bases are new style before calling type.tp_new // Was causing gc assert errors in test_bug704.py when @@ -441,7 +707,8 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k #ifndef IS_PY3K if (PyClass_Check(baseType)) { PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. " - "PySide only support multiple inheritance from python new style class.", metatype->tp_name); + "PySide only supports multiple inheritance from Python new style classes.", + metatype->tp_name); return 0; } #endif @@ -453,7 +720,18 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k // The meta type creates a new type when the Python programmer extends a wrapped C++ class. auto type_new = reinterpret_cast<newfunc>(PyType_Type.tp_new); + + // PYSIDE-939: This is a temporary patch that circumvents the problem + // with Py_TPFLAGS_METHOD_DESCRIPTOR until this is finally solved. + // PyType_Ready uses mro(). We need to temporarily remove the flag from it's type. + // We cannot use PyMethodDescr_Type since it is not exported by Python 2.7 . + static PyTypeObject *PyMethodDescr_TypePtr = Py_TYPE( + PyObject_GetAttr(reinterpret_cast<PyObject *>(&PyType_Type), Shiboken::PyName::mro())); + auto hold = PyMethodDescr_TypePtr->tp_flags; + PyMethodDescr_TypePtr->tp_flags &= ~Py_TPFLAGS_METHOD_DESCRIPTOR; auto *newType = reinterpret_cast<SbkObjectType *>(type_new(metatype, args, kwds)); + PyMethodDescr_TypePtr->tp_flags = hold; + if (!newType) return nullptr; #if PY_VERSION_HEX < 0x03000000 @@ -492,11 +770,13 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k sotp->d_func = nullptr; sotp->is_user_type = 1; + // PYSIDE-1463: Prevent feature switching while in the creation process + auto saveFeature = initSelectableFeature(nullptr); for (SbkObjectType *base : bases) { if (PepType_SOTP(base)->subtype_init) PepType_SOTP(base)->subtype_init(newType, args, kwds); } - + initSelectableFeature(saveFeature); return reinterpret_cast<PyObject *>(newType); } @@ -519,49 +799,28 @@ static PyObject *_setupNew(SbkObject *self, PyTypeObject *subtype) self->ob_dict = nullptr; self->weakreflist = nullptr; self->d = d; + PyObject_GC_Track(reinterpret_cast<PyObject *>(self)); return reinterpret_cast<PyObject *>(self); } PyObject *SbkObjectTpNew(PyTypeObject *subtype, PyObject *, PyObject *) { SbkObject *self = PyObject_GC_New(SbkObject, subtype); - PyObject *res = _setupNew(self, subtype); - PyObject_GC_Track(reinterpret_cast<PyObject *>(self)); - return res; + return _setupNew(self, subtype); } PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *, PyObject *) { - // PYSIDE-571: - // For qApp, we need to create a singleton Python object. - // We cannot track this with the GC, because it is a static variable! - - // Python 2 has a weird handling of flags in derived classes that Python 3 - // does not have. Observed with bug_307.py. - // But it could theoretically also happen with Python3. - // Therefore we enforce that there is no GC flag, ever! - - // PYSIDE-560: - // We avoid to use this in Python 3, because we have a hard time to get - // write access to these flags -#ifndef IS_PY3K - if (PyType_HasFeature(subtype, Py_TPFLAGS_HAVE_GC)) { - subtype->tp_flags &= ~Py_TPFLAGS_HAVE_GC; - subtype->tp_free = PyObject_Del; - } -#endif - auto self = reinterpret_cast<SbkObject *>(MakeSingletonQAppWrapper(subtype)); - return self == nullptr ? nullptr : _setupNew(self, subtype); -} - -void -object_dealloc(PyObject *self) -{ - Py_TYPE(self)->tp_free(self); + auto self = reinterpret_cast<SbkObject *>(MakeQAppWrapper(subtype)); + if (self == nullptr) + return nullptr; + auto ret = _setupNew(self, subtype); + auto priv = self->d; + priv->isQAppSingleton = 1; + return ret; } -PyObject * -SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *) +PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *) { // PYSIDE-595: Give the same error as type_call does when tp_new is NULL. PyErr_Format(PyExc_TypeError, @@ -570,6 +829,78 @@ SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *) return nullptr; } +PyObject *SbkType_FromSpec(PyType_Spec *spec) +{ + return SbkType_FromSpecWithBases(spec, nullptr); +} + +PyObject *SbkType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) +{ + // PYSIDE-1286: Generate correct __module__ and __qualname__ + // The name field can now be extended by an "n:" prefix which is + // the number of modules in the name. The default is 1. + // + // Example: + // "2:mainmod.submod.mainclass.subclass" + // results in + // __module__ : "mainmod.submod" + // __qualname__ : "mainclass.subclass" + // __name__ : "subclass" + + PyType_Spec new_spec = *spec; + const char *colon = strchr(spec->name, ':'); + assert(colon); + int package_level = atoi(spec->name); + const char *mod = new_spec.name = colon + 1; + + PyObject *type = PyType_FromSpecWithBases(&new_spec, bases); + if (type == nullptr) + return nullptr; + + const char *qual = mod; + for (int idx = package_level; idx > 0; --idx) { + const char *dot = strchr(qual, '.'); + if (!dot) + break; + qual = dot + 1; + } + int mlen = qual - mod - 1; + Shiboken::AutoDecRef module(Shiboken::String::fromCString(mod, mlen)); + Shiboken::AutoDecRef qualname(Shiboken::String::fromCString(qual)); + if (PyObject_SetAttr(type, Shiboken::PyMagicName::module(), module) < 0) + return nullptr; + if (PyObject_SetAttr(type, Shiboken::PyMagicName::qualname(), qualname) < 0) + return nullptr; + return type; +} + +// PYSIDE-74: Fallback used in all types now. +PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op) +{ + // This is a very simple implementation that supplies a simple identity. + static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="}; + PyObject *res; + + switch (op) { + + case Py_EQ: + res = (self == other) ? Py_True : Py_False; + break; + case Py_NE: + res = (self != other) ? Py_True : Py_False; + break; + default: + PyErr_Format(PyExc_TypeError, + "'%s' not supported between instances of '%.100s' and '%.100s'", + opstrings[op], + self->ob_type->tp_name, + other->ob_type->tp_name); + return nullptr; + } + Py_INCREF(res); + return res; +} + } //extern "C" @@ -610,35 +941,6 @@ bool walkThroughClassHierarchy(PyTypeObject *currentType, HierarchyVisitor *visi return result; } -bool importModule(const char *moduleName, PyTypeObject *** cppApiPtr) -{ - PyObject *sysModules = PyImport_GetModuleDict(); - PyObject *module = PyDict_GetItemString(sysModules, moduleName); - if (!module) { - module = PyImport_ImportModule(moduleName); - if (!module) - return false; - } else { - Py_INCREF(module); - } - - Shiboken::AutoDecRef cppApi(PyObject_GetAttrString(module, "_Cpp_Api")); - Py_DECREF(module); - - if (cppApi.isNull()) - return false; - -#ifdef IS_PY3K - if (PyCapsule_CheckExact(cppApi)) - *cppApiPtr = reinterpret_cast<PyTypeObject **>(PyCapsule_GetPointer(cppApi, nullptr)); -#else - // Python 2.6 doesn't have PyCapsule API, so let's keep usign PyCObject on all Python 2.x - if (PyCObject_Check(cppApi)) - *cppApiPtr = reinterpret_cast<PyTypeObject **>(PyCObject_AsVoidPtr(cppApi)); -#endif - return true; -} - // Wrapper metatype and base type ---------------------------------------------------------- HierarchyVisitor::HierarchyVisitor() = default; @@ -683,7 +985,9 @@ void init() Conversions::init(); +#if PY_VERSION_HEX < 0x03070000 PyEval_InitThreads(); +#endif //Init private data Pep384_Init(); @@ -691,13 +995,13 @@ void init() Shiboken::ObjectType::initPrivateData(SbkObject_TypeF()); if (PyType_Ready(SbkEnumType_TypeF()) < 0) - Py_FatalError("[libshiboken] Failed to initialise Shiboken.SbkEnumType metatype."); + Py_FatalError("[libshiboken] Failed to initialize Shiboken.SbkEnumType metatype."); if (PyType_Ready(SbkObjectType_TypeF()) < 0) - Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapperType metatype."); + Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapperType metatype."); if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())) < 0) - Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapper type."); + Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapper type."); VoidPtr::init(); @@ -705,9 +1009,10 @@ void init() } // setErrorAboutWrongArguments now gets overload info from the signature module. -void setErrorAboutWrongArguments(PyObject *args, const char *funcName) +// Info can be nullptr and contains extra info. +void setErrorAboutWrongArguments(PyObject *args, const char *funcName, PyObject *info) { - SetError_Argument(args, funcName); + SetError_Argument(args, funcName, info); } class FindBaseTypeVisitor : public HierarchyVisitor @@ -839,7 +1144,6 @@ introduceWrapperType(PyObject *enclosingObject, const char *typeName, const char *originalName, PyType_Spec *typeSpec, - const char *signatureStrings[], ObjectDestructor cppObjDtor, SbkObjectType *baseType, PyObject *baseTypes, @@ -847,7 +1151,7 @@ introduceWrapperType(PyObject *enclosingObject, { typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType ? baseType : SbkObject_TypeF()); - PyObject *heaptype = PyType_FromSpecWithBases(typeSpec, baseTypes); + PyObject *heaptype = SbkType_FromSpecWithBases(typeSpec, baseTypes); Py_TYPE(heaptype) = SbkObjectType_TypeF(); Py_INCREF(Py_TYPE(heaptype)); auto *type = reinterpret_cast<SbkObjectType *>(heaptype); @@ -864,8 +1168,7 @@ introduceWrapperType(PyObject *enclosingObject, BindingManager::instance().addClassInheritance(baseType, type); } } - // PYSIDE-510: Here is the single change to support signatures. - if (SbkSpecial_Type_Ready(enclosingObject, reinterpret_cast<PyTypeObject *>(type), signatureStrings) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(type)) < 0) return nullptr; initPrivateData(type); @@ -882,7 +1185,13 @@ introduceWrapperType(PyObject *enclosingObject, // PyModule_AddObject steals type's reference. Py_INCREF(ob_type); - return PyModule_AddObject(enclosingObject, typeName, ob_type) == 0 ? type : nullptr; + if (PyModule_AddObject(enclosingObject, typeName, ob_type) != 0) { + std::cerr << "Warning: " << __FUNCTION__ << " returns nullptr for " + << typeName << '/' << originalName << " due to PyModule_AddObject(enclosingObject=" + << enclosingObject << ",ob_type=" << ob_type << ") failing\n"; + return nullptr; + } + return type; } void setSubTypeInitHook(SbkObjectType *type, SubTypeInitHook func) @@ -998,6 +1307,12 @@ bool wasCreatedByPython(SbkObject *pyObj) void callCppDestructors(SbkObject *pyObj) { + auto priv = pyObj->d; + if (priv->isQAppSingleton && DestroyQApplication) { + // PYSIDE-1470: Allow to destroy the application from Shiboken. + DestroyQApplication(); + return; + } PyTypeObject *type = Py_TYPE(pyObj); SbkObjectTypePrivate *sotp = PepType_SOTP(type); if (sotp->is_multicpp) { @@ -1010,18 +1325,19 @@ void callCppDestructors(SbkObject *pyObj) sotp->cpp_dtor(pyObj->d->cptr[0]); } + if (priv->validCppObject && priv->containsCppWrapper) { + BindingManager::instance().releaseWrapper(pyObj); + } + /* invalidate needs to be called before deleting pointer array because it needs to delete entries for them from the BindingManager hash table; also release wrapper explicitly if object contains C++ wrapper because invalidate doesn't */ invalidate(pyObj); - if (pyObj->d->validCppObject && pyObj->d->containsCppWrapper) { - BindingManager::instance().releaseWrapper(pyObj); - } - delete[] pyObj->d->cptr; - pyObj->d->cptr = nullptr; - pyObj->d->validCppObject = false; + delete[] priv->cptr; + priv->cptr = nullptr; + priv->validCppObject = false; } bool hasOwnership(SbkObject *pyObj) @@ -1337,11 +1653,6 @@ PyObject *newObject(SbkObjectType *instanceType, return reinterpret_cast<PyObject *>(self); } -void destroy(SbkObject *self) -{ - destroy(self, nullptr); -} - void destroy(SbkObject *self, void *cppData) { // Skip if this is called with NULL pointer this can happen in derived classes |