diff options
author | Christian Tismer <tismer@stackless.com> | 2017-12-17 19:12:56 +0100 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2018-05-30 18:13:41 +0000 |
commit | 18dc31becdd994c53a9f894087cf1ef99fbd0232 (patch) | |
tree | 3021cfa473f20102bfb63a26117776615b91b526 | |
parent | 50dd4ae202d7afb3556335c056db003f5ef50532 (diff) |
PEP 384-squash: Implement PEP 384
This is the condensed checkin of 18 commits which created
the implementation of PEP 384.
Task-number: PYSIDE-560
Change-Id: I834c659af4c2b55b268f8e8dc4cfa53f02502409
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
79 files changed, 4552 insertions, 1597 deletions
diff --git a/build_scripts/main.py b/build_scripts/main.py index 26fc191c5..f27743559 100644 --- a/build_scripts/main.py +++ b/build_scripts/main.py @@ -985,6 +985,14 @@ class PysideBuild(_build): cmake_cmd.append("-DPYTHON_DEBUG_LIBRARY={}".format( self.py_library)) + if OPTION_LIMITED_API == "yes" or not OPTION_LIMITED_API: + cmake_cmd.append("-DFORCE_LIMITED_API=yes") + elif OPTION_LIMITED_API == "no": + cmake_cmd.append("-DFORCE_LIMITED_API=no") + else: + raise DistutilsSetupError("option limited-api must be 'yes' or 'no' " + "(default yes if applicable)") + if OPTION_VERBOSE_BUILD: cmake_cmd.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON") diff --git a/build_scripts/options.py b/build_scripts/options.py index 80c9041e4..d7174feff 100644 --- a/build_scripts/options.py +++ b/build_scripts/options.py @@ -80,4 +80,4 @@ OPTION_QT_SRC = option_value("qt-src-dir") OPTION_VERBOSE_BUILD = has_option("verbose-build") OPTION_SANITIZE_ADDRESS = has_option("sanitize-address") OPTION_SNAPSHOT_BUILD = has_option("snapshot-build") - +OPTION_LIMITED_API = option_value("limited-api") @@ -136,6 +136,8 @@ using `setup.py build`: --sanitize-address will build the project with address sanitizer enabled (Linux or macOS only). --skip-docs skip the documentation generation. + --limited-api=yes|no default yes if applicable + Set or clear the limited API flag. Ignored for Python 2. REQUIREMENTS: diff --git a/sources/pyside2/CMakeLists.txt b/sources/pyside2/CMakeLists.txt index 77382480d..08647530c 100644 --- a/sources/pyside2/CMakeLists.txt +++ b/sources/pyside2/CMakeLists.txt @@ -400,12 +400,53 @@ else() endif() message(STATUS "Detected OS: ${AUTO_OS}") +# On Windows, PYTHON_LIBRARIES can be a list. Example: +# optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib +# On other platforms, this result is not used at all. +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + for lib in '${PYTHON_LIBRARIES}'.split(';'): + if '/' in lib: + prefix, py = lib.rsplit( '/', 1) + if py.startswith('python3'): + print(prefix + '/python3.lib') + break + " + OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (WIN32) set(PATH_SEP "\;") else() set(PATH_SEP ":") endif() +option(FORCE_LIMITED_API "Enable the limited API." "no") + +set(PYTHON_LIMITED_API 0) +if(FORCE_LIMITED_API STREQUAL "yes") + # GREATER_EQUAL is available only from cmake 3.7 on. We mean python 3.5 . + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + if (WIN32) + set(SHIBOKEN_PYTHON_LIBRARIES ${PYTHON_LIMITED_LIBRARIES}) + endif() + add_definitions("-DPy_LIMITED_API=0x03050000") + set(PYTHON_LIMITED_API 1) + endif() + if (CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions("-DNDEBUG") + endif() +endif() + +if (PYTHON_LIMITED_API) + if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}") + message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!") + endif() + message(STATUS "******************************************************") + message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}") + message(STATUS "******************************************************") +endif() + # Define supported Qt Version set(SUPPORTED_QT_VERSION "${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}") diff --git a/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp b/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp index 22825a5cb..ed5fef3ae 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp @@ -47,7 +47,7 @@ extern "C" { static Py_ssize_t SbkQByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) - *lenp = self->ob_type->tp_as_sequence->sq_length(self); + *lenp = Py_TYPE(self)->tp_as_sequence->sq_length(self); return 1; } diff --git a/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp b/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp index 6a997c852..f1d5a6bfc 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp @@ -82,6 +82,6 @@ if (PyIndex_Check(_key)) { } else { PyErr_Format(PyExc_TypeError, "list indices must be integers or slices, not %.200s", - _key->ob_type->tp_name); + PepType((Py_TYPE(_key)))->tp_name); return NULL; } diff --git a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp index 5d28fbf41..46a69be31 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include <Python.h> +#include <sbkpython.h> #include <shiboken.h> #include <pysideweakref.h> #include <QEasingCurve> diff --git a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h index 7053d808c..358ea9eec 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h +++ b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h @@ -40,7 +40,7 @@ #ifndef __QEASINGCURVE_GLUE__ #define __QEASINGCURVE_GLUE__ -#include <Python.h> +#include <sbkpython.h> #include <QEasingCurve> class PySideEasingCurveFunctor diff --git a/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp b/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp index ed37cef34..20f3720bf 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp @@ -43,8 +43,7 @@ static bool isDecorator(PyObject* method, PyObject* self) if (!PyObject_HasAttr(self, methodName)) return true; Shiboken::AutoDecRef otherMethod(PyObject_GetAttr(self, methodName)); - return reinterpret_cast<PyMethodObject*>(otherMethod.object())->im_func != \ - reinterpret_cast<PyMethodObject*>(method)->im_func; + return PyMethod_GET_FUNCTION(otherMethod.object()) != PyMethod_GET_FUNCTION(method); } static bool getReceiver(QObject *source, const char* signal, PyObject* callback, QObject** receiver, PyObject** self, QByteArray* callbackSig) diff --git a/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp b/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp index 464fb68b1..b32d104fd 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp @@ -41,7 +41,7 @@ static QObject* _findChildHelper(const QObject* parent, const QString& name, PyT { foreach(QObject* child, parent->children()) { Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject*](child)); - if (PyType_IsSubtype(pyChild->ob_type, desiredType) + if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && (name.isNull() || name == child->objectName())) { return child; } @@ -71,7 +71,7 @@ static void _findChildrenHelper(const QObject* parent, const T& name, PyTypeObje { foreach(const QObject* child, parent->children()) { Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject*](child)); - if (PyType_IsSubtype(pyChild->ob_type, desiredType) && _findChildrenComparator(child, name)) + if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && _findChildrenComparator(child, name)) PyList_Append(result, pyChild); _findChildrenHelper(child, name, desiredType, result); } diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index f0b6b9640..63c3d50ea 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -291,12 +291,18 @@ </native-to-target> <target-to-native> <add-conversion type="PyUnicode"> - Py_UNICODE *unicode = PyUnicode_AS_UNICODE(%in); - #if defined(Py_UNICODE_WIDE) + #ifndef Py_LIMITED_API + Py_UNICODE* unicode = PyUnicode_AS_UNICODE(%in); + # if defined(Py_UNICODE_WIDE) // cast as Py_UNICODE can be a different type %out = QString::fromUcs4((const uint*)unicode); - #else + # else %out = QString::fromUtf16((const ushort*)unicode, PyUnicode_GET_SIZE(%in)); + # endif + #else + wchar_t *temp = PyUnicode_AsWideCharString(%in, NULL); + %out = QString::fromWCharArray(temp); + PyMem_Free(temp); #endif </add-conversion> <add-conversion type="PyString" check="py2kStrCheck(%in)"> @@ -410,7 +416,7 @@ <add-conversion type="SbkObject"> // a class supported by QVariant? int typeCode; - const char *typeName = QVariant_resolveMetaType(%in->ob_type, &typeCode); + const char *typeName = QVariant_resolveMetaType(Py_TYPE(%in), &typeCode); if (!typeCode || !typeName) return; QVariant var(typeCode, (void*)0); @@ -435,9 +441,9 @@ <inject-code class="native" position="beginning"> static const char *QVariant_resolveMetaType(PyTypeObject *type, int *typeId) { - if (PyObject_TypeCheck(type, &SbkObjectType_Type)) { - SbkObjectType *sbkType = (SbkObjectType*)type; - const char *typeName = Shiboken::ObjectType::getOriginalName(sbkType); + if (PyObject_TypeCheck(type, SbkObjectType_TypeF())) { + SbkObjectType* sbkType = (SbkObjectType*)type; + const char* typeName = Shiboken::ObjectType::getOriginalName(sbkType); if (!typeName) return 0; bool valueType = '*' != typeName[qstrlen(typeName) - 1]; @@ -456,15 +462,16 @@ // tp_base does not always point to the first base class, but rather to the first // that has added any python fields or slots to its object layout. // See https://mail.python.org/pipermail/python-list/2009-January/520733.html - if (type->tp_bases) { - for (int i = 0; i < PyTuple_GET_SIZE(type->tp_bases); ++i) { - const char *derivedName = QVariant_resolveMetaType((PyTypeObject*)PyTuple_GET_ITEM(type->tp_bases, i), typeId); + if (PepType(type)->tp_bases) { + for (int i = 0; i < PyTuple_GET_SIZE(PepType(type)->tp_bases); ++i) { + const char *derivedName = QVariant_resolveMetaType((PyTypeObject*)PyTuple_GET_ITEM( + PepType(type)->tp_bases, i), typeId); if (derivedName) return derivedName; } } - else if (type->tp_base) { - return QVariant_resolveMetaType(type->tp_base, typeId); + else if (PepType(type)->tp_base) { + return QVariant_resolveMetaType(PepType(type)->tp_base, typeId); } } *typeId = 0; @@ -563,16 +570,16 @@ </add-conversion> <add-conversion type="PyTypeObject"> const char *typeName; - if (Shiboken::String::checkType((PyTypeObject*)%in)) + if (Shiboken::String::checkType(reinterpret_cast<PyTypeObject*>(%in))) typeName = "QString"; else if (%in == reinterpret_cast<PyObject*>(&PyFloat_Type)) typeName = "double"; // float is a UserType in QVariant. else if (%in == reinterpret_cast<PyObject*>(&PyLong_Type)) typeName = "int"; // long is a UserType in QVariant. - else if (%in->ob_type == &SbkObjectType_Type) + else if (Py_TYPE(%in) == SbkObjectType_TypeF()) typeName = Shiboken::ObjectType::getOriginalName((SbkObjectType*)%in); else - typeName = (reinterpret_cast<PyTypeObject*>(%in))->tp_name; + typeName = PepType((reinterpret_cast<PyTypeObject*>(%in)))->tp_name; %out = QVariant::nameToType(typeName); </add-conversion> <add-conversion type="PyString" check="Shiboken::String::check(%in)"> @@ -2589,7 +2596,7 @@ <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> - QByteArray b((reinterpret_cast<PyObject*>(%PYSELF))->ob_type->tp_name); + QByteArray b(PepType(Py_TYPE(%PYSELF))->tp_name); PyObject *aux = Shiboken::String::fromStringAndSize(%CPPSELF.constData(), %CPPSELF.size()); if (PyUnicode_CheckExact(aux)) { PyObject *tmp = PyUnicode_AsASCIIString(aux); @@ -3088,7 +3095,7 @@ <inject-code> Py_ssize_t size; uchar *ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1, &size)); - %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(const_cast<const uchar*>(ptr), size); + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(const_cast<const uchar*>(ptr), size); %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); </inject-code> </modify-function> @@ -3114,8 +3121,8 @@ // %FUNCTION_NAME() - disable generation of c++ function call (void) %2; // remove warning about unused variable Shiboken::AutoDecRef emptyTuple(PyTuple_New(0)); - PyObject *pyTimer = Shiboken::SbkType<QTimer>()->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); - Shiboken::SbkType<QTimer>()->tp_init(pyTimer, emptyTuple, 0); + PyObject *pyTimer = PepType(Shiboken::SbkType<QTimer>())->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); + PepType(Shiboken::SbkType<QTimer>())->tp_init(pyTimer, emptyTuple, 0); QTimer* timer = %CONVERTTOCPP[QTimer*](pyTimer); Shiboken::AutoDecRef result( @@ -3138,14 +3145,14 @@ <inject-code class="target" position="beginning"> // %FUNCTION_NAME() - disable generation of c++ function call Shiboken::AutoDecRef emptyTuple(PyTuple_New(0)); - PyObject *pyTimer = Shiboken::SbkType<QTimer>()->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); - Shiboken::SbkType<QTimer>()->tp_init(pyTimer, emptyTuple, 0); + PyObject *pyTimer = PepType(Shiboken::SbkType<QTimer>())->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); + PepType(Shiboken::SbkType<QTimer>())->tp_init(pyTimer, emptyTuple, 0); QTimer* timer = %CONVERTTOCPP[QTimer*](pyTimer); timer->setSingleShot(true); - if (PyObject_TypeCheck(%2, &PySideSignalInstanceType)) { + if (PyObject_TypeCheck(%2, PySideSignalInstanceTypeF())) { PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance*>(%2); - Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s",PySide::Signal::getSignature(signalInstance))); + Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance))); Shiboken::AutoDecRef result( PyObject_CallMethod(pyTimer, const_cast<char*>("connect"), @@ -4026,7 +4033,7 @@ s1.addTransition(button.clicked, s1h)</code> <replace-default-expression with="0" /> </modify-argument> <inject-code> - if (PyObject_TypeCheck(%1, &PySideSignalInstanceType)) { + if (PyObject_TypeCheck(%1, PySideSignalInstanceTypeF())) { PyObject *dataSource = PySide::Signal::getObject((PySideSignalInstance*)%PYARG_1); Shiboken::AutoDecRef obType(PyObject_Type(dataSource)); QObject* sender = %CONVERTTOCPP[QObject*](dataSource); @@ -4082,11 +4089,11 @@ s1.addTransition(button.clicked, s1h)</code> // since it refers to a name very tied to the generator implementation. // Check bug #362 for more information on this // http://bugs.openbossa.org/show_bug.cgi?id=362 - if (!PyObject_TypeCheck(%1, &PySideSignalInstanceType)) + if (!PyObject_TypeCheck(%1, PySideSignalInstanceTypeF())) goto Sbk_%TYPEFunc_%FUNCTION_NAME_TypeError; PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance*>(%1); QObject* sender = %CONVERTTOCPP[QObject*](PySide::Signal::getObject(signalInstance)); - QSignalTransition*%0 = %CPPSELF->%FUNCTION_NAME(sender,PySide::Signal::getSignature(signalInstance),%2); + QSignalTransition *%0 = %CPPSELF->%FUNCTION_NAME(sender, PySide::Signal::getSignature(signalInstance),%2); %PYARG_0 = %CONVERTTOPYTHON[QSignalTransition*](%0); </inject-code> </add-function> diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml index 47bf62992..eee22b55c 100644 --- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml +++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml @@ -1752,7 +1752,7 @@ PyErr_Format(PyExc_TypeError, "Invalid return value in function %s, expected %s, got %s.", "QValidator.validate", "PySide2.QtGui.QValidator.State, (PySide2.QtGui.QValidator.State,), (PySide2.QtGui.QValidator.State, unicode) or (PySide2.QtGui.QValidator.State, unicode, int)", - pyResult->ob_type->tp_name); + PepType((Py_TYPE(pyResult)))->tp_name); return QValidator::State(); } </template> diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp index d95ae2259..fa9eb6349 100644 --- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp +++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp @@ -120,9 +120,9 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, } PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); - if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) { + if (!PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) { PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", - qobjectType->tp_name, pyObjType->tp_name); + PepType(qobjectType)->tp_name, PepType(pyObjType)->tp_name); return -1; } @@ -229,57 +229,34 @@ void propListTpFree(void* self) PySideProperty* pySelf = reinterpret_cast<PySideProperty*>(self); delete reinterpret_cast<QmlListProperty*>(PySide::Property::userData(pySelf)); // calls base type constructor - Py_TYPE(pySelf)->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } -PyTypeObject PropertyListType = { - PyVarObject_HEAD_INIT(0, 0) - "ListProperty", /*tp_name*/ - sizeof(PySideProperty), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - &PySidePropertyType, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - propListTpInit, /*tp_init */ - 0, /*tp_alloc */ - 0, /*tp_new */ - propListTpFree, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ +static PyType_Slot PropertyListType_slots[] = { + {Py_tp_init, (void *)propListTpInit}, + {Py_tp_free, (void *)propListTpFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PropertyListType_spec = { + "PySide2.QtQml.ListProperty", + sizeof(PySideProperty), + 0, + Py_TPFLAGS_DEFAULT, + PropertyListType_slots, +}; + + +PyTypeObject *PropertyListTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + PyObject *bases = Py_BuildValue("(O)", PySidePropertyTypeF()); + type = (PyTypeObject *)PyType_FromSpecWithBases(&PropertyListType_spec, bases); + Py_XDECREF(bases); + } + return type; +} } // extern "C" @@ -312,7 +289,7 @@ int propListCount(QQmlListProperty<QObject> *propList) // Check return type int cppResult = 0; - PythonToCppFunc pythonToCpp; + PythonToCppFunc pythonToCpp = 0; if (PyErr_Occurred()) PyErr_Print(); else if ((pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(Shiboken::Conversions::PrimitiveTypeConverter<int>(), retVal))) @@ -387,7 +364,7 @@ QtQml_VolatileBoolObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return Q_NULLPTR; QtQml_VolatileBoolObject *self - = reinterpret_cast<QtQml_VolatileBoolObject *>(type->tp_alloc(type, 0)); + = reinterpret_cast<QtQml_VolatileBoolObject *>(PepType(type)->tp_alloc(type, 0)); if (self != Q_NULLPTR) self->flag = ok; @@ -444,10 +421,10 @@ QtQml_VolatileBoolObject_repr(QtQml_VolatileBoolObject *self) if (self->flag) s = PyBytes_FromFormat("%s(True)", - Py_TYPE(self)->tp_name); + PepType((Py_TYPE(self)))->tp_name); else s = PyBytes_FromFormat("%s(False)", - Py_TYPE(self)->tp_name); + PepType((Py_TYPE(self)))->tp_name); Py_XINCREF(s); return s; } @@ -459,87 +436,61 @@ QtQml_VolatileBoolObject_str(QtQml_VolatileBoolObject *self) if (self->flag) s = PyBytes_FromFormat("%s(True) -> %p", - Py_TYPE(self)->tp_name, &(self->flag)); + PepType((Py_TYPE(self)))->tp_name, &(self->flag)); else s = PyBytes_FromFormat("%s(False) -> %p", - Py_TYPE(self)->tp_name, &(self->flag)); + PepType((Py_TYPE(self)))->tp_name, &(self->flag)); Py_XINCREF(s); return s; } -PyTypeObject QtQml_VolatileBoolType = { - PyVarObject_HEAD_INIT(Q_NULLPTR, 0) /*ob_size*/ - "VolatileBool", /*tp_name*/ - sizeof(QtQml_VolatileBoolObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_repr), /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str), /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "VolatileBool objects contain a C++ volatile bool", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - QtQml_VolatileBoolObject_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - QtQml_VolatileBoolObject_new, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ -#if PY_MAJOR_VERSION > 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4 - 0 /* tp_finalize */ -#endif +static PyType_Slot QtQml_VolatileBoolType_slots[] = { + {Py_tp_repr, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_repr)}, + {Py_tp_str, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str)}, + {Py_tp_methods, (void *)QtQml_VolatileBoolObject_methods}, + {Py_tp_new, (void *)QtQml_VolatileBoolObject_new}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec QtQml_VolatileBoolType_spec = { + "PySide2.QtQml.VolatileBool", + sizeof(QtQml_VolatileBoolObject), + 0, + Py_TPFLAGS_DEFAULT, + QtQml_VolatileBoolType_slots, +}; + + +PyTypeObject *QtQml_VolatileBoolTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&QtQml_VolatileBoolType_spec); + return type; +} void PySide::initQmlSupport(PyObject* module) { ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init(); // Export QmlListProperty type - if (PyType_Ready(&PropertyListType) < 0) { + if (PyType_Ready(PropertyListTypeF()) < 0) { + PyErr_Print(); qWarning() << "Error initializing PropertyList type."; return; } - Py_INCREF(reinterpret_cast<PyObject *>(&PropertyListType)); - PyModule_AddObject(module, PropertyListType.tp_name, - reinterpret_cast<PyObject *>(&PropertyListType)); + Py_INCREF(reinterpret_cast<PyObject *>(PropertyListTypeF())); + PyModule_AddObject(module, PepType_GetNameStr(PropertyListTypeF()), + reinterpret_cast<PyObject *>(PropertyListTypeF())); - if (PyType_Ready(&QtQml_VolatileBoolType) < 0) { + if (PyType_Ready(QtQml_VolatileBoolTypeF()) < 0) { + PyErr_Print(); qWarning() << "Error initializing VolatileBool type."; return; } - Py_INCREF(&QtQml_VolatileBoolType); - PyModule_AddObject(module, QtQml_VolatileBoolType.tp_name, - reinterpret_cast<PyObject *>(&QtQml_VolatileBoolType)); + Py_INCREF(QtQml_VolatileBoolTypeF()); + PyModule_AddObject(module, PepType_GetNameStr(QtQml_VolatileBoolTypeF()), + reinterpret_cast<PyObject *>(QtQml_VolatileBoolTypeF())); } diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h index a4ee7309a..0ef6539a5 100644 --- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h +++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h @@ -40,7 +40,7 @@ #ifndef PYSIDEQMLREGISTERTYPE_H #define PYSIDEQMLREGISTERTYPE_H -#include <Python.h> +#include <sbkpython.h> struct SbkObjectType; @@ -78,8 +78,8 @@ typedef struct { volatile bool flag; } QtQml_VolatileBoolObject; -PyAPI_DATA(PyTypeObject) QtQml_VolatileBoolType; +PyAPI_FUNC(PyTypeObject *) QtQml_VolatileBoolTypeF(void); -#define VolatileBool_Check(op) (Py_TYPE(op) == &QtQml_VolatileBoolType) +#define VolatileBool_Check(op) (Py_TYPE(op) == QtQml_VolatileBoolTypeF()) #endif diff --git a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp index 594fa8015..67ef53551 100644 --- a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp +++ b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp @@ -106,11 +106,11 @@ struct ElementFactory<0> : ElementFactoryBase<0> typePointerName, typeListName, \ typeMetaObject, type, registered) -bool pyTypeObjectInheritsFromClass(const PyTypeObject *pyObjType, QByteArray className) +bool pyTypeObjectInheritsFromClass(PyTypeObject *pyObjType, QByteArray className) { className.append('*'); PyTypeObject *classPyType = Shiboken::Conversions::getPythonTypeObject(className.constData()); - bool isDerived = PySequence_Contains(pyObjType->tp_mro, + bool isDerived = PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast<PyObject *>(classPyType)); return isDerived; } @@ -118,7 +118,7 @@ bool pyTypeObjectInheritsFromClass(const PyTypeObject *pyObjType, QByteArray cla template <class WrapperClass> void registerTypeIfInheritsFromClass( QByteArray className, - const PyTypeObject *typeToRegister, + PyTypeObject *typeToRegister, const QByteArray &typePointerName, const QByteArray &typeListName, QMetaObject *typeMetaObject, @@ -190,7 +190,7 @@ bool quickRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int v PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); PyTypeObject *qQuickItemPyType = Shiboken::Conversions::getPythonTypeObject("QQuickItem*"); - bool isQuickItem = PySequence_Contains(pyObjType->tp_mro, + bool isQuickItem = PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast<PyObject *>(qQuickItemPyType)); // Register only classes that inherit QQuickItem or its children. diff --git a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h index 35d3edecb..1955413b2 100644 --- a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h +++ b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h @@ -40,7 +40,7 @@ #ifndef PYSIDE_QUICK_REGISTER_TYPE_H #define PYSIDE_QUICK_REGISTER_TYPE_H -#include <Python.h> +#include <sbkpython.h> struct SbkObjectType; diff --git a/sources/pyside2/PySide2/QtScript/typesystem_script.xml b/sources/pyside2/PySide2/QtScript/typesystem_script.xml index ccb2e3ab7..dc089a300 100644 --- a/sources/pyside2/PySide2/QtScript/typesystem_script.xml +++ b/sources/pyside2/PySide2/QtScript/typesystem_script.xml @@ -84,11 +84,12 @@ <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> if (%CPPSELF.isVariant() || %CPPSELF.isString()) { - QString format = QString().sprintf("%s(\"%s\")", ((PyObject*)%PYSELF)->ob_type->tp_name, qPrintable(%CPPSELF.toString())); + QString format = QString().sprintf("%s(\"%s\")", + PepType(Py_TYPE(%PYSELF))->tp_name, + qPrintable(%CPPSELF.toString())); %PYARG_0 = Shiboken::String::fromCString(qPrintable(format)); } else { - %PYARG_0 = Shiboken::String::fromCString( - ((PyObject* )%PYSELF)->ob_type->tp_name); + %PYARG_0 = Shiboken::String::fromCString(PepType(Py_TYPE(%PYSELF))->tp_name); } </inject-code> </add-function> diff --git a/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp b/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp index 8a4b7e628..4e9c8c3b7 100644 --- a/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp +++ b/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp @@ -50,7 +50,11 @@ inline PyObject* addActionWithPyObject(QMenu* self, const QIcon& icon, const QSt self->addAction(act); PyObject* pyAct = %CONVERTTOPYTHON[QAction*](act); - Shiboken::AutoDecRef result(PyObject_CallMethod(pyAct, "connect", "OsO", pyAct, SIGNAL(triggered()), callback)); + Shiboken::AutoDecRef result(PyObject_CallMethod(pyAct, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + pyAct, + SIGNAL(triggered()), callback)); if (result.isNull()) { Py_DECREF(pyAct); return 0; diff --git a/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp b/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp index fdd621128..8cdbc2e01 100644 --- a/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp +++ b/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp @@ -45,7 +45,10 @@ addActionWithPyObject(QMenuBar* self, const QString& text, PyObject* callback) self->addAction(act); PyObject* pyAct = %CONVERTTOPYTHON[QAction*](act); - PyObject* result = PyObject_CallMethod(pyAct, "connect", "OsO", pyAct, + PyObject* result = PyObject_CallMethod(pyAct, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + pyAct, SIGNAL(triggered(bool)), callback); if (result == 0 || result == Py_False) { diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml index b4a6c2453..11e6a9f7a 100644 --- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml +++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml @@ -269,7 +269,7 @@ <enum-type name="PanelModality" since="4.6"/> <inject-code class="target" position="end"> PyObject *userTypeConstant = PyInt_FromLong(QGraphicsItem::UserType); - PyDict_SetItemString(Sbk_QGraphicsItem_Type.super.ht_type.tp_dict, "UserType", userTypeConstant); + PyDict_SetItemString(PepType(Sbk_QGraphicsItem_TypeF())->tp_dict, "UserType", userTypeConstant); </inject-code> <modify-function signature="setParentItem(QGraphicsItem*)"> <modify-argument index="this"> @@ -1022,7 +1022,11 @@ %0 = new %TYPE(%1, %2); </inject-code> <inject-code class="target" position="end"> - Shiboken::AutoDecRef result(PyObject_CallMethod(%PYSELF, "connect", "OsO", %PYSELF, SIGNAL(activated()), %PYARG_3)); + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYSELF, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + %PYSELF, SIGNAL(activated()), %PYARG_3) + ); if (!result.isNull()) Shiboken::Object::setParent(%PYARG_2, %PYSELF); </inject-code> @@ -3029,7 +3033,11 @@ <inject-code> QAction *action = %CPPSELF.addAction(%1, %2); %PYARG_0 = %CONVERTTOPYTHON[QAction*](action); - Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, "connect", "OsO", %PYARG_0, SIGNAL(triggered()), %PYARG_3)); + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + %PYARG_0, SIGNAL(triggered()), %PYARG_3) + ); </inject-code> </modify-function> <modify-function signature="addAction(QString,const QObject*,const char*)"> @@ -3045,7 +3053,11 @@ <inject-code> QAction *action = %CPPSELF.addAction(%1); %PYARG_0 = %CONVERTTOPYTHON[QAction*](action); - Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, "connect", "OsO", %PYARG_0, SIGNAL(triggered()), %PYARG_2)); + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + %PYARG_0, SIGNAL(triggered()), %PYARG_2) + ); </inject-code> </modify-function> <modify-function signature="addAction(const QString&)"> diff --git a/sources/pyside2/PySide2/typesystem_templates.xml b/sources/pyside2/PySide2/typesystem_templates.xml index 798d02ddb..103d773cf 100644 --- a/sources/pyside2/PySide2/typesystem_templates.xml +++ b/sources/pyside2/PySide2/typesystem_templates.xml @@ -314,11 +314,12 @@ <!-- templates for __repr__ --> <template name="repr_code"> - QString format = QString().sprintf("%s(%REPR_FORMAT)", ((PyObject*)%PYSELF)->ob_type->tp_name, %REPR_ARGS); + QString format = QString().sprintf("%s(%REPR_FORMAT)", + PepType(Py_TYPE(%PYSELF))->tp_name, %REPR_ARGS); %PYARG_0 = Shiboken::String::fromCString(qPrintable(format)); </template> <template name="repr_code_matrix"> - QString format= QString("%1((").arg(((PyObject*)%PYSELF)->ob_type->tp_name); + QString format= QString("%1((").arg(PepType(Py_TYPE(%PYSELF))->tp_name); QList< %MATRIX_TYPE > cppArgs; %MATRIX_TYPE data[%MATRIX_SIZE]; diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp index 63b52744f..5b426ae8e 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp @@ -388,7 +388,7 @@ DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* ba d.relatedMetaObjects = NULL; d.static_metacall = NULL; - m_d->m_className = QByteArray(type->tp_name).split('.').last(); + m_d->m_className = QByteArray(PepType(type)->tp_name).split('.').last(); m_d->m_methodOffset = base->methodCount() - 1; m_d->m_propertyOffset = base->propertyCount() - 1; parsePythonType(type); @@ -591,14 +591,14 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // This enforces registering of all signals and slots at type parsing time, and not later at // signal connection time, thus making sure no method indices change which would break // existing connections. - const PyObject *mro = type->tp_mro; + const PyObject *mro = PepType(type)->tp_mro; const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro); PyTypeObject *qObjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); QVector<PyTypeObject *> basesToCheck; for (Py_ssize_t i = 0; i < basesCount; ++i) { PyTypeObject *baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); if (PyType_IsSubtype(baseType, qObjectType) - || baseType == reinterpret_cast<PyTypeObject *>(&SbkObject_Type) + || baseType == reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()) || baseType == reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type)) { continue; } else { @@ -611,7 +611,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // PYSIDE-315: Handle all signals first, in all involved types. for (int baseIndex = 0, baseEnd = basesToCheck.size(); baseIndex < baseEnd; ++baseIndex) { PyTypeObject *baseType = basesToCheck[baseIndex]; - PyObject *attrs = baseType->tp_dict; + PyObject *attrs = PepType(baseType)->tp_dict; PyObject *key = 0; PyObject *value = 0; Py_ssize_t pos = 0; @@ -643,7 +643,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // We check for this using "is_sorted()". Sorting no longer happens at all. for (int baseIndex = 0, baseEnd = basesToCheck.size(); baseIndex < baseEnd; ++baseIndex) { PyTypeObject *baseType = basesToCheck[baseIndex]; - PyObject *attrs = baseType->tp_dict; + PyObject *attrs = PepType(baseType)->tp_dict; PyObject *key = 0; PyObject *value = 0; Py_ssize_t pos = 0; diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h index af860fe1d..880719d6f 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.h +++ b/sources/pyside2/libpyside/globalreceiverv2.h @@ -140,7 +140,6 @@ private: DynamicQMetaObject m_metaObject; DynamicSlotDataV2 *m_data; QList<const QObject*> m_refs; - int m_ref; SharedMap m_sharedMap; }; diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 6bdaf65f2..15be38760 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -265,7 +265,7 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam } //mutate native signals to signal instance type - if (attr && PyObject_TypeCheck(attr, &PySideSignalType)) { + if (attr && PyObject_TypeCheck(attr, PySideSignalTypeF())) { PyObject* signal = reinterpret_cast<PyObject*>(Signal::initialize(reinterpret_cast<PySideSignal*>(attr), name, self)); PyObject_SetAttr(self, name, reinterpret_cast<PyObject*>(signal)); return signal; @@ -309,10 +309,10 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam bool inherits(PyTypeObject* objType, const char* class_name) { - if (strcmp(objType->tp_name, class_name) == 0) + if (strcmp(PepType(objType)->tp_name, class_name) == 0) return true; - PyTypeObject* base = (objType)->tp_base; + PyTypeObject* base = PepType(objType)->tp_base; if (base == 0) return false; @@ -400,7 +400,7 @@ QString pyStringToQString(PyObject *str) { #ifdef IS_PY3K if (PyUnicode_Check(str)) { - const char *unicodeBuffer = _PyUnicode_AsString(str); + const char *unicodeBuffer = _PepUnicode_AsString(str); if (unicodeBuffer) return QString::fromUtf8(unicodeBuffer); } diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp index c5e0b5484..5e0ffed39 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.cpp +++ b/sources/pyside2/libpyside/pysideclassinfo.cpp @@ -55,55 +55,30 @@ static int classInfoTpInit(PyObject*, PyObject*, PyObject*); static void classInfoFree(void*); static PyObject* classCall(PyObject*, PyObject*, PyObject*); -PyTypeObject PySideClassInfoType = { - PyVarObject_HEAD_INIT(0, 0) - "PySide2.QtCore." CLASSINFO_CLASS_NAME, /*tp_name*/ - sizeof(PySideClassInfo), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - classCall, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - classInfoTpInit, /*tp_init */ - 0, /*tp_alloc */ - classInfoTpNew, /*tp_new */ - classInfoFree, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ - 0, /*tp_version_tag */ +static PyType_Slot PySideClassInfoType_slots[] = { + {Py_tp_call, (void *)classCall}, + {Py_tp_init, (void *)classInfoTpInit}, + {Py_tp_new, (void *)classInfoTpNew}, + {Py_tp_free, (void *)classInfoFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PySideClassInfoType_spec = { + "PySide2.QtCore." CLASSINFO_CLASS_NAME, + sizeof(PySideClassInfo), + 0, + Py_TPFLAGS_DEFAULT, + PySideClassInfoType_slots, +}; + + +PyTypeObject *PySideClassInfoTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySideClassInfoType_spec); + return type; +} PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) { @@ -152,7 +127,7 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */) { - PySideClassInfo* me = reinterpret_cast<PySideClassInfo*>(subtype->tp_alloc(subtype, 0)); + PySideClassInfo* me = reinterpret_cast<PySideClassInfo*>(PepType(subtype)->tp_alloc(subtype, 0)); me->d = new PySideClassInfoPrivate; me->d->m_alreadyWrapped = false; @@ -195,7 +170,7 @@ void classInfoFree(void *self) PySideClassInfo* data = reinterpret_cast<PySideClassInfo*>(self); delete data->d; - pySelf->ob_type->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } @@ -206,17 +181,17 @@ namespace PySide { namespace ClassInfo { void init(PyObject* module) { - if (PyType_Ready(&PySideClassInfoType) < 0) + if (PyType_Ready(PySideClassInfoTypeF()) < 0) return; - Py_INCREF(&PySideClassInfoType); - PyModule_AddObject(module, CLASSINFO_CLASS_NAME, reinterpret_cast<PyObject *>(&PySideClassInfoType)); + Py_INCREF(PySideClassInfoTypeF()); + PyModule_AddObject(module, CLASSINFO_CLASS_NAME, reinterpret_cast<PyObject *>(PySideClassInfoTypeF())); } bool checkType(PyObject* pyObj) { if (pyObj) - return PyType_IsSubtype(pyObj->ob_type, &PySideClassInfoType); + return PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfoTypeF()); return false; } diff --git a/sources/pyside2/libpyside/pysideclassinfo.h b/sources/pyside2/libpyside/pysideclassinfo.h index 91e014715..910dd9f82 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.h +++ b/sources/pyside2/libpyside/pysideclassinfo.h @@ -47,7 +47,7 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySideClassInfoType; + extern PYSIDE_API PyTypeObject *PySideClassInfoTypeF(void); struct PySideClassInfoPrivate; struct PYSIDE_API PySideClassInfo diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp index a0f4b0561..9839a1098 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.cpp +++ b/sources/pyside2/libpyside/pysidemetafunction.cpp @@ -58,55 +58,29 @@ struct PySideMetaFunctionPrivate static void functionFree(void*); static PyObject* functionCall(PyObject*, PyObject*, PyObject*); -PyTypeObject PySideMetaFunctionType = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "PySide.MetaFunction", - /*tp_basicsize*/ sizeof(PySideMetaFunction), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ functionCall, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ "MetaFunction", - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ PyType_GenericNew, - /*tp_free*/ functionFree, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +static PyType_Slot PySideMetaFunctionType_slots[] = { + {Py_tp_call, (void *)functionCall}, + {Py_tp_new, (void *)PyType_GenericNew}, + {Py_tp_free, (void *)functionFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PySideMetaFunctionType_spec = { + "PySide.MetaFunction", + sizeof(PySideMetaFunction), + 0, + Py_TPFLAGS_DEFAULT, + PySideMetaFunctionType_slots, +}; + + +PyTypeObject *PySideMetaFunctionTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySideMetaFunctionType_spec); + return type; +} void functionFree(void *self) { @@ -130,10 +104,10 @@ namespace PySide { namespace MetaFunction { void init(PyObject* module) { - if (PyType_Ready(&PySideMetaFunctionType) < 0) + if (PyType_Ready(PySideMetaFunctionTypeF()) < 0) return; - PyModule_AddObject(module, "MetaFunction", reinterpret_cast<PyObject *>(&PySideMetaFunctionType)); + PyModule_AddObject(module, "MetaFunction", reinterpret_cast<PyObject *>(PySideMetaFunctionTypeF())); } PySideMetaFunction* newObject(QObject* source, int methodIndex) @@ -144,7 +118,7 @@ PySideMetaFunction* newObject(QObject* source, int methodIndex) QMetaMethod method = source->metaObject()->method(methodIndex); if ((method.methodType() == QMetaMethod::Slot) || (method.methodType() == QMetaMethod::Method)) { - PySideMetaFunction* function = PyObject_New(PySideMetaFunction, &PySideMetaFunctionType); + PySideMetaFunction* function = PyObject_New(PySideMetaFunction, PySideMetaFunctionTypeF()); function->d = new PySideMetaFunctionPrivate(); function->d->qobject = source; function->d->methodIndex = methodIndex; diff --git a/sources/pyside2/libpyside/pysidemetafunction.h b/sources/pyside2/libpyside/pysidemetafunction.h index 9a4072dec..020f02d49 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.h +++ b/sources/pyside2/libpyside/pysidemetafunction.h @@ -49,7 +49,7 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySideMetaFunctionType; + extern PYSIDE_API PyTypeObject *PySideMetaFunctionTypeF(void); struct PySideMetaFunctionPrivate; struct PYSIDE_API PySideMetaFunction diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp index de85686ce..ccec8a2cb 100644 --- a/sources/pyside2/libpyside/pysideproperty.cpp +++ b/sources/pyside2/libpyside/pysideproperty.cpp @@ -72,55 +72,33 @@ static PyMethodDef PySidePropertyMethods[] = { {0, 0, 0, 0} }; -PyTypeObject PySidePropertyType = { - PyVarObject_HEAD_INIT(0, 0) - QPROPERTY_CLASS_NAME, /*tp_name*/ - sizeof(PySideProperty), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - qpropertyDeAlloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - qPropertyCall, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc */ - qpropertyTraverse, /*tp_traverse */ - qpropertyClear, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - PySidePropertyMethods, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - qpropertyTpInit, /*tp_init */ - 0, /*tp_alloc */ - qpropertyTpNew, /*tp_new */ - 0, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ - 0 /*tp_version_tag */ +static PyType_Slot PySidePropertyType_slots[] = { + {Py_tp_dealloc, (void *)qpropertyDeAlloc}, + {Py_tp_call, (void *)qPropertyCall}, + {Py_tp_traverse, (void *)qpropertyTraverse}, + {Py_tp_clear, (void *)qpropertyClear}, + {Py_tp_methods, (void *)PySidePropertyMethods}, + {Py_tp_init, (void *)qpropertyTpInit}, + {Py_tp_new, (void *)qpropertyTpNew}, + {0, 0} }; +// Dotted modulename is crucial for PyType_FromSpec to work. Is this name right? +static PyType_Spec PySidePropertyType_spec = { + "PySide2.QtCore." QPROPERTY_CLASS_NAME, + sizeof(PySideProperty), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, + PySidePropertyType_slots, +}; + + +PyTypeObject *PySidePropertyTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySidePropertyType_spec); + return type; +} static void qpropertyMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args) { @@ -174,7 +152,7 @@ static void qpropertyMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::C static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */) { - PySideProperty* me = reinterpret_cast<PySideProperty*>(subtype->tp_alloc(subtype, 0)); + PySideProperty* me = reinterpret_cast<PySideProperty*>(PepType(subtype)->tp_alloc(subtype, 0)); me->d = new PySidePropertyPrivate; memset(me->d, 0, sizeof(PySidePropertyPrivate)); PySidePropertyPrivate* pData = me->d; @@ -232,7 +210,7 @@ int qpropertyTpInit(PyObject* self, PyObject* args, PyObject* kwds) void qpropertyDeAlloc(PyObject* self) { qpropertyClear(self); - Py_TYPE(self)->tp_free(self); + PepType(Py_TYPE(self))->tp_free(self); } PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */) @@ -329,9 +307,9 @@ namespace { static PyObject* getFromType(PyTypeObject* type, PyObject* name) { PyObject* attr = 0; - attr = PyDict_GetItem(type->tp_dict, name); + attr = PyDict_GetItem(PepType(type)->tp_dict, name); if (!attr) { - PyObject* bases = type->tp_bases; + PyObject* bases = PepType(type)->tp_bases; int size = PyTuple_GET_SIZE(bases); for(int i=0; i < size; i++) { PyObject* base = PyTuple_GET_ITEM(bases, i); @@ -350,17 +328,17 @@ namespace PySide { namespace Property { void init(PyObject* module) { - if (PyType_Ready(&PySidePropertyType) < 0) + if (PyType_Ready(PySidePropertyTypeF()) < 0) return; - Py_INCREF(&PySidePropertyType); - PyModule_AddObject(module, QPROPERTY_CLASS_NAME, reinterpret_cast<PyObject *>(&PySidePropertyType)); + Py_INCREF(PySidePropertyTypeF()); + PyModule_AddObject(module, QPROPERTY_CLASS_NAME, reinterpret_cast<PyObject *>(PySidePropertyTypeF())); } bool checkType(PyObject* pyObj) { if (pyObj) { - return PyType_IsSubtype(pyObj->ob_type, &PySidePropertyType); + return PyType_IsSubtype(Py_TYPE(pyObj), PySidePropertyTypeF()); } return false; } @@ -427,7 +405,7 @@ PySideProperty* getObject(PyObject* source, PyObject* name) attr = PyDict_GetItem(dict, name); } - attr = getFromType(source->ob_type, name); + attr = getFromType(Py_TYPE(source), name); if (attr && checkType(attr)) { Py_INCREF(attr); return reinterpret_cast<PySideProperty*>(attr); diff --git a/sources/pyside2/libpyside/pysideproperty.h b/sources/pyside2/libpyside/pysideproperty.h index d8cafc6c2..d77416abe 100644 --- a/sources/pyside2/libpyside/pysideproperty.h +++ b/sources/pyside2/libpyside/pysideproperty.h @@ -46,7 +46,7 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySidePropertyType; + extern PYSIDE_API PyTypeObject *PySidePropertyTypeF(void); struct PySidePropertyPrivate; struct PYSIDE_API PySideProperty diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp index d38069850..11db70bb5 100644 --- a/sources/pyside2/libpyside/pysideqflags.cpp +++ b/sources/pyside2/libpyside/pysideqflags.cpp @@ -44,14 +44,17 @@ extern "C" { struct SbkConverter; + struct PySideQFlagsTypePrivate + { + SbkConverter** converterPtr; + SbkConverter* converter; + }; /** * Type of all QFlags */ struct PySideQFlagsType { - PyHeapTypeObject super; - SbkConverter** converterPtr; - SbkConverter* converter; + PepTypeObject type; }; #define PYSIDE_QFLAGS(X) reinterpret_cast<PySideQFlagsObject*>(X) @@ -131,20 +134,61 @@ namespace PySide { namespace QFlags { - PyTypeObject* create(const char* name, PyNumberMethods* numberMethods) + static PyType_Slot SbkNewQFlagsType_slots[] = { +#ifdef IS_PY3K + {Py_nb_bool, 0}, +#else + {Py_nb_nonzero, 0}, + {Py_nb_long, 0}, +#endif + {Py_nb_invert, 0}, + {Py_nb_and, 0}, + {Py_nb_xor, 0}, + {Py_nb_or, 0}, + {Py_nb_int, 0}, +#ifndef IS_PY3K + {Py_nb_long, 0}, +#endif + {Py_tp_new, (void *)PySideQFlagsNew}, + {Py_tp_richcompare, (void *)PySideQFlagsRichCompare}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} + }; + static PyType_Spec SbkNewQFlagsType_spec = { + "missing QFlags name", // to be inserted later + sizeof(PySideQFlagsObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, + SbkNewQFlagsType_slots, + }; + + PyTypeObject *create(const char* name, PyType_Slot numberMethods[]) { - PyTypeObject* type = reinterpret_cast<PyTypeObject*>(new PySideQFlagsType); - ::memset(type, 0, sizeof(PySideQFlagsType)); + char qualname[200]; + strcpy(qualname, "PySide2.libpyside."); + strcat(qualname, name); + // Careful: PyType_FromSpec does not allocate the string. + PyType_Spec *newspec = new PyType_Spec; + newspec->name = strdup(qualname); + newspec->basicsize = SbkNewQFlagsType_spec.basicsize; + newspec->itemsize = SbkNewQFlagsType_spec.itemsize; + newspec->flags = SbkNewQFlagsType_spec.flags; + int idx = -1; +#ifdef IS_PY3K +# define SLOT slot +#else +# define SLOT slot_ +#endif + while (numberMethods[++idx].SLOT) { + assert(SbkNewQFlagsType_slots[idx].SLOT == numberMethods[idx].SLOT); + SbkNewQFlagsType_slots[idx].pfunc = numberMethods[idx].pfunc; + } + newspec->slots = SbkNewQFlagsType_spec.slots; + PyTypeObject *type = (PyTypeObject *)PyType_FromSpec(newspec); Py_TYPE(type) = &PyType_Type; - type->tp_basicsize = sizeof(PySideQFlagsObject); - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES; - type->tp_name = name; - type->tp_new = &PySideQFlagsNew; - type->tp_as_number = numberMethods; - type->tp_richcompare = &PySideQFlagsRichCompare; PySideQFlagsType* flagsType = reinterpret_cast<PySideQFlagsType*>(type); - flagsType->converterPtr = &flagsType->converter; + PepType_PFTP(flagsType)->converterPtr = &PepType_PFTP(flagsType)->converter; if (PyType_Ready(type) < 0) return 0; diff --git a/sources/pyside2/libpyside/pysideqflags.h b/sources/pyside2/libpyside/pysideqflags.h index e0598798d..71f30808d 100644 --- a/sources/pyside2/libpyside/pysideqflags.h +++ b/sources/pyside2/libpyside/pysideqflags.h @@ -63,7 +63,7 @@ namespace QFlags /** * Creates a new QFlags type. */ - PYSIDE_API PyTypeObject* create(const char* name, PyNumberMethods* numberMethods); + PYSIDE_API PyTypeObject *create(const char* name, PyType_Slot *numberMethods); /** * Creates a new QFlags instance of type \p type and value \p value. */ diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp index 76ef65b5e..483e9e050 100644 --- a/sources/pyside2/libpyside/pysidesignal.cpp +++ b/sources/pyside2/libpyside/pysidesignal.cpp @@ -93,117 +93,73 @@ static PyObject* signalCall(PyObject*, PyObject*, PyObject*); static PyObject* metaSignalCheck(PyObject*, PyObject*); -static PyMappingMethods Signal_as_mapping = { - 0, - signalGetItem, - 0 -}; static PyMethodDef Signal_methods[] = { {"__instancecheck__", (PyCFunction)metaSignalCheck, METH_O, NULL}, {0, 0, 0, 0} }; -PyTypeObject PySideSignalMetaType = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "PySide2.QtCore.MetaSignal", - /*tp_basicsize*/ sizeof(PyTypeObject), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ Signal_methods, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ 0, - /*tp_free*/ 0, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +static PyType_Slot PySideSignalMetaType_slots[] = { + {Py_tp_methods, (void *)Signal_methods}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideSignalMetaType_spec = { + "PySide2.QtCore.MetaSignal", + 0, + // sizeof(PyHeapTypeObject) is filled in by PyType_FromSpecWithBases + // which calls PyType_Ready which calls inherit_special. + 0, + Py_TPFLAGS_DEFAULT, + PySideSignalMetaType_slots, }; -PyTypeObject PySideSignalType = { - PyVarObject_HEAD_INIT(&PySideSignalMetaType, 0) - /*tp_name*/ "PySide2.QtCore." SIGNAL_CLASS_NAME, - /*tp_basicsize*/ sizeof(PySideSignal), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ &Signal_as_mapping, - /*tp_hash*/ 0, - /*tp_call*/ signalCall, - /*tp_str*/ signalToString, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ SIGNAL_CLASS_NAME, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ signalTpInit, - /*tp_alloc*/ 0, - /*tp_new*/ PyType_GenericNew, - /*tp_free*/ signalFree, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 + +PyTypeObject *PySideSignalMetaTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + PyObject *bases = Py_BuildValue("(O)", &PyType_Type); + type = (PyTypeObject *)PyType_FromSpecWithBases(&PySideSignalMetaType_spec, bases); + Py_XDECREF(bases); + } + return type; +} + +static PyType_Slot PySideSignalType_slots[] = { + {Py_mp_subscript, (void *)signalGetItem}, + {Py_tp_call, (void *)signalCall}, + {Py_tp_str, (void *)signalToString}, + {Py_tp_init, (void *)signalTpInit}, + {Py_tp_new, (void *)PyType_GenericNew}, + {Py_tp_free, (void *)signalFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideSignalType_spec = { + "PySide2.QtCore." SIGNAL_CLASS_NAME, + sizeof(PySideSignal), + 0, + Py_TPFLAGS_DEFAULT, + PySideSignalType_slots, }; + +PyTypeObject *PySideSignalTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + type = (PyTypeObject *)PyType_FromSpec(&PySideSignalType_spec); + PyTypeObject *hold = Py_TYPE(type); + Py_TYPE(type) = PySideSignalMetaTypeF(); + Py_INCREF(Py_TYPE(type)); + Py_DECREF(hold); + } + return type; +} + static PyMethodDef SignalInstance_methods[] = { {"connect", (PyCFunction)signalInstanceConnect, METH_VARARGS|METH_KEYWORDS, 0}, {"disconnect", signalInstanceDisconnect, METH_VARARGS, 0}, @@ -211,61 +167,31 @@ static PyMethodDef SignalInstance_methods[] = { {0, 0, 0, 0} /* Sentinel */ }; -static PyMappingMethods SignalInstance_as_mapping = { +static PyType_Slot PySideSignalInstanceType_slots[] = { + //{Py_tp_as_mapping, (void *)&SignalInstance_as_mapping}, + {Py_mp_subscript, (void *)signalInstanceGetItem}, + {Py_tp_call, (void *)signalInstanceCall}, + {Py_tp_methods, (void *)SignalInstance_methods}, + {Py_tp_new, (void *)PyType_GenericNew}, + {Py_tp_free, (void *)signalInstanceFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideSignalInstanceType_spec = { + "PySide2.QtCore." SIGNAL_INSTANCE_NAME, + sizeof(PySideSignalInstance), 0, - signalInstanceGetItem, - 0 + Py_TPFLAGS_DEFAULT, + PySideSignalInstanceType_slots, }; -PyTypeObject PySideSignalInstanceType = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "PySide2.QtCore." SIGNAL_INSTANCE_NAME, - /*tp_basicsize*/ sizeof(PySideSignalInstance), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ &SignalInstance_as_mapping, - /*tp_hash*/ 0, - /*tp_call*/ signalInstanceCall, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ SIGNAL_INSTANCE_NAME, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ SignalInstance_methods, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ PyType_GenericNew, - /*tp_free*/ signalInstanceFree, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}; + +PyTypeObject *PySideSignalInstanceTypeF(void) +{ + static PyTypeObject *type = + (PyTypeObject *)PyType_FromSpec(&PySideSignalInstanceType_spec); + return type; +} int signalTpInit(PyObject* self, PyObject* args, PyObject* kwds) { @@ -327,7 +253,7 @@ void signalFree(void* self) Py_XDECREF(data->homonymousMethod); data->homonymousMethod = 0; - pySelf->ob_type->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } PyObject* signalGetItem(PyObject* self, PyObject* key) @@ -372,7 +298,7 @@ void signalInstanceFree(void* self) } delete dataPvt; data->d = 0; - pySelf->ob_type->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) @@ -389,7 +315,7 @@ PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) Shiboken::AutoDecRef pyArgs(PyList_New(0)); bool match = false; - if (slot->ob_type == &PySideSignalInstanceType) { + if (Py_TYPE(slot) == PySideSignalInstanceTypeF()) { PySideSignalInstance* sourceWalk = source; PySideSignalInstance* targetWalk; @@ -427,9 +353,9 @@ PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) PyObject *function = isMethod ? PyMethod_GET_FUNCTION(slot) : slot; PyCodeObject *objCode = reinterpret_cast<PyCodeObject *>(PyFunction_GET_CODE(function)); PyFunctionObject *function_obj = reinterpret_cast<PyFunctionObject *>(function); - functionName = Shiboken::String::toCString(function_obj->func_name); + functionName = Shiboken::String::toCString(PepFunction_GetName(function_obj)); useSelf = isMethod; - slotArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount; + slotArgs = PepCode_GET_FLAGS(objCode) & CO_VARARGS ? -1 : PepCode_GET_ARGCOUNT(objCode); if (useSelf) slotArgs -= 1; @@ -574,7 +500,7 @@ PyObject* signalInstanceDisconnect(PyObject* self, PyObject* args) slot = Py_None; bool match = false; - if (slot->ob_type == &PySideSignalInstanceType) { + if (Py_TYPE(slot) == PySideSignalInstanceTypeF()) { PySideSignalInstance* target = reinterpret_cast<PySideSignalInstance*>(slot); if (QMetaObject::checkConnectArgs(source->d->signature, target->d->signature)) { PyList_Append(pyArgs, source->d->source); @@ -626,7 +552,7 @@ PyObject* signalCall(PyObject* self, PyObject* args, PyObject* kw) return 0; } - descrgetfunc getDescriptor = signal->homonymousMethod->ob_type->tp_descr_get; + descrgetfunc getDescriptor = PepType(Py_TYPE(signal->homonymousMethod))->tp_descr_get; // Check if there exists a method with the same name as the signal, which is also a static // method in C++ land. @@ -637,7 +563,7 @@ PyObject* signalCall(PyObject* self, PyObject* args, PyObject* kw) } // Assumes homonymousMethod is not a static method. - ternaryfunc callFunc = signal->homonymousMethod->ob_type->tp_call; + ternaryfunc callFunc = PepType(Py_TYPE(signal->homonymousMethod))->tp_call; return callFunc(homonymousMethod, args, kw); } @@ -649,14 +575,14 @@ PyObject* signalInstanceCall(PyObject* self, PyObject* args, PyObject* kw) return 0; } - descrgetfunc getDescriptor = PySideSignal->d->homonymousMethod->ob_type->tp_descr_get; + descrgetfunc getDescriptor = PepType(Py_TYPE(PySideSignal->d->homonymousMethod))->tp_descr_get; Shiboken::AutoDecRef homonymousMethod(getDescriptor(PySideSignal->d->homonymousMethod, PySideSignal->d->source, 0)); return PyCFunction_Call(homonymousMethod, args, kw); } static PyObject *metaSignalCheck(PyObject * /* klass */, PyObject* args) { - if (PyType_IsSubtype(args->ob_type, &PySideSignalInstanceType)) + if (PyType_IsSubtype(Py_TYPE(args), PySideSignalInstanceTypeF())) Py_RETURN_TRUE; else Py_RETURN_FALSE; @@ -669,25 +595,25 @@ namespace Signal { void init(PyObject* module) { - if (PyType_Ready(&PySideSignalMetaType) < 0) + if (PyType_Ready(PySideSignalMetaTypeF()) < 0) return; - if (PyType_Ready(&PySideSignalType) < 0) + if (PyType_Ready(PySideSignalTypeF()) < 0) return; - Py_INCREF(&PySideSignalType); - PyModule_AddObject(module, SIGNAL_CLASS_NAME, reinterpret_cast<PyObject *>(&PySideSignalType)); + Py_INCREF(PySideSignalTypeF()); + PyModule_AddObject(module, SIGNAL_CLASS_NAME, reinterpret_cast<PyObject *>(PySideSignalTypeF())); - if (PyType_Ready(&PySideSignalInstanceType) < 0) + if (PyType_Ready(PySideSignalInstanceTypeF()) < 0) return; - Py_INCREF(&PySideSignalInstanceType); + Py_INCREF(PySideSignalInstanceTypeF()); } bool checkType(PyObject* pyObj) { if (pyObj) - return PyType_IsSubtype(pyObj->ob_type, &PySideSignalType); + return PyType_IsSubtype(Py_TYPE(pyObj), PySideSignalTypeF()); return false; } @@ -699,9 +625,9 @@ void updateSourceObject(PyObject* source) PyObject* value; PyObject* key; - while (PyDict_Next(objType->tp_dict, &pos, &key, &value)) { - if (PyObject_TypeCheck(value, &PySideSignalType)) { - Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject *>(PyObject_New(PySideSignalInstance, &PySideSignalInstanceType))); + while (PyDict_Next(PepType(objType)->tp_dict, &pos, &key, &value)) { + if (PyObject_TypeCheck(value, PySideSignalTypeF())) { + Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject *>(PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()))); instanceInitialize(signalInstance.cast<PySideSignalInstance*>(), key, reinterpret_cast<PySideSignal*>(value), source, 0); PyObject_SetAttr(source, key, signalInstance); } @@ -714,7 +640,8 @@ char* getTypeName(PyObject* type) { if (PyType_Check(type)) { char* typeName = NULL; - if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type), reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type), + reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { SbkObjectType* objType = reinterpret_cast<SbkObjectType*>(type); typeName = strdup(Shiboken::ObjectType::getOriginalName(objType)); } else { @@ -730,7 +657,7 @@ char* getTypeName(PyObject* type) typeName = strdup("double"); else if (objType == &PyBool_Type) typeName = strdup("bool"); - else if (Py_TYPE(objType) == &SbkEnumType_Type) + else if (Py_TYPE(objType) == SbkEnumType_TypeF()) typeName = strdup(Shiboken::Enum::getCppName(objType)); else typeName = strdup("PyObject"); @@ -763,7 +690,7 @@ char* parseSignature(PyObject* args) return getTypeName(args); for (Py_ssize_t i = 0, i_max = PySequence_Size(args); i < i_max; i++) { - Shiboken::AutoDecRef arg(PySequence_ITEM(args, i)); + Shiboken::AutoDecRef arg(PySequence_GetItem(args, i)); char* typeName = getTypeName(arg); if (typeName) { if (signature) { @@ -796,7 +723,7 @@ void appendSignature(PySideSignal* self, const SignalSignature &signature) PySideSignalInstance* initialize(PySideSignal* self, PyObject* name, PyObject* object) { - PySideSignalInstance* instance = PyObject_New(PySideSignalInstance, &PySideSignalInstanceType); + PySideSignalInstance* instance = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); SbkObject* sbkObj = reinterpret_cast<SbkObject*>(object); if (!Shiboken::Object::wasCreatedByPython(sbkObj)) Py_INCREF(object); // PYSIDE-79: this flag was crucial for a wrapper call. @@ -827,7 +754,7 @@ void instanceInitialize(PySideSignalInstance* self, PyObject* name, PySideSignal index++; if (index < data->signaturesSize) { - selfPvt->next = PyObject_New(PySideSignalInstance, &PySideSignalInstanceType); + selfPvt->next = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); instanceInitialize(selfPvt->next, name, data, source, index); } } @@ -854,7 +781,7 @@ PySideSignalInstance* newObjectFromMethod(PyObject* source, const QList<QMetaMet PySideSignalInstance* root = 0; PySideSignalInstance* previous = 0; foreach (const QMetaMethod &m, methodList) { - PySideSignalInstance* item = PyObject_New(PySideSignalInstance, &PySideSignalInstanceType); + PySideSignalInstance* item = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); if (!root) root = item; @@ -881,7 +808,7 @@ PySideSignal* newObject(const char* name, ...) { va_list listSignatures; char* sig = 0; - PySideSignal* self = PyObject_New(PySideSignal, &PySideSignalType); + PySideSignal* self = PyObject_New(PySideSignal, PySideSignalTypeF()); self->signalName = strdup(name); self->signaturesSize = 0; self->signatures = 0; @@ -928,7 +855,7 @@ static typename T::value_type join(T t, const char* sep) static void _addSignalToWrapper(SbkObjectType* wrapperType, const char* signalName, PySideSignal* signal) { - PyObject* typeDict = wrapperType->super.ht_type.tp_dict; + PyObject* typeDict = PepType(wrapperType)->tp_dict; PyObject* homonymousMethod; if ((homonymousMethod = PyDict_GetItemString(typeDict, signalName))) { Py_INCREF(homonymousMethod); @@ -964,7 +891,7 @@ void registerSignals(SbkObjectType* pyObj, const QMetaObject* metaObject) SignalSigMap::Iterator it = signalsFound.begin(); SignalSigMap::Iterator end = signalsFound.end(); for (; it != end; ++it) { - PySideSignal* self = PyObject_New(PySideSignal, &PySideSignalType); + PySideSignal* self = PyObject_New(PySideSignal, PySideSignalTypeF()); self->signalName = strdup(it.key().constData()); self->signaturesSize = 0; self->signatures = 0; @@ -1047,14 +974,14 @@ QString getCallbackSignature(const char* signal, QObject* receiver, PyObject* ca if (isMethod || isFunction) { PyObject* function = isMethod ? PyMethod_GET_FUNCTION(callback) : callback; PyCodeObject* objCode = reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(function)); - functionName = Shiboken::String::toCString(reinterpret_cast<PyFunctionObject*>(function)->func_name); + functionName = Shiboken::String::toCString(PepFunction_GetName(function)); useSelf = isMethod; - numArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount; + numArgs = PepCode_GET_FLAGS(objCode) & CO_VARARGS ? -1 : PepCode_GET_ARGCOUNT(objCode); } else if (PyCFunction_Check(callback)) { const PyCFunctionObject *funcObj = reinterpret_cast<const PyCFunctionObject *>(callback); - functionName = funcObj->m_ml->ml_name; - useSelf = funcObj->m_self; - const int flags = funcObj->m_ml->ml_flags; + functionName = PepCFunction_GET_NAMESTR(funcObj); + useSelf = PyCFunction_GET_SELF(funcObj); + const int flags = PyCFunction_GET_FLAGS(funcObj); if (receiver) { //Search for signature on metaobject diff --git a/sources/pyside2/libpyside/pysidesignal.h b/sources/pyside2/libpyside/pysidesignal.h index f5365098f..abbefbb1a 100644 --- a/sources/pyside2/libpyside/pysidesignal.h +++ b/sources/pyside2/libpyside/pysidesignal.h @@ -50,8 +50,8 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySideSignalType; - extern PYSIDE_API PyTypeObject PySideSignalInstanceType; + extern PYSIDE_API PyTypeObject *PySideSignalTypeF(void); + extern PYSIDE_API PyTypeObject *PySideSignalInstanceTypeF(void); // Internal object struct PYSIDE_API PySideSignal; diff --git a/sources/pyside2/libpyside/pysidesignal_p.h b/sources/pyside2/libpyside/pysidesignal_p.h index e2e28b3dd..24cbde505 100644 --- a/sources/pyside2/libpyside/pysidesignal_p.h +++ b/sources/pyside2/libpyside/pysidesignal_p.h @@ -44,7 +44,7 @@ extern "C" { - extern PyTypeObject PySideSignalType; + extern PyTypeObject *PySideSignalTypeF(void); struct PySideSignal { PyObject_HEAD diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp index 8f307260d..db1a7d9ed 100644 --- a/sources/pyside2/libpyside/pysideslot.cpp +++ b/sources/pyside2/libpyside/pysideslot.cpp @@ -62,55 +62,29 @@ static int slotTpInit(PyObject*, PyObject*, PyObject*); static PyObject* slotCall(PyObject*, PyObject*, PyObject*); // Class Definition ----------------------------------------------- -static PyTypeObject PySideSlotType = { - PyVarObject_HEAD_INIT(0, 0) - "PySide2.QtCore." SLOT_DEC_NAME, /*tp_name*/ - sizeof(PySideSlot), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - slotCall, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - SLOT_DEC_NAME, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - slotTpInit, /*tp_init */ - 0, /*tp_alloc */ - PyType_GenericNew, /*tp_new */ - 0, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ - 0 /*tp_version_tag*/ +static PyType_Slot PySideSlotType_slots[] = { + {Py_tp_call, (void *)slotCall}, + {Py_tp_init, (void *)slotTpInit}, + {Py_tp_new, (void *)PyType_GenericNew}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PySideSlotType_spec = { + "PySide2.QtCore." SLOT_DEC_NAME, + sizeof(PySideSlot), + 0, + Py_TPFLAGS_DEFAULT, + PySideSlotType_slots, +}; + + +static PyTypeObject *PySideSlotTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySideSlotType_spec); + return type; +} int slotTpInit(PyObject *self, PyObject *args, PyObject *kw) { @@ -139,7 +113,7 @@ int slotTpInit(PyObject *self, PyObject *args, PyObject *kw) data->args = typeName; } } else { - PyErr_Format(PyExc_TypeError, "Unknown signal argument type: %s", argType->ob_type->tp_name); + PyErr_Format(PyExc_TypeError, "Unknown signal argument type: %s", PepType((Py_TYPE(argType)))->tp_name); return -1; } } @@ -166,7 +140,7 @@ PyObject *slotCall(PyObject *self, PyObject *args, PyObject * /* kw */) PySideSlot *data = reinterpret_cast<PySideSlot*>(self); if (!data->slotName) { - PyObject *funcName = reinterpret_cast<PyFunctionObject*>(callback)->func_name; + PyObject *funcName = PepFunction_GetName(callback); data->slotName = strdup(Shiboken::String::toCString(funcName)); } @@ -209,11 +183,11 @@ namespace PySide { namespace Slot { void init(PyObject* module) { - if (PyType_Ready(&PySideSlotType) < 0) + if (PyType_Ready(PySideSlotTypeF()) < 0) return; - Py_INCREF(&PySideSlotType); - PyModule_AddObject(module, SLOT_DEC_NAME, reinterpret_cast<PyObject *>(&PySideSlotType)); + Py_INCREF(PySideSlotTypeF()); + PyModule_AddObject(module, SLOT_DEC_NAME, reinterpret_cast<PyObject *>(PySideSlotTypeF())); } } // namespace Slot diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index c31334ee5..906aafd7c 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -40,6 +40,7 @@ #include "pysideweakref.h" #include <sbkpython.h> +#include <shiboken.h> typedef struct { PyObject_HEAD @@ -50,56 +51,27 @@ typedef struct { static PyObject* CallableObject_call(PyObject* callable_object, PyObject* args, PyObject* kw); -static PyTypeObject PySideCallableObjectType = { - PyVarObject_HEAD_INIT(0, 0) +static PyType_Slot PySideCallableObjectType_slots[] = { + {Py_tp_call, (void *)CallableObject_call}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideCallableObjectType_spec = { const_cast<char*>("PySide.Callable"), - sizeof(PySideCallableObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - CallableObject_call, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0 /* tp_version_tag */ + sizeof(PySideCallableObject), + 0, + Py_TPFLAGS_DEFAULT, + PySideCallableObjectType_slots, }; + +static PyTypeObject *PySideCallableObjectTypeF(void) +{ + static PyTypeObject *type = + (PyTypeObject *)PyType_FromSpec(&PySideCallableObjectType_spec); + return type; +} + static PyObject *CallableObject_call(PyObject *callable_object, PyObject *args, PyObject * /* kw */) { PySideCallableObject* obj = reinterpret_cast<PySideCallableObject *>(callable_object); @@ -116,13 +88,13 @@ PyObject* create(PyObject* obj, PySideWeakRefFunction func, void* userData) if (obj == Py_None) return 0; - if (Py_TYPE(&PySideCallableObjectType) == 0) + if (Py_TYPE(PySideCallableObjectTypeF()) == 0) { - Py_TYPE(&PySideCallableObjectType) = &PyType_Type; - PyType_Ready(&PySideCallableObjectType); + Py_TYPE(PySideCallableObjectTypeF()) = &PyType_Type; + PyType_Ready(PySideCallableObjectTypeF()); } - PySideCallableObject* callable = PyObject_New(PySideCallableObject, &PySideCallableObjectType); + PySideCallableObject* callable = PyObject_New(PySideCallableObject, PySideCallableObjectTypeF()); if (!callable || PyErr_Occurred()) return 0; diff --git a/sources/pyside2/libpyside/signalmanager.cpp.in b/sources/pyside2/libpyside/signalmanager.cpp.in index 50f436134..c67bc6369 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp.in +++ b/sources/pyside2/libpyside/signalmanager.cpp.in @@ -590,7 +590,7 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa // Create a instance meta object if (!dict || !PyDict_Contains(dict, metaObjectAttr)) { - dmo = new DynamicQMetaObject(pySelf->ob_type, metaObject); + dmo = new DynamicQMetaObject(Py_TYPE(pySelf), metaObject); #ifdef IS_PY3K PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject); #else diff --git a/sources/pyside2/libpyside/signalmanager.h b/sources/pyside2/libpyside/signalmanager.h index 4f286745f..5948a7df1 100644 --- a/sources/pyside2/libpyside/signalmanager.h +++ b/sources/pyside2/libpyside/signalmanager.h @@ -61,7 +61,6 @@ public: PyObjectWrapper& operator=(const PyObjectWrapper &other); private: PyObject* m_me; - void* m_data; //future }; PYSIDE_API QDataStream &operator<<(QDataStream& out, const PyObjectWrapper& myObj); diff --git a/sources/pyside2/plugins/customwidget.cpp b/sources/pyside2/plugins/customwidget.cpp index c2ed00bd0..bad05f2d3 100644 --- a/sources/pyside2/plugins/customwidget.cpp +++ b/sources/pyside2/plugins/customwidget.cpp @@ -51,7 +51,7 @@ PyCustomWidget::PyCustomWidget(PyObject* objectType) : m_data(new PyCustomWidgetPrivate()) { m_data->pyObject = objectType; - m_name = QString(reinterpret_cast<PyTypeObject*>(objectType)->tp_name); + m_name = QString(PepType(reinterpret_cast<PyTypeObject*>(objectType))->tp_name); } PyCustomWidget::~PyCustomWidget() diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index ce582d21a..d76c788ec 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -2647,7 +2647,7 @@ bool AbstractMetaBuilderPrivate::isQObject(const FileModelItem &dom, const QStri classItem = ns->findClass(names.at(names.size() - 1)); } - if (classItem == nullptr) + if (!classItem) return false; if (classItem->extendsClass(QLatin1String("QObject"))) diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index 60ab7878f..5720ff554 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -335,18 +335,6 @@ if (SANITIZE_ADDRESS AND NOT MSVC) set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address") endif() -add_subdirectory(ApiExtractor) - -set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) - -# uninstall target -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) -add_custom_target(uninstall "${CMAKE_COMMAND}" - -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") - - # Detect if the python libs were compiled in debug mode # On Linux distros there is no standard way to check that. execute_process( @@ -390,13 +378,30 @@ execute_process( OUTPUT_VARIABLE PYTHON_WITH_COUNT_ALLOCS OUTPUT_STRIP_TRAILING_WHITESPACE) +# On Windows, PYTHON_LIBRARIES can be a list. Example: +# optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib +# On other platforms, this result is not used at all. +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + for lib in '${PYTHON_LIBRARIES}'.split(';'): + if '/' in lib: + prefix, py = lib.rsplit('/', 1) + if py.startswith('python3'): + print(prefix + '/python3.lib') + break + " + OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(SHIBOKEN_BUILD_TYPE "Release") -# We do not want to link against the python shared / static library on Linux And macOS. +# We do not want to link against the python shared / static library on Linux and macOS. # The dynamic linker will pick up the python symbols at runtime automatically. # On Windows we do need to link against the python.lib import library. set(SBK_PYTHON_LIBRARIES "") +option(FORCE_LIMITED_API "Enable the limited API." "no") +set(PYTHON_LIMITED_API 0) if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT PYTHON_DEBUG_LIBRARIES) message(WARNING "Python debug shared library not found; assuming python was built with shared library support disabled.") @@ -420,11 +425,32 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(SBK_PYTHON_LIBRARIES ${PYTHON_DEBUG_LIBRARIES}) endif() set(SHIBOKEN_BUILD_TYPE "Debug") -else() +endif() +if(FORCE_LIMITED_API STREQUAL "yes") + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + # GREATER_EQUAL is available only from cmake 3.7 on. We mean python 3.5 . + add_definitions("-DPy_LIMITED_API=0x03050000") + set(PYTHON_LIMITED_API 1) + endif() if(WIN32) set(SBK_PYTHON_LIBRARIES ${PYTHON_LIBRARIES}) + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + # PYSIDE-560: XXX maybe add an option to setup.py as override + set(SBK_PYTHON_LIBRARIES ${PYTHON_LIMITED_LIBRARIES}) + endif() + endif() + if (CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions("-DNDEBUG") endif() - add_definitions("-DNDEBUG") +endif() + +if (PYTHON_LIMITED_API) + if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}") + message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!") + endif() + message(STATUS "******************************************************") + message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}") + message(STATUS "******************************************************") endif() if(APPLE) @@ -437,6 +463,17 @@ else() set(SBK_PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIRS}) endif() +add_subdirectory(ApiExtractor) + +set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) + +# uninstall target +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +add_custom_target(uninstall "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + add_subdirectory(libshiboken) add_subdirectory(doc) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index d7c04d3c9..bd654f17c 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -214,6 +214,8 @@ static QString chopType(QString s) { if (s.endsWith(QLatin1String("_Type"))) s.chop(5); + else if (s.endsWith(QLatin1String("_TypeF()"))) + s.chop(8); return s; } @@ -665,7 +667,7 @@ QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctio if (func->type()->isPrimitive()) return QLatin1Char('"') + func->type()->name() + QLatin1Char('"'); - return QString::fromLatin1("Shiboken::SbkType< %1 >()->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); + return QString::fromLatin1("PepType(Shiboken::SbkType< %1 >())->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); } void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFunction* func) @@ -892,7 +894,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\ "\"Invalid return value in function %s, expected %s, got %s.\", \""; s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func); - s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << ", PepType(Py_TYPE(" PYTHON_RETURN_VAR "))->tp_name);" << endl; s << INDENT << "return " << defaultReturnExpr << ';' << endl; } s << INDENT << '}' << endl; @@ -912,7 +914,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\ "\"Invalid return value in function %s, expected %s, got %s.\", \""; s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func); - s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << ", PepType(Py_TYPE(" PYTHON_RETURN_VAR "))->tp_name);" << endl; s << INDENT << "return " << defaultReturnExpr << ';' << endl; } s << INDENT << '}' << endl; @@ -1144,11 +1146,11 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla QString targetTypeName = metaClass->name() + QLatin1String("_PTR"); QString code; QTextStream c(&code); - c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);"; + c << INDENT << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);"; writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); // "Is convertible" function for the Python object to C++ pointer conversion. - QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType); + QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)%1)").arg(cpythonType); writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true); s << endl; @@ -1157,7 +1159,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla code.clear(); if (usePySideExtensions() && metaClass->isQObject()) { - c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, &" << cpythonType << ");" << endl; + c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, " << cpythonType << ");" << endl; } else { c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl; c << INDENT << "if (pyOut) {" << endl; @@ -1168,7 +1170,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla } c << INDENT << '}' << endl; c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType; + c << INDENT << "return Shiboken::Object::newObject(" << cpythonType; c << ", const_cast<void*>(cppIn), false, false, typeName);"; } std::swap(targetTypeName, sourceTypeName); @@ -1197,7 +1199,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla else computedWrapperName = wrapperName(classContext.preciseType()); - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName; + c << INDENT << "return Shiboken::Object::newObject(" << cpythonType << ", new ::" << computedWrapperName; c << "(*((" << typeName << "*)cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); s << endl; @@ -1329,7 +1331,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas if (metaClass->isNamespace()) return; s << INDENT << "// Register Converter" << endl; - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&"; + s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter("; s << cpythonTypeName(metaClass) << ',' << endl; { Indentation indent(INDENT); @@ -2324,7 +2326,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, if (!defaultValue.isEmpty()) s << '{' << endl << INDENT; - s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<const SbkObjectType *>(" + s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))" << endl; { Indentation indent(INDENT); @@ -2838,7 +2840,7 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, if (toNative->sourceType()) inType = cpythonTypeNameExt(toNative->sourceType()); else - inType = QString::fromLatin1("(&%1_Type)").arg(toNative->sourceTypeName()); + inType = QString::fromLatin1("(%1_TypeF())").arg(toNative->sourceTypeName()); code.replace(QLatin1String("%INTYPE"), inType); code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName()); code.replace(QLatin1String("%in"), QLatin1String("pyIn")); @@ -3698,24 +3700,20 @@ void CppGenerator::writeClassDefinition(QTextStream &s, } if (!metaClass->baseClass()) - baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(&SbkObject_Type)"); + baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(SbkObject_TypeF())"); bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor(); const AbstractMetaClass *qCoreApp = AbstractMetaClass::findClass(classes(), QLatin1String("QCoreApplication")); const bool isQApp = qCoreApp != Q_NULLPTR && metaClass->inheritsFrom(qCoreApp); + tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); tp_dealloc = metaClass->hasPrivateDestructor() ? - QLatin1String("SbkDeallocWrapperWithPrivateDtor") : QLatin1String("0"); + QLatin1String("SbkDeallocWrapperWithPrivateDtor") : + QLatin1String("SbkDummyDealloc /* PYSIDE-595: Prevent replacement of \"0\" with subtype_dealloc. */"); tp_init = QLatin1String("0"); } else { - if (onlyPrivCtor) - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); - else - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); - QString deallocClassName; if (shouldGenerateCppWrapper(metaClass)) deallocClassName = wrapperName(metaClass); @@ -3741,7 +3739,21 @@ void CppGenerator::writeClassDefinition(QTextStream &s, } if (metaClass->hasPrivateDestructor() || onlyPrivCtor) { - tp_new = QLatin1String("0"); + // tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); + // This is not generally possible, because PySide does not care about + // privacy the same way. This worked before the heap types were used, + // because inheritance is not really checked for static types. + // Instead, we check this at runtime, see SbkObjectTypeTpNew. + if (metaClass->fullName().startsWith(QLatin1String("PySide2.Qt"))) { + // PYSIDE-595: No idea how to do non-inheritance correctly. + // Since that is only relevant in shiboken, I used a shortcut for + // PySide. + tp_new = QLatin1String("SbkObjectTpNew"); + } + else { + tp_new = QLatin1String("SbkDummyNew /* PYSIDE-595: Prevent replacement " + "of \"0\" with base->tp_new. */"); + } tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC")); } else if (isQApp) { @@ -3782,6 +3794,9 @@ void CppGenerator::writeClassDefinition(QTextStream &s, s << endl; } + s << "// Class Definition -----------------------------------------------" << endl; + s << "extern \"C\" {" << endl; + if (!metaClass->typeEntry()->hashFunction().isEmpty()) tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc"); @@ -3789,83 +3804,65 @@ void CppGenerator::writeClassDefinition(QTextStream &s, if (callOp && !callOp->isModifiedRemoved()) tp_call = QLatin1Char('&') + cpythonFunctionName(callOp); - s << "// Class Definition -----------------------------------------------" << endl; - s << "extern \"C\" {" << endl; - - if (supportsNumberProtocol(metaClass)) { - s << "static PyNumberMethods " << className + QLatin1String("_TypeAsNumber") << ";" << endl; - s << endl; - } - - if (supportsSequenceProtocol(metaClass)) { - s << "static PySequenceMethods " << className + QLatin1String("_TypeAsSequence") << ";" << endl; - s << endl; - } - - if (supportsMappingProtocol(metaClass)) { - s << "static PyMappingMethods " << className + QLatin1String("_TypeAsMapping") << ";" << endl; - s << endl; - } - - s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl; - s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; QString computedClassTargetFullName; if (!classContext.forSmartPointer()) computedClassTargetFullName = getClassTargetFullName(metaClass); else computedClassTargetFullName = getClassTargetFullName(classContext.preciseType()); - s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl; - s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl; - s << INDENT << "/*tp_itemsize*/ 0," << endl; - s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl; - s << INDENT << "/*tp_print*/ 0," << endl; - s << INDENT << "/*tp_getattr*/ 0," << endl; - s << INDENT << "/*tp_setattr*/ 0," << endl; - s << INDENT << "/*tp_compare*/ 0," << endl; - s << INDENT << "/*tp_repr*/ " << m_tpFuncs[QLatin1String("__repr__")] << "," << endl; - s << INDENT << "/*tp_as_number*/ 0," << endl; - s << INDENT << "/*tp_as_sequence*/ 0," << endl; - s << INDENT << "/*tp_as_mapping*/ 0," << endl; - s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl; - s << INDENT << "/*tp_call*/ " << tp_call << ',' << endl; - s << INDENT << "/*tp_str*/ " << m_tpFuncs[QLatin1String("__str__")] << ',' << endl; - s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl; - s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl; - s << INDENT << "/*tp_as_buffer*/ 0," << endl; - s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl; - s << INDENT << "/*tp_doc*/ 0," << endl; - s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl; - s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl; - s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl; - s << INDENT << "/*tp_weaklistoffset*/ 0," << endl; - s << INDENT << "/*tp_iter*/ " << m_tpFuncs[QLatin1String("__iter__")] << ',' << endl; - s << INDENT << "/*tp_iternext*/ " << m_tpFuncs[QLatin1String("__next__")] << ',' << endl; - s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl; - s << INDENT << "/*tp_members*/ 0," << endl; - s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl; - s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl; - s << INDENT << "/*tp_dict*/ 0," << endl; - s << INDENT << "/*tp_descr_get*/ 0," << endl; - s << INDENT << "/*tp_descr_set*/ 0," << endl; - s << INDENT << "/*tp_dictoffset*/ 0," << endl; - s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl; - s << INDENT << "/*tp_alloc*/ 0," << endl; - s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl; - s << INDENT << "/*tp_free*/ 0," << endl; - s << INDENT << "/*tp_is_gc*/ 0," << endl; - s << INDENT << "/*tp_bases*/ 0," << endl; - s << INDENT << "/*tp_mro*/ 0," << endl; - s << INDENT << "/*tp_cache*/ 0," << endl; - s << INDENT << "/*tp_subclasses*/ 0," << endl; - s << INDENT << "/*tp_weaklist*/ 0" << endl; - s << "}, }," << endl; - s << INDENT << "/*priv_data*/ 0" << endl; - s << "};" << endl; QString suffix; if (isObjectType(metaClass)) suffix = QLatin1String("*"); - s << "} //extern" << endl; + const QString typePtr = QLatin1String("_") + className + + QLatin1String("_Type"); + s << "static SbkObjectType *" << typePtr << " = nullptr;" << endl; + s << "static SbkObjectType *" << className << "_TypeF(void)" << endl; + s << "{" << endl; + s << INDENT << "return " << typePtr << ";" << endl; + s << "}" << endl; + s << endl; + s << "static PyType_Slot " << className << "_slots[] = {" << endl; + s << INDENT << "{Py_tp_base, (void *)0}, // inserted by introduceWrapperType" << endl; + s << INDENT << "{Py_tp_dealloc, (void *)" << tp_dealloc << "}," << endl; + s << INDENT << "{Py_tp_repr, (void *)" << m_tpFuncs[QLatin1String("__repr__")] << "}," << endl; + s << INDENT << "{Py_tp_hash, (void *)" << tp_hash << "}," << endl; + s << INDENT << "{Py_tp_call, (void *)" << tp_call << "}," << endl; + s << INDENT << "{Py_tp_str, (void *)" << m_tpFuncs[QLatin1String("__str__")] << "}," << endl; + s << INDENT << "{Py_tp_getattro, (void *)" << tp_getattro << "}," << endl; + s << INDENT << "{Py_tp_setattro, (void *)" << tp_setattro << "}," << endl; + s << INDENT << "{Py_tp_traverse, (void *)" << className << "_traverse}," << endl; + s << INDENT << "{Py_tp_clear, (void *)" << className << "_clear}," << endl; + s << INDENT << "{Py_tp_richcompare, (void *)" << tp_richcompare << "}," << endl; + s << INDENT << "{Py_tp_iter, (void *)" << m_tpFuncs[QLatin1String("__iter__")] << "}," << endl; + s << INDENT << "{Py_tp_iternext, (void *)" << m_tpFuncs[QLatin1String("__next__")] << "}," << endl; + s << INDENT << "{Py_tp_methods, (void *)" << className << "_methods}," << endl; + s << INDENT << "{Py_tp_getset, (void *)" << tp_getset << "}," << endl; + s << INDENT << "{Py_tp_init, (void *)" << tp_init << "}," << endl; + s << INDENT << "{Py_tp_new, (void *)" << tp_new << "}," << endl; + if (supportsSequenceProtocol(metaClass)) { + s << INDENT << "// type supports sequence protocol" << endl; + writeTypeAsSequenceDefinition(s, metaClass); + } + if (supportsMappingProtocol(metaClass)) { + s << INDENT << "// type supports mapping protocol" << endl; + writeTypeAsMappingDefinition(s, metaClass); + } + if (supportsNumberProtocol(metaClass)) { + // This one must come last. See the function itself. + s << INDENT << "// type supports number protocol" << endl; + writeTypeAsNumberDefinition(s, metaClass); + } + s << INDENT << "{0, 0}" << endl; + s << "};" << endl; + s << "static PyType_Spec " << className << "_spec = {" << endl; + s << INDENT << "\"" << computedClassTargetFullName << "\"," << endl; + s << INDENT << "sizeof(SbkObject)," << endl; + s << INDENT << "0," << endl; + s << INDENT << tp_flags << "," << endl; + s << INDENT << className << "_slots" << endl; + s << "};" << endl; + s << endl; + s << "} //extern \"C\"" << endl; } void CppGenerator::writeMappingMethods(QTextStream &s, @@ -3943,14 +3940,13 @@ void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractM funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__"); } - s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl; for (QHash<QString, QString>::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) { const QString& sqName = it.key(); if (funcs[sqName].isEmpty()) continue; if (it.value() == QLatin1String("sq_slice")) s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_TypeAsSequence." << it.value() << " = " << funcs[sqName] << ';' << endl; + s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[sqName] << "}," << endl; if (it.value() == QLatin1String("sq_slice")) s << "#endif" << endl; } @@ -3976,12 +3972,11 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe } QString baseName = cpythonBaseName(metaClass); - s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl; for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) { const QString &mpName = it.key(); if (funcs[mpName].isEmpty()) continue; - s << INDENT << baseName << "_TypeAsMapping." << it.value() << " = " << funcs[mpName] << ';' << endl; + s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[mpName] << "}," << endl; } } @@ -4029,7 +4024,6 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString(); - s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl; for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) { const QString &nbName = it.key(); if (nb[nbName].isEmpty()) @@ -4038,21 +4032,29 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool) // so a shiboken macro is used. if (nbName == QLatin1String("bool")) { - s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl; + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "{Py_nb_bool, (void *)" << nb[nbName] << "}," << endl; + s << "#else" << endl; + s << INDENT << "{Py_nb_nonzero, (void *)" << nb[nbName] << "}," << endl; + s << "#endif" << endl; } else { bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__"); - if (excludeFromPy3K) { - s << "#ifdef IS_PY3K" << endl; - s << INDENT << "SBK_UNUSED(&" << nb[nbName] << ");" << endl; - s << "#else" << endl; - } - s << INDENT << baseName << "_TypeAsNumber." << it.value() << " = " << nb[nbName] << ';' << endl; - if (excludeFromPy3K) - s << "#endif" << endl; + if (!excludeFromPy3K) + s << INDENT << "{Py_" << it.value() << ", (void *)" << nb[nbName] << "}," << endl; } } - if (!nb[QLatin1String("__div__")].isEmpty()) - s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb[QLatin1String("__div__")] << ';' << endl; + if (!nb[QLatin1String("__div__")].isEmpty()) { + s << INDENT << "{Py_nb_true_divide, (void *)" << nb[QLatin1String("__div__")] << "}," << endl; + s << "#ifndef IS_PY3K" << endl; + s << INDENT << "{Py_nb_divide, (void *)" << nb[QLatin1String("__div__")] << "}," << endl; + s << "#endif" << endl; + } + if (!nb[QLatin1String("__idiv__")].isEmpty()) { + s << INDENT << "// This function is unused in Python 3. We reference it here." << endl; + s << INDENT << "{0, (void *)" << nb[QLatin1String("__idiv__")] << "}," << endl; + s << INDENT << "// This list is ending at the first 0 entry." << endl; + s << INDENT << "// Therefore, we need to put the unused functions at the very end." << endl; + } } void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass) @@ -4061,7 +4063,7 @@ void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaCla s << "static int "; s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; + s << INDENT << "return PepType(reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; s << '}' << endl; } @@ -4071,7 +4073,7 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* s << "static int "; s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_clear(" PYTHON_SELF_VAR ");" << endl; + s << INDENT << "return PepType(reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))->tp_clear(" PYTHON_SELF_VAR ");" << endl; s << '}' << endl; } @@ -4147,7 +4149,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s, { Indentation indent(INDENT); s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild(" - << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<const SbkObjectType *>(" + << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType) << ")));\n"; s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n"; @@ -4474,7 +4476,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu const EnumTypeEntry *enumTypeEntry = cppEnum->typeEntry(); QString enclosingObjectVariable; if (enclosingClass) - enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass); + enclosingObjectVariable = cpythonTypeName(enclosingClass); else if (hasUpperEnclosingClass) enclosingObjectVariable = QLatin1String("enclosingClass"); else @@ -4488,8 +4490,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu if (!cppEnum->isAnonymous()) { FlagsTypeEntry* flags = enumTypeEntry->flags(); if (flags) { - s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &" - << cpythonEnumName(cppEnum) << "_as_number);" << endl; + s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", " + << cpythonEnumName(cppEnum) << "_number_slots);" << endl; } enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry); @@ -4539,8 +4541,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu { Indentation indent(INDENT); s << INDENT << "PyObject* anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl; - s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable - << ")->super.ht_type.tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; + s << INDENT << "if (PyDict_SetItemString(PepType(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable + << "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; { Indentation indent(INDENT); s << INDENT << "return " << m_currentErrorCode << ';' << endl; @@ -4609,7 +4611,7 @@ void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaC } } - s << INDENT << "PySide::Signal::registerSignals(&" << cpythonTypeName(metaClass) << ", &::" + s << INDENT << "PySide::Signal::registerSignals(" << cpythonTypeName(metaClass) << ", &::" << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl; } @@ -4659,57 +4661,22 @@ void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const Abstr { QString cpythonName = cpythonEnumName(cppEnum); - s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl; - s << INDENT << "/*nb_add*/ 0," << endl; - s << INDENT << "/*nb_subtract*/ 0," << endl; - s << INDENT << "/*nb_multiply*/ 0," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/* nb_divide */ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_remainder*/ 0," << endl; - s << INDENT << "/*nb_divmod*/ 0," << endl; - s << INDENT << "/*nb_power*/ 0," << endl; - s << INDENT << "/*nb_negative*/ 0," << endl; - s << INDENT << "/*nb_positive*/ 0," << endl; - s << INDENT << "/*nb_absolute*/ 0," << endl; - s << INDENT << "/*nb_nonzero*/ " << cpythonName << "__nonzero," << endl; - s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__," << endl; - s << INDENT << "/*nb_lshift*/ 0," << endl; - s << INDENT << "/*nb_rshift*/ 0," << endl; - s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__," << endl; - s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__," << endl; - s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/* nb_coerce */ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_int*/ " << cpythonName << "_long," << endl; - s << INDENT << "#ifdef IS_PY3K" << endl; - s << INDENT << "/*nb_reserved*/ 0," << endl; - s << INDENT << "/*nb_float*/ 0," << endl; - s << INDENT << "#else" << endl; - s << INDENT << "/*nb_long*/ " << cpythonName << "_long," << endl; - s << INDENT << "/*nb_float*/ 0," << endl; - s << INDENT << "/*nb_oct*/ 0," << endl; - s << INDENT << "/*nb_hex*/ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_inplace_add*/ 0," << endl; - s << INDENT << "/*nb_inplace_subtract*/ 0," << endl; - s << INDENT << "/*nb_inplace_multiply*/ 0," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/*nb_inplace_divide*/ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_inplace_remainder*/ 0," << endl; - s << INDENT << "/*nb_inplace_power*/ 0," << endl; - s << INDENT << "/*nb_inplace_lshift*/ 0," << endl; - s << INDENT << "/*nb_inplace_rshift*/ 0," << endl; - s << INDENT << "/*nb_inplace_and*/ 0," << endl; - s << INDENT << "/*nb_inplace_xor*/ 0," << endl; - s << INDENT << "/*nb_inplace_or*/ 0," << endl; - s << INDENT << "/*nb_floor_divide*/ 0," << endl; - s << INDENT << "/*nb_true_divide*/ 0," << endl; - s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl; - s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl; - s << INDENT << "/*nb_index*/ 0" << endl; + s << "static PyType_Slot " << cpythonName << "_number_slots[] = {" << endl; + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "{Py_nb_bool, (void *)" << cpythonName << "__nonzero}," << endl; + s << "#else" << endl; + s << INDENT << "{Py_nb_nonzero, (void *)" << cpythonName << "__nonzero}," << endl; + s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long}," << endl; + s << "#endif" << endl; + s << INDENT << "{Py_nb_invert, (void *)" << cpythonName << "___invert__}," << endl; + s << INDENT << "{Py_nb_and, (void *)" << cpythonName << "___and__}," << endl; + s << INDENT << "{Py_nb_xor, (void *)" << cpythonName << "___xor__}," << endl; + s << INDENT << "{Py_nb_or, (void *)" << cpythonName << "___or__}," << endl; + s << INDENT << "{Py_nb_int, (void *)" << cpythonName << "_long}," << endl; + s << "#ifndef IS_PY3K" << endl; + s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long}," << endl; + s << "#endif" << endl; + s << INDENT << "{0, 0} // sentinel" << endl; s << "};" << endl << endl; } @@ -4803,37 +4770,8 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "(PyObject* " << enclosingObjectVariable << ")" << endl; s << '{' << endl; - if (supportsNumberProtocol(metaClass)) { - s << INDENT << "// type has number operators" << endl; - writeTypeAsNumberDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl; - s << endl; - } - - if (supportsSequenceProtocol(metaClass)) { - s << INDENT << "// type supports sequence protocol" << endl; - writeTypeAsSequenceDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl; - s << endl; - } - - if (supportsMappingProtocol(metaClass)) { - s << INDENT << "// type supports mapping protocol" << endl; - writeTypeAsMappingDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl; - s << endl; - } - - if (!classContext.forSmartPointer()) - s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl; - else - s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl; - - s << INDENT << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl; - s << endl; - // Multiple inheritance - QString pyTypeBasesVariable = pyTypeName + QLatin1String("_bases"); + QString pyTypeBasesVariable = chopType(pyTypeName) + QLatin1String("_Type_bases"); const AbstractMetaClassList baseClasses = getBaseClasses(metaClass); if (metaClass->baseClassNames().size() > 1) { s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl; @@ -4848,28 +4786,42 @@ void CppGenerator::writeClassRegister(QTextStream &s, } // Create type and insert it in the module or enclosing class. - s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable; - QString typeName; - if (!classContext.forSmartPointer()) - typeName = metaClass->name(); - else - typeName = classContext.preciseType()->cppSignature(); - - s << ", \"" << typeName << "\", \""; + const QString typePtr = QLatin1String("_") + chopType(pyTypeName) + + QLatin1String("_Type"); - // Original name - if (!classContext.forSmartPointer()) - s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); - else - s << classContext.preciseType()->cppSignature(); - - s << "\"," << endl; + s << INDENT << typePtr << " = Shiboken::ObjectType::introduceWrapperType(" << endl; { Indentation indent(INDENT); - s << INDENT << "&" << pyTypeName << "," << endl; - s << INDENT << initFunctionName << "_SignaturesString"; + // 1:enclosingObject + s << INDENT << enclosingObjectVariable << "," << endl; + QString typeName; + if (!classContext.forSmartPointer()) + typeName = metaClass->name(); + else + typeName = classContext.preciseType()->cppSignature(); + + // 2:typeName + s << INDENT << "\"" << typeName << "\"," << endl; + + // 3:originalName + s << INDENT << "\""; + if (!classContext.forSmartPointer()) { + s << metaClass->qualifiedCppName(); + if (isObjectType(classTypeEntry)) + s << '*'; + } else { + s << classContext.preciseType()->cppSignature(); + } + + s << "\"," << endl; + // 4:typeSpec + s << INDENT << '&' << chopType(pyTypeName) << "_spec," << endl; - // Set destructor function + // 5:signaturesString + s << INDENT << initFunctionName << "_SignaturesString," << endl; + + // 6:cppObjDtor + s << INDENT; if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { QString dtorClassName = metaClass->qualifiedCppName(); if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) @@ -4877,28 +4829,37 @@ void CppGenerator::writeClassRegister(QTextStream &s, if (classContext.forSmartPointer()) dtorClassName = wrapperName(classContext.preciseType()); - s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; - } else if (metaClass->baseClass() || hasEnclosingClass) { - s << ", 0"; + s << "&Shiboken::callCppDestructor< ::" << dtorClassName << " >," << endl; + } else { + s << "0," << endl; } - // Base type + // 7:baseType if (metaClass->baseClass()) { - s << ", reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ')'; - // The other base types - if (metaClass->baseClassNames().size() > 1) - s << ", " << pyTypeBasesVariable; - else if (hasEnclosingClass) - s << ", 0"; - } else if (hasEnclosingClass) { - s << ", 0, 0"; - } - if (hasEnclosingClass) - s << ", true"; - s << ")) {" << endl; - s << INDENT << "return;" << endl; + s << INDENT << "reinterpret_cast<SbkObjectType *>(" + << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ")," << endl; + } else { + s << INDENT << "0," << endl; + } + + // 8:baseTypes + if (metaClass->baseClassNames().size() > 1) + s << INDENT << pyTypeBasesVariable << ',' << endl; + else + s << INDENT << "0," << endl; + + // 9:isInnerClass + s << INDENT << (hasEnclosingClass ? "true" : "false") << endl; } - s << INDENT << '}' << endl << endl; + s << INDENT << ");" << endl; + s << INDENT << endl; + + if (!classContext.forSmartPointer()) + s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl; + else + s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl; + s << INDENT << " = reinterpret_cast<PyTypeObject*>(" << pyTypeName << ");" << endl; + s << endl; // Register conversions for the type. writeConverterRegister(s, metaClass, classContext); @@ -4920,15 +4881,15 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "Shiboken::ObjectType::getMultipleIheritanceFunction(reinterpret_cast<SbkObjectType*>("; s << cpythonTypeNameExt(miClass->typeEntry()) << "));" << endl; } - s << INDENT << "Shiboken::ObjectType::setMultipleIheritanceFunction(&"; + s << INDENT << "Shiboken::ObjectType::setMultipleInheritanceFunction("; s << cpythonTypeName(metaClass) << ", func);" << endl; - s << INDENT << "Shiboken::ObjectType::setCastFunction(&" << cpythonTypeName(metaClass); + s << INDENT << "Shiboken::ObjectType::setCastFunction(" << cpythonTypeName(metaClass); s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");" << endl; } // Set typediscovery struct or fill the struct of another one if (metaClass->isPolymorphic() && metaClass->baseClass()) { - s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(&" << cpythonTypeName(metaClass); + s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(" << cpythonTypeName(metaClass); s << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl << endl; } @@ -4948,7 +4909,7 @@ void CppGenerator::writeClassRegister(QTextStream &s, for (const AbstractMetaField *field : fields) { if (!field->isStatic()) continue; - s << INDENT << QLatin1String("PyDict_SetItemString(") + cpythonTypeName(metaClass) + QLatin1String(".super.ht_type.tp_dict, \""); + s << INDENT << QLatin1String("PyDict_SetItemString(PepType(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \""); s << field->name() << "\", "; writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name()); s << ");" << endl; @@ -4969,8 +4930,8 @@ void CppGenerator::writeClassRegister(QTextStream &s, } if (usePySideExtensions() && metaClass->isQObject()) { - s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(&" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; - s << INDENT << "PySide::initDynamicMetaObject(&" << pyTypeName << ", &::" << metaClass->qualifiedCppName() + s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; + s << INDENT << "PySide::initDynamicMetaObject(" << pyTypeName << ", &::" << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));" << endl; } @@ -5163,7 +5124,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl; { Indentation indent(INDENT); - s << INDENT << "PyObject* meth = PyDict_GetItem(" PYTHON_SELF_VAR "->ob_type->tp_dict, name);" << endl; + s << INDENT << "PyObject* meth = PyDict_GetItem(PepType(Py_TYPE(" PYTHON_SELF_VAR "))->tp_dict, name);" << endl; s << INDENT << "if (meth)" << endl; { Indentation indent(INDENT); @@ -5228,7 +5189,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl; s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl; s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl; - s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl; + s << INDENT << " PepType(tp)->tp_name, PyBytes_AS_STRING(name));" << endl; s << INDENT << "return NULL;" << endl; } s << INDENT << "} else {" << endl; @@ -5308,7 +5269,7 @@ bool CppGenerator::finishGeneration() QString defineStr = QLatin1String("init_") + cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")); if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) - defineStr += QLatin1Char('(') + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String("->tp_dict);"); + defineStr += QLatin1String("(PepType(") + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String(")->tp_dict);"); else defineStr += QLatin1String("(module);"); s_classPythonDefines << INDENT << defineStr << endl; @@ -5854,10 +5815,12 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex s << INDENT << "if (idx >= 0)" << endl; { Indentation indent(INDENT); - s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl; + s << INDENT << "str.replace(0, idx, PepType((Py_TYPE(self)))->tp_name);" << endl; } - s << INDENT << "PyObject* mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl; - s << INDENT << "if (mod)" << endl; + s << INDENT << "PyObject* mod = PyDict_GetItemString(PepType(Py_TYPE(self))->tp_dict, \"__module__\");" << endl; + // PYSIDE-595: The introduction of heap types has the side effect that the module name + // is always prepended to the type name. Therefore the strchr check: + s << INDENT << "if (mod && !strchr(str, '.'))" << endl; { Indentation indent(INDENT); s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);" << endl; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 6165ef009..976b34141 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -804,7 +804,7 @@ QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type) { - return cpythonBaseName(type) + QLatin1String("_Type"); + return cpythonBaseName(type) + QLatin1String("_TypeF()"); } QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type) @@ -838,7 +838,7 @@ QString ShibokenGenerator::converterObject(const TypeEntry* type) if (isCppPrimitive(type)) return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); if (isWrapperType(type) || type->isEnum() || type->isFlags()) - return QString::fromLatin1("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type)); + return QString::fromLatin1("*PepType_SGTP(%1)->converter").arg(cpythonTypeNameExt(type)); if (type->isArray()) { qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName(); @@ -1164,7 +1164,7 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType if (isPointerToWrapperType(type)) { typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type)); } else if (isWrapperType(type)) { - typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<const SbkObjectType *>("); + typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<SbkObjectType *>("); typeCheck += cpythonTypeNameExt(type); typeCheck += QLatin1String("), "); } else { @@ -1287,7 +1287,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* result += QLatin1String("isPythonToCppReferenceConvertible"); else result += QLatin1String("isPythonToCppValueConvertible"); - result += QLatin1String("(reinterpret_cast<const SbkObjectType *>(") + result += QLatin1String("(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(metaType) + QLatin1String("), "); return result; } @@ -1341,7 +1341,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT else conversion = QLatin1String("pointer"); QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) + QLatin1String("), "); if (conversion != QLatin1String("pointer")) result += QLatin1Char('&'); @@ -1362,7 +1362,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* ty if (isWrapperType(type)) { const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer"); QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + cpythonTypeNameExt(type) + + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) + QLatin1String("), "); if (conversion != QLatin1String("pointer")) result += QLatin1Char('&'); @@ -1625,7 +1625,7 @@ void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* // Replace template variable by the Python Type object // for the class context in which the variable is used. code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(context) + QLatin1String(".super.ht_type")); + cpythonTypeName(context) + QLatin1String("->type")); code.replace(QLatin1String("%TYPE"), wrapperName(context)); code.replace(QLatin1String("%CPPTYPE"), context->name()); } @@ -1856,7 +1856,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, // class implementing the method in which the code snip is written if (func->isStatic()) { code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(func->implementingClass()) + QLatin1String(".super.ht_type")); + cpythonTypeName(func->implementingClass()) + QLatin1String("->type")); } else { code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->")); code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type")); diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index e87cf07fd..b5ba78e15 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -48,7 +48,10 @@ threadstatesaver.cpp shibokenbuffer.cpp signature.cpp qapp_macro.cpp +pep384impl.cpp voidptr.cpp +typespec.cpp +bufferprocs27.cpp ) get_numpy_location() @@ -89,9 +92,12 @@ install(FILES threadstatesaver.h shibokenbuffer.h sbkpython.h + pep384impl.h signature.h qapp_macro.h voidptr.h + typespec.h + bufferprocs27.h "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" DESTINATION include/shiboken2${shiboken2_SUFFIX}) install(TARGETS libshiboken EXPORT shiboken2 diff --git a/sources/shiboken2/libshiboken/autodecref.h b/sources/shiboken2/libshiboken/autodecref.h index 1f3f41eab..7b6aa47da 100644 --- a/sources/shiboken2/libshiboken/autodecref.h +++ b/sources/shiboken2/libshiboken/autodecref.h @@ -79,7 +79,9 @@ public: /// Returns the pointer of the Python object being held. inline PyObject* object() { return m_pyObj; } inline operator PyObject*() { return m_pyObj; } +#ifndef Py_LIMITED_API inline operator PyTupleObject*() { return reinterpret_cast<PyTupleObject*>(m_pyObj); } +#endif inline operator bool() const { return m_pyObj != 0; } inline PyObject* operator->() { return m_pyObj; } diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 21f6933d2..0e2712ec8 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -66,55 +66,34 @@ extern "C" static void SbkObjectTypeDealloc(PyObject* pyObj); static PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); -PyTypeObject SbkObjectType_Type = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "Shiboken.ObjectType", - /*tp_basicsize*/ sizeof(SbkObjectType), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkObjectTypeDealloc, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ PyObject_GenericSetAttr, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ PyType_GenericAlloc, - /*tp_new*/ SbkObjectTypeTpNew, - /*tp_free*/ PyObject_GC_Del, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +static PyType_Slot SbkObjectType_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkObjectTypeDealloc}, + {Py_tp_setattro, (void *)PyObject_GenericSetAttr}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_new, (void *)SbkObjectTypeTpNew}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {0, 0} }; +static PyType_Spec SbkObjectType_Type_spec = { + "Shiboken.ObjectType", + 0, // basicsize (inserted later) + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + SbkObjectType_Type_slots, +}; + + +PyTypeObject *SbkObjectType_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + SbkObjectType_Type_spec.basicsize = + PepHeapType_SIZE + sizeof(SbkObjectTypePrivate); + type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec)); + } + return type; +} static PyObject *SbkObjectGetDict(PyObject* pObj, void *) { @@ -176,57 +155,36 @@ static int SbkObject_clear(PyObject* self) return 0; } -SbkObjectType SbkObject_Type = { { { - PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0) - /*tp_name*/ "Shiboken.Object", - /*tp_basicsize*/ sizeof(SbkObject), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkDeallocWrapperWithPrivateDtor, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, - /*tp_doc*/ 0, - /*tp_traverse*/ SbkObject_traverse, - /*tp_clear*/ SbkObject_clear, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ offsetof(SbkObject, weakreflist), - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ SbkObjectGetSetList, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ offsetof(SbkObject, ob_dict), - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ 0, - /*tp_free*/ 0, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}, }, - /*priv_data*/ 0 +static PyType_Slot SbkObject_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkDeallocWrapperWithPrivateDtor}, + {Py_tp_traverse, (void *)SbkObject_traverse}, + {Py_tp_clear, (void *)SbkObject_clear}, + // unsupported: {Py_tp_weaklistoffset, (void *)offsetof(SbkObject, weakreflist)}, + {Py_tp_getset, (void *)SbkObjectGetSetList}, + // unsupported: {Py_tp_dictoffset, (void *)offsetof(SbkObject, ob_dict)}, + {0, 0} }; +static PyType_Spec SbkObject_Type_spec = { + "Shiboken.Object", + sizeof(SbkObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + SbkObject_Type_slots, +}; + + +SbkObjectType *SbkObject_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObject_Type_spec)); + Py_TYPE(type) = SbkObjectType_TypeF(); + Py_INCREF(Py_TYPE(type)); + PepType(type)->tp_weaklistoffset = offsetof(SbkObject, weakreflist); + PepType(type)->tp_dictoffset = offsetof(SbkObject, ob_dict); + } + return reinterpret_cast<SbkObjectType *>(type); +} static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) @@ -237,8 +195,8 @@ 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->tp_dealloc == SbkDeallocWrapper - || pyType->tp_dealloc == SbkDeallocWrapperWithPrivateDtor); + bool needTypeDecref = (PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper + || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapperWithPrivateDtor); // Ensure that the GC is no longer tracking this object to avoid a // possible reentrancy problem. Since there are multiple steps involved @@ -257,10 +215,10 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) // If I have ownership and is valid delete C++ pointer if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyType); - if (sbkType->d->is_multicpp) { + SbkObjectTypePrivate *sotp = PepType_SOTP(pyType); + if (sotp->is_multicpp) { Shiboken::DeallocVisitor visitor(sbkObj); - Shiboken::walkThroughClassHierarchy(pyObj->ob_type, &visitor); + Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); } else { void* cptr = sbkObj->d->cptr[0]; Shiboken::Object::deallocData(sbkObj, true); @@ -268,7 +226,7 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) Shiboken::ThreadStateSaver threadSaver; if (Py_IsInitialized()) threadSaver.save(); - sbkType->d->cpp_dtor(cptr); + sotp->cpp_dtor(cptr); } } else { Shiboken::Object::deallocData(sbkObj, true); @@ -297,91 +255,103 @@ void SbkDeallocWrapperWithPrivateDtor(PyObject* self) void SbkObjectTypeDealloc(PyObject* pyObj) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyObj); + SbkObjectTypePrivate *sotp = PepType_SOTP(pyObj); + PyTypeObject *type = reinterpret_cast<PyTypeObject*>(pyObj); PyObject_GC_UnTrack(pyObj); Py_TRASHCAN_SAFE_BEGIN(pyObj); - if (sbkType->d) { - if(sbkType->d->user_data && sbkType->d->d_func) { - sbkType->d->d_func(sbkType->d->user_data); - sbkType->d->user_data = 0; + if (sotp) { + if (sotp->user_data && sotp->d_func) { + sotp->d_func(sotp->user_data); + sotp->user_data = nullptr; } - free(sbkType->d->original_name); - sbkType->d->original_name = 0; - if (!Shiboken::ObjectType::isUserType(reinterpret_cast<PyTypeObject*>(sbkType))) - Shiboken::Conversions::deleteConverter(sbkType->d->converter); - delete sbkType->d; - sbkType->d = 0; + free(sotp->original_name); + sotp->original_name = nullptr; + if (!Shiboken::ObjectType::isUserType(type)) + Shiboken::Conversions::deleteConverter(sotp->converter); + delete sotp; + sotp = nullptr; } Py_TRASHCAN_SAFE_END(pyObj); } PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) { -#ifndef IS_PY3K // Check if all bases are new style before calling type.tp_new // Was causing gc assert errors in test_bug704.py when // this check happened after creating the type object. // Argument parsing take from type.tp_new code. + + // PYSIDE-595: Also check if all bases allow inheritance. + // Before we changed to heap types, it was sufficient to remove the + // Py_TPFLAGS_BASETYPE flag. That does not work, because PySide does + // not respect this flag itself! PyObject* name; PyObject* pyBases; PyObject* dict; static const char* kwlist[] = { "name", "bases", "dict", 0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:sbktype", (char**)kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO!O!:sbktype", (char**)kwlist, &name, &PyTuple_Type, &pyBases, &PyDict_Type, &dict)) return NULL; - for(int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { + for (int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { PyObject* baseType = PyTuple_GET_ITEM(pyBases, i); +#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); + PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. " + "PySide only support multiple inheritance from python new style class.", PepType(metatype)->tp_name); return 0; } - } #endif + if (PepType(reinterpret_cast<PyTypeObject*>(baseType))->tp_new == SbkDummyNew) { + // PYSIDE-595: A base class does not allow inheritance. + return SbkDummyNew(metatype, args, kwds); + } + } // The meta type creates a new type when the Python programmer extends a wrapped C++ class. - SbkObjectType* newType = reinterpret_cast<SbkObjectType*>(PyType_Type.tp_new(metatype, args, kwds)); + newfunc type_new = reinterpret_cast<newfunc>(PepType(&PyType_Type)->tp_new); + SbkObjectType *newType = reinterpret_cast<SbkObjectType*>(type_new(metatype, args, kwds)); if (!newType) return 0; Shiboken::ObjectType::initPrivateData(newType); - SbkObjectTypePrivate* d = newType->d; + SbkObjectTypePrivate *sotp = PepType_SOTP(newType); std::list<SbkObjectType*> bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType)); if (bases.size() == 1) { - SbkObjectTypePrivate* parentType = bases.front()->d; - d->mi_offsets = parentType->mi_offsets; - d->mi_init = parentType->mi_init; - d->mi_specialcast = parentType->mi_specialcast; - d->type_discovery = parentType->type_discovery; - d->cpp_dtor = parentType->cpp_dtor; - d->is_multicpp = 0; - d->converter = parentType->converter; + SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front()); + sotp->mi_offsets = parentType->mi_offsets; + sotp->mi_init = parentType->mi_init; + sotp->mi_specialcast = parentType->mi_specialcast; + sotp->type_discovery = parentType->type_discovery; + sotp->cpp_dtor = parentType->cpp_dtor; + sotp->is_multicpp = 0; + sotp->converter = parentType->converter; } else { - d->mi_offsets = 0; - d->mi_init = 0; - d->mi_specialcast = 0; - d->type_discovery = 0; - d->cpp_dtor = 0; - d->is_multicpp = 1; - d->converter = 0; + sotp->mi_offsets = nullptr; + sotp->mi_init = nullptr; + sotp->mi_specialcast = nullptr; + sotp->type_discovery = nullptr; + sotp->cpp_dtor = nullptr; + sotp->is_multicpp = 1; + sotp->converter = nullptr; } if (bases.size() == 1) - d->original_name = strdup(bases.front()->d->original_name); + sotp->original_name = strdup(PepType_SOTP(bases.front())->original_name); else - d->original_name = strdup("object"); - d->user_data = 0; - d->d_func = 0; - d->is_user_type = 1; + sotp->original_name = strdup("object"); + sotp->user_data = nullptr; + sotp->d_func = nullptr; + sotp->is_user_type = 1; std::list<SbkObjectType*>::const_iterator it = bases.begin(); for (; it != bases.end(); ++it) { - if ((*it)->d->subtype_init) - (*it)->d->subtype_init(newType, args, kwds); + if (PepType_SOTP(*it)->subtype_init) + PepType_SOTP(*it)->subtype_init(newType, args, kwds); } return reinterpret_cast<PyObject*>(newType); @@ -392,18 +362,19 @@ static PyObject *_setupNew(SbkObject *self, PyTypeObject *subtype) Py_INCREF(reinterpret_cast<PyObject*>(subtype)); SbkObjectPrivate* d = new SbkObjectPrivate; - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(subtype); - int numBases = ((sbkType->d && sbkType->d->is_multicpp) ? Shiboken::getNumberOfCppBaseClasses(subtype) : 1); + SbkObjectTypePrivate * sotp = PepType_SOTP(subtype); + int numBases = ((sotp && sotp->is_multicpp) ? + Shiboken::getNumberOfCppBaseClasses(subtype) : 1); d->cptr = new void*[numBases]; - std::memset(d->cptr, 0, sizeof(void*)*numBases); + std::memset(d->cptr, 0, sizeof(void*) * size_t(numBases)); d->hasOwnership = 1; d->containsCppWrapper = 0; d->validCppObject = 0; - d->parentInfo = 0; - d->referredObjects = 0; + d->parentInfo = nullptr; + d->referredObjects = nullptr; d->cppObjectCreated = 0; - self->ob_dict = 0; - self->weakreflist = 0; + self->ob_dict = nullptr; + self->weakreflist = nullptr; self->d = d; return reinterpret_cast<PyObject*>(self); } @@ -422,18 +393,37 @@ PyObject* SbkQAppTpNew(PyTypeObject* subtype, PyObject *, PyObject *) // For qApp, we need to create a singleton Python object. // We cannot track this with the GC, because it is a static variable! - // Python2 has a weird handling of flags in derived classes that Python3 + // 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 SbkObject* self = reinterpret_cast<SbkObject*>(MakeSingletonQAppWrapper(subtype)); return self == 0 ? 0 : _setupNew(self, subtype); } +void +SbkDummyDealloc(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, + "cannot create '%.100s' instances ¯\\_(ツ)_/¯", + PepType(type)->tp_name); + return nullptr; +} } //extern "C" @@ -464,16 +454,16 @@ static void decRefPyObjectList(const std::list<PyObject*> &pyObj, PyObject* skip static void _walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor) { - PyObject* bases = currentType->tp_bases; + PyObject* bases = PepType(currentType)->tp_bases; Py_ssize_t numBases = PyTuple_GET_SIZE(bases); for (int i = 0; i < numBases; ++i) { PyTypeObject* type = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i)); - if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { continue; } else { SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(type); - if (sbkType->d->is_user_type) + if (PepType_SOTP(sbkType)->is_user_type) _walkThroughClassHierarchy(type, visitor); else visitor->visit(sbkType); @@ -532,7 +522,7 @@ void DtorCallerVisitor::done() for (; it != m_ptrs.end(); ++it) { Shiboken::ThreadStateSaver threadSaver; threadSaver.save(); - it->second->d->cpp_dtor(it->first); + PepType_SOTP(it->second)->cpp_dtor(it->first); } } @@ -555,15 +545,17 @@ void init() PyEval_InitThreads(); //Init private data - Shiboken::ObjectType::initPrivateData(&SbkObject_Type); + Pep_Init(); + + Shiboken::ObjectType::initPrivateData(SbkObject_TypeF()); - if (PyType_Ready(&SbkEnumType_Type) < 0) + if (PyType_Ready(SbkEnumType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.SbkEnumType metatype."); - if (PyType_Ready(&SbkObjectType_Type) < 0) + if (PyType_Ready(SbkObjectType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapperType metatype."); - if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkObject_Type)) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapper type."); VoidPtr::init(); @@ -581,10 +573,10 @@ void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const cha if (i) params += ", "; PyObject* arg = PyTuple_GET_ITEM(args, i); - params += arg->ob_type->tp_name; + params += PepType((Py_TYPE(arg)))->tp_name; } } else { - params = args->ob_type->tp_name; + params = PepType((Py_TYPE(args)))->tp_name; } } @@ -660,12 +652,12 @@ namespace ObjectType bool checkType(PyTypeObject* type) { - return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type)) != 0; + return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF())) != 0; } bool isUserType(PyTypeObject* type) { - return checkType(type) && reinterpret_cast<SbkObjectType*>(type)->d->is_user_type; + return checkType(type) && PepType_SOTP(type)->is_user_type; } bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) @@ -673,7 +665,7 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) FindBaseTypeVisitor visitor(ctorType); walkThroughClassHierarchy(myType, &visitor); if (!visitor.found()) { - PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name); + PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", PepType(ctorType)->tp_name, PepType(myType)->tp_name); return false; } return true; @@ -681,114 +673,133 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) bool hasCast(SbkObjectType* type) { - return type->d->mi_specialcast != 0; + return PepType_SOTP(type)->mi_specialcast != 0; } void* cast(SbkObjectType* sourceType, SbkObject* obj, PyTypeObject* targetType) { - return sourceType->d->mi_specialcast(Object::cppPointer(obj, targetType), reinterpret_cast<SbkObjectType*>(targetType)); + return PepType_SOTP(sourceType)->mi_specialcast(Object::cppPointer(obj, targetType), + reinterpret_cast<SbkObjectType*>(targetType)); } void setCastFunction(SbkObjectType* type, SpecialCastFunction func) { - type->d->mi_specialcast = func; + PepType_SOTP(type)->mi_specialcast = func; } -void setOriginalName(SbkObjectType* self, const char* name) +void setOriginalName(SbkObjectType* type, const char* name) { - if (self->d->original_name) - free(self->d->original_name); - self->d->original_name = strdup(name); + SbkObjectTypePrivate *sotp = PepType_SOTP(type); + if (sotp->original_name) + free(sotp->original_name); + sotp->original_name = strdup(name); } -const char* getOriginalName(SbkObjectType* self) +const char* getOriginalName(SbkObjectType* type) { - return self->d->original_name; + return PepType_SOTP(type)->original_name; } -void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func) +void setTypeDiscoveryFunctionV2(SbkObjectType* type, TypeDiscoveryFuncV2 func) { - self->d->type_discovery = func; + PepType_SOTP(type)->type_discovery = func; } -void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other) +void copyMultimpleheritance(SbkObjectType* type, SbkObjectType* other) { - self->d->mi_init = other->d->mi_init; - self->d->mi_offsets = other->d->mi_offsets; - self->d->mi_specialcast = other->d->mi_specialcast; + PepType_SOTP(type)->mi_init = PepType_SOTP(other)->mi_init; + PepType_SOTP(type)->mi_offsets = PepType_SOTP(other)->mi_offsets; + PepType_SOTP(type)->mi_specialcast = PepType_SOTP(other)->mi_specialcast; } -void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction function) +void setMultipleInheritanceFunction(SbkObjectType* type, MultipleInheritanceInitFunction function) { - self->d->mi_init = function; + PepType_SOTP(type)->mi_init = function; } -MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self) +MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* type) { - return self->d->mi_init; + return PepType_SOTP(type)->mi_init; } -void setDestructorFunction(SbkObjectType* self, ObjectDestructor func) +void setDestructorFunction(SbkObjectType* type, ObjectDestructor func) { - self->d->cpp_dtor = func; + PepType_SOTP(type)->cpp_dtor = func; } -void initPrivateData(SbkObjectType* self) +void initPrivateData(SbkObjectType* type) { - self->d = new SbkObjectTypePrivate; - memset(self->d, 0, sizeof(SbkObjectTypePrivate)); + PepType_SOTP(type) = new SbkObjectTypePrivate; + memset(PepType_SOTP(type), 0, sizeof(SbkObjectTypePrivate)); } -bool introduceWrapperType(PyObject *enclosingObject, - const char *typeName, const char *originalName, - SbkObjectType *type, - const char *signaturesString, - ObjectDestructor cppObjDtor, - SbkObjectType *baseType, PyObject *baseTypes, - bool isInnerClass) +SbkObjectType * +introduceWrapperType(PyObject *enclosingObject, + const char *typeName, + const char *originalName, + PyType_Spec *typeSpec, + const char *signaturesString, + ObjectDestructor cppObjDtor, + SbkObjectType *baseType, + PyObject *baseTypes, + bool isInnerClass) { - initPrivateData(type); - setOriginalName(type, originalName); - setDestructorFunction(type, cppObjDtor); - if (baseType) { - type->super.ht_type.tp_base = reinterpret_cast<PyTypeObject *>(baseType); + typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType); + } + else { + typeSpec->slots[0].pfunc = reinterpret_cast<void *>(SbkObject_TypeF()); + } + PyObject *heaptype = PyType_FromSpecWithBases(typeSpec, baseTypes); + Py_TYPE(heaptype) = SbkObjectType_TypeF(); + Py_INCREF(Py_TYPE(heaptype)); + SbkObjectType *type = reinterpret_cast<SbkObjectType *>(heaptype); + if (baseType) { if (baseTypes) { for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i) BindingManager::instance().addClassInheritance(reinterpret_cast<SbkObjectType *>(PySequence_Fast_GET_ITEM(baseTypes, i)), type); - type->super.ht_type.tp_bases = baseTypes; } else { BindingManager::instance().addClassInheritance(baseType, type); } } - - // PySide-510 - // here is the single change to support signatures. + // PYSIDE-510: Here is the single change to support signatures. if (SbkSpecial_Type_Ready(enclosingObject, reinterpret_cast<PyTypeObject *>(type), signaturesString) < 0) - return false; + return nullptr; - if (isInnerClass) - return PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + initPrivateData(type); + setOriginalName(type, originalName); + setDestructorFunction(type, cppObjDtor); + + if (isInnerClass) { + if (PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0) + return type; + else + return nullptr; + } //PyModule_AddObject steals type's reference. Py_INCREF(reinterpret_cast<PyObject *>(type)); - return PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + if (PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0) { + return type; + } + return nullptr; } -void setSubTypeInitHook(SbkObjectType* self, SubTypeInitHook func) +void setSubTypeInitHook(SbkObjectType* type, SubTypeInitHook func) { - self->d->subtype_init = func; + PepType_SOTP(type)->subtype_init = func; } -void* getTypeUserData(SbkObjectType* self) +void* getTypeUserData(SbkObjectType* type) { - return self->d->user_data; + return PepType_SOTP(type)->user_data; } -void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func) +void setTypeUserData(SbkObjectType* type, void* userData, DeleteUserDataFunc d_func) { - self->d->user_data = userData; - self->d->d_func = d_func; + SbkObjectTypePrivate *sotp = PepType_SOTP(type); + sotp->user_data = userData; + sotp->d_func = d_func; } } // namespace ObjectType @@ -801,12 +812,12 @@ static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen); bool checkType(PyObject* pyObj) { - return ObjectType::checkType(pyObj->ob_type); + return ObjectType::checkType(Py_TYPE(pyObj)); } bool isUserType(PyObject* pyObj) { - return ObjectType::isUserType(pyObj->ob_type); + return ObjectType::isUserType(Py_TYPE(pyObj)); } Py_hash_t hash(PyObject* pyObj) @@ -858,14 +869,15 @@ bool wasCreatedByPython(SbkObject* pyObj) void callCppDestructors(SbkObject* pyObj) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); - if (sbkType->d->is_multicpp) { + PyTypeObject *type = Py_TYPE(pyObj); + SbkObjectTypePrivate * sotp = PepType_SOTP(type); + if (sotp->is_multicpp) { Shiboken::DtorCallerVisitor visitor(pyObj); - Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); + Shiboken::walkThroughClassHierarchy(type, &visitor); } else { Shiboken::ThreadStateSaver threadSaver; threadSaver.save(); - sbkType->d->cpp_dtor(pyObj->d->cptr[0]); + sotp->cpp_dtor(pyObj->d->cptr[0]); } /* invalidate needs to be called before deleting pointer array because @@ -916,7 +928,7 @@ void releaseOwnership(SbkObject* self) { // skip if the ownership have already moved to c++ SbkObjectType* selfType = reinterpret_cast<SbkObjectType*>(Py_TYPE(self)); - if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(selfType->d->converter)) + if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(PepType_SOTP(selfType)->converter)) return; // remove object ownership @@ -1037,7 +1049,7 @@ void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType) { PyTypeObject* type = Py_TYPE(pyObj); int idx = 0; - if (reinterpret_cast<SbkObjectType*>(type)->d->is_multicpp) + if (PepType_SOTP(reinterpret_cast<SbkObjectType*>(type))->is_multicpp) idx = getTypeIndexOnHierarchy(type, desiredType); if (pyObj->d->cptr) return pyObj->d->cptr[idx]; @@ -1057,8 +1069,9 @@ std::vector<void*> cppPointers(SbkObject* pyObj) bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) { int idx = 0; - if (reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj))->d->is_multicpp) - idx = getTypeIndexOnHierarchy(Py_TYPE(sbkObj), desiredType); + PyTypeObject *type = Py_TYPE(sbkObj); + if (PepType_SOTP(type)->is_multicpp) + idx = getTypeIndexOnHierarchy(type, desiredType); const bool alreadyInitialized = sbkObj->d->cptr[idx] != 0; if (alreadyInitialized) @@ -1073,19 +1086,21 @@ bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) bool isValid(PyObject* pyObj) { if (!pyObj || pyObj == Py_None - || Py_TYPE(pyObj->ob_type) != &SbkObjectType_Type) { + || Py_TYPE(Py_TYPE(pyObj)) != SbkObjectType_TypeF()) { return true; } SbkObjectPrivate* priv = reinterpret_cast<SbkObject*>(pyObj)->d; if (!priv->cppObjectCreated && isUserType(pyObj)) { - PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", pyObj->ob_type->tp_name); + PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } if (!priv->validCppObject) { - PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", pyObj->ob_type->tp_name); + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } @@ -1100,13 +1115,15 @@ bool isValid(SbkObject* pyObj, bool throwPyError) SbkObjectPrivate* priv = pyObj->d; if (!priv->cppObjectCreated && isUserType(reinterpret_cast<PyObject*>(pyObj))) { if (throwPyError) - PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", Py_TYPE(pyObj)->tp_name); + PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } if (!priv->validCppObject) { if (throwPyError) - PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", Py_TYPE(pyObj)->tp_name); + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } @@ -1116,7 +1133,7 @@ bool isValid(SbkObject* pyObj, bool throwPyError) bool isValid(PyObject* pyObj, bool throwPyError) { if (!pyObj || pyObj == Py_None || - !PyType_IsSubtype(pyObj->ob_type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + !PyType_IsSubtype(Py_TYPE(pyObj), reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { return true; } return isValid(reinterpret_cast<SbkObject*>(pyObj), throwPyError); @@ -1384,24 +1401,25 @@ void deallocData(SbkObject* self, bool cleanup) } delete self->d; // PYSIDE-205: always delete d. Py_XDECREF(self->ob_dict); + // PYSIDE-571: qApp is no longer allocated. - if (PyObject_IS_GC((PyObject*)self)) - Py_TYPE(self)->tp_free(self); + if (PyObject_IS_GC(reinterpret_cast<PyObject*>(self))) + PepType(Py_TYPE(self))->tp_free(self); } void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func) { - SbkObjectType* ob_type = reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper)); - if (ob_type->d->user_data) - ob_type->d->d_func(ob_type->d->user_data); + SbkObjectTypePrivate *sotp = PepType_SOTP(Py_TYPE(wrapper)); + if (sotp->user_data) + sotp->d_func(sotp->user_data); - ob_type->d->d_func = d_func; - ob_type->d->user_data = userData; + sotp->d_func = d_func; + sotp->user_data = userData; } void* getTypeUserData(SbkObject* wrapper) { - return reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper))->d->user_data; + return PepType_SOTP(Py_TYPE(wrapper))->user_data; } void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append) @@ -1483,7 +1501,7 @@ std::string info(SbkObject* self) s << "C++ address....... "; std::list<SbkObjectType*>::const_iterator it = bases.begin(); for (int i = 0; it != bases.end(); ++it, ++i) - s << reinterpret_cast<PyTypeObject *>(*it)->tp_name << '/' << self->d->cptr[i] << ' '; + s << PepType((reinterpret_cast<PyTypeObject*>(*it)))->tp_name << '/' << self->d->cptr[i] << ' '; s << "\n"; } else { diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index fc553cf8c..755058e8b 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -93,22 +93,34 @@ typedef void (*ObjectDestructor)(void*); typedef void (*SubTypeInitHook)(SbkObjectType*, PyObject*, PyObject*); -extern LIBSHIBOKEN_API PyTypeObject SbkObjectType_Type; -extern LIBSHIBOKEN_API SbkObjectType SbkObject_Type; +extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void); +extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void); struct SbkObjectTypePrivate; /// PyTypeObject extended with C++ multiple inheritance information. struct LIBSHIBOKEN_API SbkObjectType { - PyHeapTypeObject super; - SbkObjectTypePrivate* d; + PepTypeObject type; }; LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*); // the special case of a switchable singleton LIBSHIBOKEN_API PyObject* SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds); +/** + * PYSIDE-595: Use a null deallocator instead of nullptr. + * + * When moving to heaptypes, we were struck by a special default behavior of + * PyType_FromSpecWithBases that inserts subtype_dealloc when tp_dealloc is + * nullptr. To prevent inserting this, we use a null deallocator that is there + * as a placeholder. + * + * The same holds for a null tp_new. We use one that raises the right error. + */ +LIBSHIBOKEN_API void SbkDummyDealloc(PyObject*); +LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*); + } // extern "C" namespace Shiboken @@ -173,7 +185,7 @@ LIBSHIBOKEN_API const char* getOriginalName(SbkObjectType* self); LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func); LIBSHIBOKEN_API void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other); -LIBSHIBOKEN_API void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); +LIBSHIBOKEN_API void setMultipleInheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self); LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDestructor func); @@ -197,13 +209,15 @@ LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self); * wrapper type. * \returns true if the initialization went fine, false otherwise. */ -LIBSHIBOKEN_API bool introduceWrapperType(PyObject* enclosingObject, - const char* typeName, const char* originalName, - SbkObjectType* type, - const char* signaturesString, - ObjectDestructor cppObjDtor = 0, - SbkObjectType* baseType = 0, PyObject* baseTypes = 0, - bool isInnerClass = false); +LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject, + const char *typeName, + const char *originalName, + PyType_Spec *typeSpec, + const char *signaturesString, + ObjectDestructor cppObjDtor, + SbkObjectType *baseType, + PyObject *baseTypes, + bool isInnerClass); /** * Set the subtype init hook for a type. diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp index de3458ab5..5a3283ab5 100644 --- a/sources/shiboken2/libshiboken/bindingmanager.cpp +++ b/sources/shiboken2/libshiboken/bindingmanager.cpp @@ -83,8 +83,10 @@ public: SbkObjectType* node1 = i->first; const NodeList& nodeList = i->second; NodeList::const_iterator j = nodeList.begin(); - for (; j != nodeList.end(); ++j) - file << '"' << (*j)->super.ht_type.tp_name << "\" -> \"" << node1->super.ht_type.tp_name << "\"\n"; + for (; j != nodeList.end(); ++j) { + file << '"' << PepType(*j)->tp_name << "\" -> \"" + << PepType(node1)->tp_name << "\"\n"; + } } file << "}\n"; } @@ -102,7 +104,10 @@ public: return newType; } } - void* typeFound = ((type->d && type->d->type_discovery) ? type->d->type_discovery(*cptr, baseType) : 0); + void *typeFound = nullptr; + if (PepType_SOTP(type) && PepType_SOTP(type)->type_discovery) { + typeFound = PepType_SOTP(type)->type_discovery(*cptr, baseType); + } if (typeFound) { // This "typeFound != type" is needed for backwards compatibility with old modules using a newer version of // libshiboken because old versions of type_discovery function used to return a SbkObjectType* instead of @@ -111,7 +116,7 @@ public: *cptr = typeFound; return type; } else { - return 0; + return nullptr; } } }; @@ -128,7 +133,7 @@ static void showWrapperMap(const WrapperMap& wrapperMap) const SbkObject *sbkObj = iter->second; fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", iter->first, static_cast<const void *>(sbkObj), - Py_TYPE(sbkObj)->tp_name, + PepType((Py_TYPE(sbkObj)))->tp_name, int(reinterpret_cast<const PyObject *>(sbkObj)->ob_refcnt)); } fprintf(stderr, "-------------------------------\n"); @@ -210,7 +215,7 @@ bool BindingManager::hasWrapper(const void* cptr) void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) { SbkObjectType* instanceType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); - SbkObjectTypePrivate* d = instanceType->d; + SbkObjectTypePrivate* d = PepType_SOTP(instanceType); if (!d) return; @@ -231,7 +236,7 @@ void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) void BindingManager::releaseWrapper(SbkObject* sbkObj) { SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj)); - SbkObjectTypePrivate* d = sbkType->d; + SbkObjectTypePrivate* d = PepType_SOTP(sbkType); int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1); void** cptrs = reinterpret_cast<SbkObject*>(sbkObj)->d->cptr; @@ -278,17 +283,17 @@ PyObject* BindingManager::getOverride(const void* cptr, const char* methodName) PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName); if (method && PyMethod_Check(method) - && reinterpret_cast<PyMethodObject*>(method)->im_self == reinterpret_cast<PyObject*>(wrapper)) { + && PyMethod_GET_SELF(method) == reinterpret_cast<PyObject*>(wrapper)) { PyObject* defaultMethod; - PyObject* mro = Py_TYPE(wrapper)->tp_mro; + PyObject* mro = PepType(Py_TYPE(wrapper))->tp_mro; // The first class in the mro (index 0) is the class being checked and it should not be tested. // The last class in the mro (size - 1) is the base Python object class which should not be tested also. for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) { PyTypeObject* parent = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(mro, i)); - if (parent->tp_dict) { - defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); - if (defaultMethod && reinterpret_cast<PyMethodObject*>(method)->im_func != defaultMethod) { + if (PepType(parent)->tp_dict) { + defaultMethod = PyDict_GetItem(PepType(parent)->tp_dict, pyMethodName); + if (defaultMethod && PyMethod_GET_FUNCTION(method) != defaultMethod) { Py_DECREF(pyMethodName); return method; } diff --git a/sources/shiboken2/libshiboken/bufferprocs27.cpp b/sources/shiboken2/libshiboken/bufferprocs27.cpp new file mode 100644 index 000000000..168a28a96 --- /dev/null +++ b/sources/shiboken2/libshiboken/bufferprocs27.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/***************************************************************************** + * + * Copied from abstract.c + * + * Py_buffer has been replaced by Pep_buffer + * + */ + +#ifdef Py_LIMITED_API + +#include "pep384impl.h" +/* Buffer C-API for Python 3.0 */ + +int +PyObject_GetBuffer(PyObject *obj, Pep_buffer *view, int flags) +{ + PyBufferProcs *pb = PepType_AS_BUFFER(Py_TYPE(obj)); + + if (pb == NULL || pb->bf_getbuffer == NULL) { + PyErr_Format(PyExc_TypeError, + "a bytes-like object is required, not '%.100s'", + PepType((Py_TYPE(obj)))->tp_name); + return -1; + } + return (*pb->bf_getbuffer)(obj, view, flags); +} + +static int +_IsFortranContiguous(const Pep_buffer *view) +{ + Py_ssize_t sd, dim; + int i; + + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) { /* C-contiguous by definition */ + /* Trivially F-contiguous */ + if (view->ndim <= 1) return 1; + + /* ndim > 1 implies shape != NULL */ + assert(view->shape != NULL); + + /* Effectively 1-d */ + sd = 0; + for (i=0; i<view->ndim; i++) { + if (view->shape[i] > 1) sd += 1; + } + return sd <= 1; + } + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); + + sd = view->itemsize; + for (i=0; i<view->ndim; i++) { + dim = view->shape[i]; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } + sd *= dim; + } + return 1; +} + +static int +_IsCContiguous(const Pep_buffer *view) +{ + Py_ssize_t sd, dim; + int i; + + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) return 1; /* C-contiguous by definition */ + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); + + sd = view->itemsize; + for (i=view->ndim-1; i>=0; i--) { + dim = view->shape[i]; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } + sd *= dim; + } + return 1; +} + +int +PyBuffer_IsContiguous(const Pep_buffer *view, char order) +{ + + if (view->suboffsets != NULL) return 0; + + if (order == 'C') + return _IsCContiguous(view); + else if (order == 'F') + return _IsFortranContiguous(view); + else if (order == 'A') + return (_IsCContiguous(view) || _IsFortranContiguous(view)); + return 0; +} + + +void* +PyBuffer_GetPointer(Pep_buffer *view, Py_ssize_t *indices) +{ + char* pointer; + int i; + pointer = (char *)view->buf; + for (i = 0; i < view->ndim; i++) { + pointer += view->strides[i]*indices[i]; + if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) { + pointer = *((char**)pointer) + view->suboffsets[i]; + } + } + return (void*)pointer; +} + + +void +_Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape) +{ + int k; + + for (k=0; k<nd; k++) { + if (index[k] < shape[k]-1) { + index[k]++; + break; + } + else { + index[k] = 0; + } + } +} + +void +_Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape) +{ + int k; + + for (k=nd-1; k>=0; k--) { + if (index[k] < shape[k]-1) { + index[k]++; + break; + } + else { + index[k] = 0; + } + } +} + +int +PyBuffer_FromContiguous(Pep_buffer *view, void *buf, Py_ssize_t len, char fort) +{ + int k; + void (*addone)(int, Py_ssize_t *, const Py_ssize_t *); + Py_ssize_t *indices, elements; + char *src, *ptr; + + if (len > view->len) { + len = view->len; + } + + if (PyBuffer_IsContiguous(view, fort)) { + /* simplest copy is all that is needed */ + memcpy(view->buf, buf, len); + return 0; + } + + /* Otherwise a more elaborate scheme is needed */ + + /* view->ndim <= 64 */ + indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); + if (indices == NULL) { + PyErr_NoMemory(); + return -1; + } + for (k=0; k<view->ndim;k++) { + indices[k] = 0; + } + + if (fort == 'F') { + addone = _Py_add_one_to_index_F; + } + else { + addone = _Py_add_one_to_index_C; + } + src = (char *)buf; // patched by CT + /* XXX : This is not going to be the fastest code in the world + several optimizations are possible. + */ + elements = len / view->itemsize; + while (elements--) { + ptr = (char *)PyBuffer_GetPointer(view, indices); // patched by CT + memcpy(ptr, src, view->itemsize); + src += view->itemsize; + addone(view->ndim, indices, view->shape); + } + + PyMem_Free(indices); + return 0; +} + +int PyObject_CopyData(PyObject *dest, PyObject *src) +{ + Pep_buffer view_dest, view_src; + int k; + Py_ssize_t *indices, elements; + char *dptr, *sptr; + + if (!PyObject_CheckBuffer(dest) || + !PyObject_CheckBuffer(src)) { + PyErr_SetString(PyExc_TypeError, + "both destination and source must be "\ + "bytes-like objects"); + return -1; + } + + if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1; + if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) { + PyBuffer_Release(&view_dest); + return -1; + } + + if (view_dest.len < view_src.len) { + PyErr_SetString(PyExc_BufferError, + "destination is too small to receive data from source"); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return -1; + } + + if ((PyBuffer_IsContiguous(&view_dest, 'C') && + PyBuffer_IsContiguous(&view_src, 'C')) || + (PyBuffer_IsContiguous(&view_dest, 'F') && + PyBuffer_IsContiguous(&view_src, 'F'))) { + /* simplest copy is all that is needed */ + memcpy(view_dest.buf, view_src.buf, view_src.len); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return 0; + } + + /* Otherwise a more elaborate copy scheme is needed */ + + /* XXX(nnorwitz): need to check for overflow! */ + indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim); + if (indices == NULL) { + PyErr_NoMemory(); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return -1; + } + for (k=0; k<view_src.ndim;k++) { + indices[k] = 0; + } + elements = 1; + for (k=0; k<view_src.ndim; k++) { + /* XXX(nnorwitz): can this overflow? */ + elements *= view_src.shape[k]; + } + while (elements--) { + _Py_add_one_to_index_C(view_src.ndim, indices, view_src.shape); + dptr = (char *)PyBuffer_GetPointer(&view_dest, indices); // patched by CT + sptr = (char *)PyBuffer_GetPointer(&view_src, indices); // patched by CT + memcpy(dptr, sptr, view_src.itemsize); + } + PyMem_Free(indices); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return 0; +} + +void +PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape, + Py_ssize_t *strides, int itemsize, + char fort) +{ + int k; + Py_ssize_t sd; + + sd = itemsize; + if (fort == 'F') { + for (k=0; k<nd; k++) { + strides[k] = sd; + sd *= shape[k]; + } + } + else { + for (k=nd-1; k>=0; k--) { + strides[k] = sd; + sd *= shape[k]; + } + } + return; +} + +int +PyBuffer_FillInfo(Pep_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, + int readonly, int flags) +{ + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "PyBuffer_FillInfo: view==NULL argument is obsolete"); + return -1; + } + + if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && + (readonly == 1)) { + PyErr_SetString(PyExc_BufferError, + "Object is not writable."); + return -1; + } + + view->obj = obj; + if (obj) + Py_INCREF(obj); + view->buf = buf; + view->len = len; + view->readonly = readonly; + view->itemsize = 1; + view->format = NULL; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = (char *)"B"; // patched by CT + view->ndim = 1; + view->shape = NULL; + if ((flags & PyBUF_ND) == PyBUF_ND) + view->shape = &(view->len); + view->strides = NULL; + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) + view->strides = &(view->itemsize); + view->suboffsets = NULL; + view->internal = NULL; + return 0; +} + +void +PyBuffer_Release(Pep_buffer *view) +{ + PyObject *obj = view->obj; + PyBufferProcs *pb; + if (obj == NULL) + return; + pb = PepType_AS_BUFFER(Py_TYPE(obj)); + if (pb && pb->bf_releasebuffer) + pb->bf_releasebuffer(obj, view); + view->obj = NULL; + Py_DECREF(obj); +} + +#endif // Py_LIMITED_API diff --git a/sources/shiboken2/libshiboken/bufferprocs27.h b/sources/shiboken2/libshiboken/bufferprocs27.h new file mode 100644 index 000000000..83c4a4750 --- /dev/null +++ b/sources/shiboken2/libshiboken/bufferprocs27.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +PSF LICENSE AGREEMENT FOR PYTHON 3.6.5¶ +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 3.6.2 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 3.6.2 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2017 Python Software Foundation; All Rights + Reserved" are retained in Python 3.6.2 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 3.6.2 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 3.6.2. + +4. PSF is making Python 3.6.2 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 3.6.2 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.6.2 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.6.2, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 3.6.2, Licensee agrees + to be bound by the terms and conditions of this License Agreement. +*/ + +#ifndef BUFFER_REENABLE_H +#define BUFFER_REENABLE_H + +/* buffer interface */ +// This has been renamed to Pep_buffer and will be used. +typedef struct bufferinfo { + void *buf; + PyObject *obj; /* owned reference */ + Py_ssize_t len; + Py_ssize_t itemsize; /* This is Py_ssize_t so it can be + pointed to by strides in simple case.*/ + int readonly; + int ndim; + char *format; + Py_ssize_t *shape; + Py_ssize_t *strides; + Py_ssize_t *suboffsets; + void *internal; +} Pep_buffer; + +typedef int (*getbufferproc)(PyObject *, Pep_buffer *, int); +typedef void (*releasebufferproc)(PyObject *, Pep_buffer *); + +/* Maximum number of dimensions */ +#define PyBUF_MAX_NDIM 64 + +/* Flags for getting buffers */ +#define PyBUF_SIMPLE 0 +#define PyBUF_WRITABLE 0x0001 +/* we used to include an E, backwards compatible alias */ +#define PyBUF_WRITEABLE PyBUF_WRITABLE +#define PyBUF_FORMAT 0x0004 +#define PyBUF_ND 0x0008 +#define PyBUF_STRIDES (0x0010 | PyBUF_ND) +#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) +#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) +#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) +#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) + +#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) +#define PyBUF_CONTIG_RO (PyBUF_ND) + +#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) +#define PyBUF_STRIDED_RO (PyBUF_STRIDES) + +#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) + +#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) + + +#define PyBUF_READ 0x100 +#define PyBUF_WRITE 0x200 + +/* End buffer interface */ +LIBSHIBOKEN_API PyObject *PyMemoryView_FromBuffer(Pep_buffer *info); +#define Py_buffer Pep_buffer + +#endif // BUFFER_REENABLE_H diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp new file mode 100644 index 000000000..2707d3716 --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -0,0 +1,924 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pep384impl.h" + +extern "C" +{ + +/********************************************************************** + ********************************************************************** + + + The New Type API + ================ + + After converting everything but the "object.h" file, we could not + believe our eyes: it suddenly was clear that we would have no more + access to type objects, and even more scary that all types which we + use have to be heap types, only! + + For PySide with it's intense use of heap type extensions in various + flavors, it seemed to be quite unsolvable. In the end, it was + nicely solved, but it took almost 3.5 months to get that right. + + Before we see how this is done, we will explain the differences + between the APIs and their consequences. + + + The Interface + ------------- + + The old type API of Python knows static types and heap types. + Static types are written down as a declaration of a PyTypeObject + structure with all its fields filled in. Here is for example + the definition of the Python type "object": + + PyTypeObject PyBaseObject_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "object", |* tp_name *| + sizeof(PyObject), |* tp_basicsize *| + 0, |* tp_itemsize *| + object_dealloc, |* tp_dealloc *| + 0, |* tp_print *| + 0, |* tp_getattr *| + 0, |* tp_setattr *| + 0, |* tp_reserved *| + object_repr, |* tp_repr *| + 0, |* tp_as_number *| + 0, |* tp_as_sequence *| + 0, |* tp_as_mapping *| + (hashfunc)_Py_HashPointer, |* tp_hash *| + 0, |* tp_call *| + object_str, |* tp_str *| + PyObject_GenericGetAttr, |* tp_getattro *| + PyObject_GenericSetAttr, |* tp_setattro *| + 0, |* tp_as_buffer *| + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, |* tp_flags *| + PyDoc_STR("object()\n--\n\nThe most base type"), |* tp_doc *| + 0, |* tp_traverse *| + 0, |* tp_clear *| + object_richcompare, |* tp_richcompare *| + 0, |* tp_weaklistoffset *| + 0, |* tp_iter *| + 0, |* tp_iternext *| + object_methods, |* tp_methods *| + 0, |* tp_members *| + object_getsets, |* tp_getset *| + 0, |* tp_base *| + 0, |* tp_dict *| + 0, |* tp_descr_get *| + 0, |* tp_descr_set *| + 0, |* tp_dictoffset *| + object_init, |* tp_init *| + PyType_GenericAlloc, |* tp_alloc *| + object_new, |* tp_new *| + PyObject_Del, |* tp_free *| + }; + + We can write the same structure in form of a PyType_Spec structure, + and there is even a tool that does this for us, but I had to fix a + few things because there is little support for this. + + The tool is XXX go home and continue..... + + + + + The Transition To Simpler Types + =============================== + + After all code has been converted to the limited API, there is the + PyHeapTypeObject remaining as a problem. + + Why a problem? Well, all the type structures in shiboken use + special extra fields at the end of the heap type object. This + currently enforces knowledge at compile time about how large the + heap type object is. In a clean implementation, we would only use + the PyTypeObject itself and access the fields "behind" the type + by a pointer that is computed at runtime. + + + Excursion: PepTypeObject + ------------------------ + + Before we are going into details, let us motivate the existence of + the PepTypeObject, an alias to PyTypeObject: + + Originally, we wanted to use PyTypeObject as an opaque type and + restrict ourselves to only use the access function PyType_GetSlot. + This function allows access to all fields which are supported by + the limited API. + + But this is a restriction, because we get no access to tp_dict, + which we need to support the signature extension. But we can work + around that. + + The real restriction is that PyType_GetSlot only works for heap + types. This makes the function quite useless, because we have + no access to PyType_Type, which is the most important type "type" + in Python. We need that for instance to compute the size of + PyHeapTypeObject dynamically. + + With much effort, it is possible to clone PyType_Type as a heap + type. But due to a bug in the Pep 384 support, we need + access to the nb_index field of a normal type. Cloning does not + help because PyNumberMethods fields are not inherited. + + After I realized this dead end, I changed the concept and did not + use PyType_GetSlot at all (except in function copyNumberMethods), + but created PepTypeObject as a remake of PyTypeObject with only + those fields defined that are needed in PySide. + + Is this breakage of the limited API? I don't think so. A special + function runs on program startup that checks the correct position + of the fields of PepHeapType, although a change in those fields is + more than unlikely. + The really crucial thing is to no longer use PyHeapTypeObject + explicitly because that _does_ change its layout over time. + + + Diversification + --------------- + + There are multiple SbkXXX structures which all use a "d" field + for their private data. This makes it not easy to find the right + fields when switching between types and objects. + + struct LIBSHIBOKEN_API SbkObjectType + { + PyHeapTypeObject super; + SbkObjectTypePrivate *d; + }; + + struct LIBSHIBOKEN_API SbkObject + { + PyObject_HEAD + PyObject* ob_dict; + PyObject* weakreflist; + SbkObjectPrivate* d; + }; + + The first step was to rename the SbkObjectTypePrivate from "d" to + "sotp". It was chosen to be short but easy to remember. + + + Abstraction + ----------- + + After renaming the type extension pointers to "sotp", I replaced + them by function-like macros which did the special access "behind" + the types, instead of those explicit fields. For instance, the + expression + + type->sotp->converter + + became + + PepType_SOTP(type)->converter + + The macro expression can be seen here: + + #define _genericTypeExtender(etype) \ + (reinterpret_cast<char*>(etype) + \ + (reinterpret_cast<PepTypeObject*>(&PyType_Type))->tp_basicsize) + + #define PepType_SOTP(etype) \ + (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype))) + + It looks complicated, but in the end there is only a single new + indirection via PyType_Type, which happens at runtime. This is the + key to fulfil what Pep 384 wants: No version-dependent fields. + + + Simplification + -------------- + + After all type extension fields were replaced by macro calls, we + could remove the version dependent definition + + typedef struct _pepheaptypeobject { + union { + PepTypeObject ht_type; + void *opaque[PY_HEAPTYPE_SIZE]; + }; + } PepHeapTypeObject; + + and the version dependent structure + + struct LIBSHIBOKEN_API SbkObjectType + { + PepHeapTypeObject super; + SbkObjectTypePrivate *sotp; + }; + + could be replaced by the simplified + + struct LIBSHIBOKEN_API SbkObjectType + { + PepTypeObject type; + }; + + which is no longer version-dependent. + + + Verification Of PepTypeObject + ============================= + + We have introduced PepTypeObject as a new alias for PyTypeObject, + and now we need to prove that we are allowed to do so. + + When using the limited API as intended, then types are completely + opaque, and access is only through PyType_FromSpec and (from + version 3.5 upwards) through PyType_GetSlot. + + Python then uses all the slot definitions in the type description + and produces a regular type object. + + + Unused Information + ------------------ + + But we know many things about types that are not explicitly said, + but they are inherently clear: + + a) The basic structure of a type is always the same, regardless + if it is a static type or a heap type. + + b) types are evolving very slowly, and a field is never replaced + by another field with different semantics. + + Inherent rule a) gives us the following information: If we calculate + the offsets of the fields, then this info is also usable for non- + -heap types. + + The validation checks if rule b) is still valid. + + + How it Works + ------------ + + The basic idea of the validation is to produce a new type using + PyType_FromSpec and to see where in the type structure these fields + show up. So we build a PyType_Slot structure with all the fields we + are using and make sure that these values are all unique in the + type. + + Most fields are not investigated by PyType_FromSpec, and so we + simply used some numeric value. Some fields are interpreted, like + tp_members. This field must really be a PyMemberDef. And there are + tp_base and tp_bases which have to be type objects and lists + thereof. It was easiest to not produce these fields from scratch + but use them from the "type" object PyType_Type. + + Then one would think to write a function that searches the known + values in the opaque type structure. + + But we can do better and use optimistically the observation (b): + We simply use the PepTypeObject structure and assume that every + field lands exactly where we are awaiting it. + + And that is the whole proof: If we find all the disjoint values at + the places where we expect them, thenthis is q.e.d. :) + + + About tp_dict + ------------- + + One word about the tp_dict field: This field is a bit special in + the proof, since it does not appear in the spec and cannot easily + be checked by "type.__dict__" because that creates a dictproxy + object. So how do we proove that is really the right dict? + + We have to create that PyMethodDef structure anyway, and instead of + leaving it empty, we insert a dummy function. Then we ask the + tp_dict field if it has that object in it, and that's q.e.d. + + + *********/ + + +/***************************************************************************** + * + * Support for object.h + * + */ + +/* + * Here is the verification code for PepTypeObject. + * We create a type object and check if its fields + * appear at the right offsets. + */ + +#define make_dummy_int(x) (x * sizeof(void*)) +#define make_dummy(x) (reinterpret_cast<void*>(make_dummy_int(x))) + +#ifdef Py_LIMITED_API +datetime_struc *PyDateTimeAPI = NULL; +#endif + +static PyObject * +dummy_func(PyObject *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static struct PyMethodDef probe_methoddef[] = { + {"dummy", dummy_func, METH_NOARGS}, + {0} +}; + +#define probe_tp_call make_dummy(1) +#define probe_tp_str make_dummy(2) +#define probe_tp_traverse make_dummy(3) +#define probe_tp_clear make_dummy(4) +#define probe_tp_methods probe_methoddef +#define probe_tp_descr_get make_dummy(6) +#define probe_tp_init make_dummy(7) +#define probe_tp_alloc make_dummy(8) +#define probe_tp_new make_dummy(9) +#define probe_tp_free make_dummy(10) +#define probe_tp_is_gc make_dummy(11) + +#define probe_tp_name "type.probe" +#define probe_tp_basicsize make_dummy_int(42) + +static PyType_Slot typeprobe_slots[] = { + {Py_tp_call, probe_tp_call}, + {Py_tp_str, probe_tp_str}, + {Py_tp_traverse, probe_tp_traverse}, + {Py_tp_clear, probe_tp_clear}, + {Py_tp_methods, probe_tp_methods}, + {Py_tp_descr_get, probe_tp_descr_get}, + {Py_tp_init, probe_tp_init}, + {Py_tp_alloc, probe_tp_alloc}, + {Py_tp_new, probe_tp_new}, + {Py_tp_free, probe_tp_free}, + {Py_tp_is_gc, probe_tp_is_gc}, + {0, 0} +}; +static PyType_Spec typeprobe_spec = { + probe_tp_name, + probe_tp_basicsize, + 0, + Py_TPFLAGS_DEFAULT, + typeprobe_slots, +}; + +static void +check_PepTypeObject_valid(void) +{ + PyObject *obtype = reinterpret_cast<PyObject*>(&PyType_Type); + PyTypeObject *probe_tp_base = reinterpret_cast<PyTypeObject*>( + PyObject_GetAttrString(obtype, "__base__")); + PyObject *probe_tp_bases = PyObject_GetAttrString(obtype, "__bases__"); + PepTypeObject *check = reinterpret_cast<PepTypeObject*>( + PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases)); + PepTypeObject *typetype = reinterpret_cast<PepTypeObject*>(obtype); + PyObject *w = PyObject_GetAttrString(obtype, "__weakrefoffset__"); + long probe_tp_weakrefoffset = PyLong_AsLong(w); + PyObject *d = PyObject_GetAttrString(obtype, "__dictoffset__"); + long probe_tp_dictoffset = PyLong_AsLong(d); + PyObject *probe_tp_mro = PyObject_GetAttrString(obtype, "__mro__"); + if (false + || probe_tp_name != check->tp_name + || probe_tp_basicsize != check->tp_basicsize + || probe_tp_call != check->tp_call + || probe_tp_str != check->tp_str + || probe_tp_traverse != check->tp_traverse + || probe_tp_clear != check->tp_clear + || probe_tp_weakrefoffset != typetype->tp_weaklistoffset + || probe_tp_methods != check->tp_methods + || probe_tp_base != typetype->tp_base + || !PyDict_Check(check->tp_dict) + || !PyDict_GetItemString(check->tp_dict, "dummy") + || probe_tp_descr_get != check->tp_descr_get + || probe_tp_dictoffset != typetype->tp_dictoffset + || probe_tp_init != check->tp_init + || probe_tp_alloc != check->tp_alloc + || probe_tp_new != check->tp_new + || probe_tp_free != check->tp_free + || probe_tp_is_gc != check->tp_is_gc + || probe_tp_bases != typetype->tp_bases + || probe_tp_mro != typetype->tp_mro) + Py_FatalError("The structure of type objects has changed!"); + Py_DECREF(check); + Py_DECREF(probe_tp_base); + Py_DECREF(w); + Py_DECREF(d); + Py_DECREF(probe_tp_bases); + Py_DECREF(probe_tp_mro); +} + + +#ifdef Py_LIMITED_API + +// This structure is only here because Python 3 has an error. +// I will fix that. + +typedef struct { + /* Number implementations must check *both* + arguments for proper type and implement the necessary conversions + in the slot functions themselves. */ + + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_bool; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + unaryfunc nb_int; + void *nb_reserved; /* the slot formerly known as nb_long */ + unaryfunc nb_float; + + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + unaryfunc nb_index; + + binaryfunc nb_matrix_multiply; + binaryfunc nb_inplace_matrix_multiply; +} PyNumberMethods; + +// temporary structure until we have a generator for the offsets +typedef struct _oldtypeobject { + PyVarObject ob_base; + void *X01; // const char *tp_name; + void *X02; // Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + PyNumberMethods *tp_as_number; + +} PyOldTypeObject; + +// There is a bug in Python 3.6 that turned the Index_Check function +// into a macro without taking care of the limited API. +// This leads to the single problem that we don't have +// access to PyLong_Type's nb_index field which is no heap type. +// We cannot easily create this function by inheritance since it is +// not inherited. +// +// Simple solution: Create the structure and write such a function. +// Long term: Submit a patch to python.org . + +unaryfunc +PepType_nb_index(PyTypeObject *type) +{ + return reinterpret_cast<PyOldTypeObject*>(type)->tp_as_number->nb_index; +} + +int PyIndex_Check(PyObject *obj) +{ + PyOldTypeObject *type = reinterpret_cast<PyOldTypeObject*>(Py_TYPE(obj)); + return type->tp_as_number != NULL && + type->tp_as_number->nb_index != NULL; +} + +/***************************************************************************** + * + * Support for unicodeobject.h + * + */ + +char * +_PepUnicode_AsString(PyObject *str) +{ + /* + * We need to keep the string alive but cannot borrow the Python object. + * Ugly easy way out: We re-code as an interned bytes string. This + * produces a pseudo-leak as long there are new strings. + * Typically, this function is used for name strings, and the dict size + * will not grow so much. + */ +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) + + static PyObject *cstring_dict = NULL; + if (cstring_dict == NULL) { + cstring_dict = PyDict_New(); + if (cstring_dict == NULL) + Py_FatalError("Error in " AT); + } + PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", NULL); + PyObject *entry = PyDict_GetItem(cstring_dict, bytesStr); + if (entry == NULL) { + int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr); + if (e != 0) + Py_FatalError("Error in " AT); + entry = bytesStr; + } + else + Py_DECREF(bytesStr); + return PyBytes_AsString(entry); +} + +/***************************************************************************** + * + * Support for longobject.h + * + */ + +/* + * This is the original Python function _PyLong_AsInt() from longobject.c . + * We define it here because we are not allowed to use the function + * from Python with an underscore. + */ + +/* Get a C int from an int object or any object that has an __int__ + method. Return -1 and set an error if overflow occurs. */ + +int +_PepLong_AsInt(PyObject *obj) +{ + int overflow; + long result = PyLong_AsLongAndOverflow(obj, &overflow); + if (overflow || result > INT_MAX || result < INT_MIN) { + /* XXX: could be cute and give a different + message for overflow == -1 */ + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int"); + return -1; + } + return (int)result; +} + +/***************************************************************************** + * + * Support for pydebug.h + * + */ +static PyObject *sys_flags = NULL; + +int +Pep_GetFlag(const char *name) +{ + static int initialized = 0; + int ret = -1; + + if (!initialized) { + sys_flags = PySys_GetObject("flags"); + // func gives no error if NULL is returned and does not incref. + Py_XINCREF(sys_flags); + initialized = 1; + } + if (sys_flags != NULL) { + PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + } + return ret; +} + +int +Pep_GetVerboseFlag() +{ + static int initialized = 0; + static int verbose_flag = -1; + + if (!initialized) { + verbose_flag = Pep_GetFlag("verbose"); + if (verbose_flag != -1) + initialized = 1; + } + return verbose_flag; +} + +/***************************************************************************** + * + * Support for code.h + * + */ + +int +PepCode_Get(PyCodeObject *co, const char *name) +{ + PyObject *ob = (PyObject *)co; + PyObject *ob_ret; + int ret = -1; + + ob_ret = PyObject_GetAttrString(ob, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + return ret; +} + +/***************************************************************************** + * + * Support for datetime.h + * + */ + +static PyTypeObject *dt_getCheck(const char *name) +{ + PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name); + if (op == NULL) { + fprintf(stderr, "datetime.%s not found\n", name); + Py_FatalError("aborting"); + } + return (PyTypeObject *)op; +} + +// init_DateTime is called earlier than our module init. +// We use the provided PyDateTime_IMPORT machinery. +datetime_struc * +init_DateTime(void) +{ + static int initialized = 0; + if (!initialized) { + PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc)); + if (PyDateTimeAPI == NULL) + Py_FatalError("PyDateTimeAPI malloc error, aborting"); + PyDateTimeAPI->module = PyImport_ImportModule("datetime"); + if (PyDateTimeAPI->module == NULL) + Py_FatalError("datetime module not found, aborting"); + PyDateTimeAPI->DateType = dt_getCheck("date"); + PyDateTimeAPI->DateTimeType = dt_getCheck("datetime"); + PyDateTimeAPI->TimeType = dt_getCheck("time"); + PyDateTimeAPI->DeltaType = dt_getCheck("timedelta"); + PyDateTimeAPI->TZInfoType = dt_getCheck("tzinfo"); + initialized = 1; + } + return PyDateTimeAPI; +} + +int +PyDateTime_Get(PyObject *ob, const char *name) +{ + PyObject *ob_ret; + int ret = -1; + + ob_ret = PyObject_GetAttrString(ob, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + return ret; +} + +PyObject * +PyDate_FromDate(int year, int month, int day) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateType, + (char *)"(iii)", year, month, day); +} + +PyObject * +PyDateTime_FromDateAndTime(int year, int month, int day, + int hour, int min, int sec, int usec) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateTimeType, + (char *)"(iiiiiii)", year, month, day, + hour, min, sec, usec); +} + +PyObject * +PyTime_FromTime(int hour, int min, int sec, int usec) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType, + (char *)"(iiii)", hour, min, sec, usec); +} + +/***************************************************************************** + * + * Support for pythonrun.h + * + */ + +// Flags are ignored in these simple helpers. +PyObject * +PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) +{ + PyObject* code = Py_CompileString(str, "pyscript", start); + PyObject* ret = NULL; + + if (code != NULL) { + ret = PyEval_EvalCode(code, globals, locals); + } + Py_XDECREF(code); + return ret; +} + +// This is only a simple local helper that returns a computed variable. +static PyObject * +PepRun_GetResult(const char *command, const char *resvar) +{ + PyObject *d, *v, *res; + + d = PyDict_New(); + if (d == NULL || PyDict_SetItemString(d, "__builtins__", + PyEval_GetBuiltins()) < 0) + return NULL; + v = PyRun_String(command, Py_file_input, d, d); + res = v ? PyDict_GetItemString(d, resvar) : NULL; + Py_XDECREF(v); + Py_DECREF(d); + return res; +} + +/***************************************************************************** + * + * Support for classobject.h + * + */ + +PyTypeObject *PepMethod_TypePtr = NULL; + +static PyTypeObject *getMethodType(void) +{ + static const char prog[] = + "class _C:\n" + " def _m(self): pass\n" + "MethodType = type(_C()._m)\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "MethodType"); +} + +// We have no access to PyMethod_New and must call types.MethodType, instead. +PyObject * +PyMethod_New(PyObject *func, PyObject *self) +{ + return PyObject_CallFunction((PyObject *)PepMethod_TypePtr, + (char *)"(OO)", func, self); +} + +PyObject * +PyMethod_Function(PyObject *im) +{ + PyObject *ret = PyObject_GetAttrString(im, "__func__"); + + // We have to return a borrowed reference. + Py_DECREF(ret); + return ret; +} + +PyObject * +PyMethod_Self(PyObject *im) +{ + PyObject *ret = PyObject_GetAttrString(im, "__self__"); + + // We have to return a borrowed reference. + // If we don't obey that here, then we get a test error! + Py_DECREF(ret); + return ret; +} + +/***************************************************************************** + * + * Support for funcobject.h + * + */ + +PyObject * +PepFunction_Get(PyObject *ob, const char *name) +{ + PyObject *ret; + + // We have to return a borrowed reference. + ret = PyObject_GetAttrString(ob, name); + Py_XDECREF(ret); + return ret; +} + +/***************************************************************************** + * + * Support for funcobject.h + * + */ + +// this became necessary after Windows was activated. + +PyTypeObject *PepFunction_TypePtr = NULL; + +static PyTypeObject *getFunctionType(void) +{ + static const char prog[] = + "from types import FunctionType\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "FunctionType"); +} + +/***************************************************************************** + * + * Extra support for signature.cpp + * + */ + +PyTypeObject *PepStaticMethod_TypePtr = NULL; + +static PyTypeObject *getStaticMethodType(void) +{ + static const char prog[] = + "StaticMethodType = type(str.__dict__['maketrans'])\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethodType"); +} + +#endif // Py_LIMITED_API + +/***************************************************************************** + * + * Common newly needed functions + * + */ + +// The introduction of heaptypes converted many type names to the +// dotted form, since PyType_FromSpec uses it to compute the module +// name. This function reverts this effect. +const char * +PepType_GetNameStr(PyTypeObject *type) +{ + const char *ret = PepType(type)->tp_name; + const char *nodots = strrchr(ret, '.'); + if (nodots) + ret = nodots + 1; + return ret; +} + +/***************************************************************************** + * + * Module Initialization + * + */ + +void +Pep_Init() +{ + check_PepTypeObject_valid(); +#ifdef Py_LIMITED_API + Pep_GetVerboseFlag(); + PepMethod_TypePtr = getMethodType(); + PepFunction_TypePtr = getFunctionType(); + PepStaticMethod_TypePtr = getStaticMethodType(); +#endif +} + +} // extern "C" diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h new file mode 100644 index 000000000..fc0e3b40e --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -0,0 +1,571 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PEP384IMPL_H +#define PEP384IMPL_H + +#include "sbkpython.h" + +extern "C" +{ + +/***************************************************************************** + * + * RESOLVED: memoryobject.h + * + */ + +// Extracted into bufferprocs27.h +#ifdef Py_LIMITED_API +#include "bufferprocs27.h" +#endif + +/***************************************************************************** + * + * RESOLVED: object.h + * + */ +#ifdef Py_LIMITED_API +// Why the hell is this useful debugging function not allowed? +LIBSHIBOKEN_API void _PyObject_Dump(PyObject *); +#endif + +/* + * There are a few structures that are needed, but cannot be used without + * breaking the API. We use some heuristics to get those fields anyway + * and validate that we really found them, see Pepresolve.cpp . + */ + +// PepType is just a typecast that allows direct access. This is +// often better to read than the reversal via the former macro +// functions PepType_tp_xxx. +#define PepType(o) (reinterpret_cast<PepTypeObject*>(o)) + +#ifdef Py_LIMITED_API + +/* + * These are the type object fields that we use. + * We will verify that they never change. + * The unused fields are intentionally named as "void *Xnn" because + * the chance is smaller to forget to validate a field. + * When we need more fields, we replace it back and add it to the + * validation. + */ +typedef struct _peptypeobject { + PyVarObject ob_base; + const char *tp_name; + Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + void *X10; // PyNumberMethods *tp_as_number; + void *X11; // PySequenceMethods *tp_as_sequence; + void *X12; // PyMappingMethods *tp_as_mapping; + void *X13; // hashfunc tp_hash; + ternaryfunc tp_call; + reprfunc tp_str; + void *X16; // getattrofunc tp_getattro; + void *X17; // setattrofunc tp_setattro; + void *X18; // PyBufferProcs *tp_as_buffer; + void *X19; // unsigned long tp_flags; + void *X20; // const char *tp_doc; + traverseproc tp_traverse; + inquiry tp_clear; + void *X23; // richcmpfunc tp_richcompare; + Py_ssize_t tp_weaklistoffset; + void *X25; // getiterfunc tp_iter; + void *X26; // iternextfunc tp_iternext; + struct PyMethodDef *tp_methods; + void *X28; // struct PyMemberDef *tp_members; + void *X29; // struct PyGetSetDef *tp_getset; + struct _typeobject *tp_base; + PyObject *tp_dict; + descrgetfunc tp_descr_get; + void *X33; // descrsetfunc tp_descr_set; + Py_ssize_t tp_dictoffset; + initproc tp_init; + allocfunc tp_alloc; + newfunc tp_new; + freefunc tp_free; + inquiry tp_is_gc; /* For PyObject_IS_GC */ + PyObject *tp_bases; + PyObject *tp_mro; /* method resolution order */ + +} PepTypeObject; + +LIBSHIBOKEN_API unaryfunc PepType_nb_index(PyTypeObject *type); + +#undef PyIndex_Check + +LIBSHIBOKEN_API int PyIndex_Check(PyObject *obj); + +#undef PyObject_IS_GC +#define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ + ( PepType(Py_TYPE(o))->tp_is_gc == NULL || \ + PepType(Py_TYPE(o))->tp_is_gc(o) )) + +#else +#define PepTypeObject PyTypeObject +#define PepType_nb_index(o) (PepType(o)->nb_index) +#endif // Py_LIMITED_API + +struct SbkObjectTypePrivate; +struct PySideQFlagsTypePrivate; +struct _SbkGenericTypePrivate; + +#define PepHeapType_SIZE \ + (reinterpret_cast<PepTypeObject*>(&PyType_Type)->tp_basicsize) + +#define _genericTypeExtender(etype) \ + (reinterpret_cast<char*>(etype) + PepHeapType_SIZE) + +#define PepType_SOTP(etype) \ + (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype))) + +#define PepType_SETP(etype) \ + (reinterpret_cast<SbkEnumTypePrivate*>(_genericTypeExtender(etype))) + +#define PepType_PFTP(etype) \ + (reinterpret_cast<PySideQFlagsTypePrivate*>(_genericTypeExtender(etype))) + +#define PepType_SGTP(etype) \ + (reinterpret_cast<_SbkGenericTypePrivate*>(_genericTypeExtender(etype))) + +// functions used everywhere +LIBSHIBOKEN_API const char *PepType_GetNameStr(PyTypeObject *type); + +/***************************************************************************** + * + * RESOLVED: longobject.h + * + */ +#ifdef Py_LIMITED_API +LIBSHIBOKEN_API int _PepLong_AsInt(PyObject *); +#else +#define _PepLong_AsInt _PyLong_AsInt +#endif + +/***************************************************************************** + * + * RESOLVED: pydebug.h + * + */ +#ifdef Py_LIMITED_API +/* + * We have no direct access to Py_VerboseFlag because debugging is not + * supported. The python developers are partially a bit too rigorous. + * Instead, we compute the value and use a function call macro. + * Was before: extern LIBSHIBOKEN_API int Py_VerboseFlag; + */ +LIBSHIBOKEN_API int Pep_GetFlag(const char *name); +LIBSHIBOKEN_API int Pep_GetVerboseFlag(void); +#define Py_VerboseFlag Pep_GetVerboseFlag() +#endif + +/***************************************************************************** + * + * RESOLVED: unicodeobject.h + * + */ +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API char *_PepUnicode_AsString(PyObject *); + +#define PyUnicode_GET_SIZE(op) PyUnicode_GetSize((PyObject *)(op)) + +#else +#define _PepUnicode_AsString PyUnicode_AsUTF8 +#endif + +/***************************************************************************** + * + * RESOLVED: bytesobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyBytes_AS_STRING(op) PyBytes_AsString(op) +#define PyBytes_GET_SIZE(op) PyBytes_Size(op) +#endif + +/***************************************************************************** + * + * RESOLVED: floatobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyFloat_AS_DOUBLE(op) PyFloat_AsDouble(op) +#endif + +/***************************************************************************** + * + * RESOLVED: tupleobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyTuple_GET_ITEM(op, i) PyTuple_GetItem((PyObject *)op, i) +#define PyTuple_GET_SIZE(op) PyTuple_Size((PyObject *)op) +#define PyTuple_SET_ITEM(op, i, v) PyTuple_SetItem(op, i, v) +#endif + +/***************************************************************************** + * + * RESOLVED: listobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyList_GET_ITEM(op, i) PyList_GetItem(op, i) +#define PyList_SET_ITEM(op, i, v) PyList_SetItem(op, i, v) +#define PyList_GET_SIZE(op) PyList_Size(op) +#endif + +/***************************************************************************** + * + * RESOLVED: methodobject.h + * + */ + +#ifdef Py_LIMITED_API + +typedef struct _pycfunc PyCFunctionObject; +#define PyCFunction_GET_FUNCTION(func) PyCFunction_GetFunction((PyObject *)func) +#define PyCFunction_GET_SELF(func) PyCFunction_GetSelf((PyObject *)func) +#define PyCFunction_GET_FLAGS(func) PyCFunction_GetFlags((PyObject *)func) +#define PepCFunction_GET_NAMESTR(func) \ + _PepUnicode_AsString(PyObject_GetAttrString((PyObject *)func, "__name__")) +#else +#define PepCFunction_GET_NAMESTR(func) ((func)->m_ml->ml_name) +#endif + +/***************************************************************************** + * + * RESOLVED: descrobject.h + * + */ +#ifdef Py_LIMITED_API +typedef struct _methoddescr PyMethodDescrObject; +#endif + +/***************************************************************************** + * + * RESOLVED: pystate.h + * + */ + +/* + * pystate provides the data structure that is needed for the trashcan + * algorithm. Unfortunately, it is not included in the limited API. + * We have two options: + * + * (1) ignore trashcan and live without secured deeply nested structures, + * (2) maintain the structure ourselves and make sure it does not change. + * + * I have chosen the second option. + * + * When a new python version appears, you need to check compatibility of + * the PyThreadState structure (pystate.h) and the trashcan macros at the + * end of object.h . + */ + +#ifdef Py_LIMITED_API + +#define Py_TRASH_MIN_COMPATIBLE 0x03020400 +#define Py_TRASH_MAX_COMPATIBLE 0x030700A0 + +#if PY_VERSION_HEX >= Py_TRASH_MIN_COMPATIBLE && \ + PY_VERSION_HEX <= Py_TRASH_MAX_COMPATIBLE +typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); + +// This structure has the trashcan variables since Python 3.2.4. +// We renamed all but the trashcan fields to make sure that we don't use +// anything else somewhere. + +typedef struct _ts { + struct _ts *Pep_prev; + struct _ts *Pep_next; + PyInterpreterState *Pep_interp; + + struct _frame *Pep_frame; + int Pep_recursion_depth; + char Pep_overflowed; + char Pep_recursion_critical; + + int Pep_tracing; + int Pep_use_tracing; + + Py_tracefunc Pep_c_profilefunc; + Py_tracefunc Pep_c_tracefunc; + PyObject *Pep_c_profileobj; + PyObject *Pep_c_traceobj; + + PyObject *Pep_curexc_type; + PyObject *Pep_curexc_value; + PyObject *Pep_curexc_traceback; + + PyObject *Pep_exc_type; + PyObject *Pep_exc_value; + PyObject *Pep_exc_traceback; + + PyObject *Pep_dict; + + int Pep_gilstate_counter; + + PyObject *Pep_async_exc; + long Pep_thread_id; + // These two variables only are of interest to us. + int trash_delete_nesting; + PyObject *trash_delete_later; + // Here we cut away the rest of the reduced structure. +} PyThreadState; +#else +#error *** Please check compatibility of the trashcan code, see Pep.h *** +#endif + +#endif // Py_LIMITED_API + +/***************************************************************************** + * + * RESOLVED: pythonrun.h + * + */ +#ifdef Py_LIMITED_API +LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *); +#endif + +/***************************************************************************** + * + * RESOLVED: abstract.h + * + */ +#ifdef Py_LIMITED_API + +// This definition breaks the limited API a little, because it re-enables the +// buffer functions. +// But this is no problem as we check it's validity for every version. + +#define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \ + PY_VERSION_HEX < 0X0306FFFF) +#if !PYTHON_BUFFER_VERSION_COMPATIBLE +# error Please check the buffer compatibility for this python version! +#endif + +typedef struct { + getbufferproc bf_getbuffer; + releasebufferproc bf_releasebuffer; +} PyBufferProcs; + +typedef struct _Pepbuffertype { + PyVarObject ob_base; + void *skip[17]; + PyBufferProcs *tp_as_buffer; +} PepBufferType; + +#define PepType_AS_BUFFER(type) \ + reinterpret_cast<PepBufferType *>(type)->tp_as_buffer + +#define PyObject_CheckBuffer(obj) \ + ((PepType_AS_BUFFER(Py_TYPE(obj)) != NULL) && \ + (PepType_AS_BUFFER(Py_TYPE(obj))->bf_getbuffer != NULL)) + +LIBSHIBOKEN_API int PyObject_GetBuffer(PyObject *ob, Pep_buffer *view, int flags); +LIBSHIBOKEN_API void PyBuffer_Release(Pep_buffer *view); + +#else + +#define Pep_buffer Py_buffer + +#endif /* Py_LIMITED_API */ + +/***************************************************************************** + * + * RESOLVED: funcobject.h + * + */ +#ifdef Py_LIMITED_API +typedef struct _func PyFunctionObject; + +extern LIBSHIBOKEN_API PyTypeObject *PepFunction_TypePtr; +LIBSHIBOKEN_API PyObject *PepFunction_Get(PyObject *, const char *); + +#define PyFunction_Check(op) (Py_TYPE(op) == PepFunction_TypePtr) +#define PyFunction_GET_CODE(func) PyFunction_GetCode(func) + +#define PyFunction_GetCode(func) PepFunction_Get((PyObject *)func, "__code__") +#define PepFunction_GetName(func) PepFunction_Get((PyObject *)func, "__name__") +#else +#define PepFunction_GetName(func) (((PyFunctionObject *)func)->func_name) +#endif + +/***************************************************************************** + * + * RESOLVED: classobject.h + * + */ +#ifdef Py_LIMITED_API + +typedef struct _meth PyMethodObject; + +extern LIBSHIBOKEN_API PyTypeObject *PepMethod_TypePtr; + +LIBSHIBOKEN_API PyObject *PyMethod_New(PyObject *, PyObject *); +LIBSHIBOKEN_API PyObject *PyMethod_Function(PyObject *); +LIBSHIBOKEN_API PyObject *PyMethod_Self(PyObject *); + +#define PyMethod_Check(op) ((op)->ob_type == PepMethod_TypePtr) + +#define PyMethod_GET_SELF(op) PyMethod_Self(op) +#define PyMethod_GET_FUNCTION(op) PyMethod_Function(op) +#endif + +/***************************************************************************** + * + * RESOLVED: code.h + * + */ +#ifdef Py_LIMITED_API +/* Bytecode object */ + // we have to grab the code object from python +typedef struct _code PyCodeObject; + +LIBSHIBOKEN_API int PepCode_Get(PyCodeObject *co, const char *name); + +#define PepCode_GET_FLAGS(o) PepCode_Get(o, "co_flags") +#define PepCode_GET_ARGCOUNT(o) PepCode_Get(o, "co_argcount") + +/* Masks for co_flags above */ +#define CO_OPTIMIZED 0x0001 +#define CO_NEWLOCALS 0x0002 +#define CO_VARARGS 0x0004 +#define CO_VARKEYWORDS 0x0008 +#define CO_NESTED 0x0010 +#define CO_GENERATOR 0x0020 +#else +#define PepCode_GET_FLAGS(o) ((o)->co_flags) +#define PepCode_GET_ARGCOUNT(o) ((o)->co_argcount) +#endif + +/***************************************************************************** + * + * RESOLVED: datetime.h + * + */ +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API int PyDateTime_Get(PyObject *ob, const char *name); + +#define PyDateTime_GetYear(o) PyDateTime_Get(o, "year") +#define PyDateTime_GetMonth(o) PyDateTime_Get(o, "month") +#define PyDateTime_GetDay(o) PyDateTime_Get(o, "day") +#define PyDateTime_GetHour(o) PyDateTime_Get(o, "hour") +#define PyDateTime_GetMinute(o) PyDateTime_Get(o, "minute") +#define PyDateTime_GetSecond(o) PyDateTime_Get(o, "second") +#define PyDateTime_GetMicrosecond(o) PyDateTime_Get(o, "microsecond") +#define PyDateTime_GetFold(o) PyDateTime_Get(o, "fold") + +#define PyDateTime_GET_YEAR(o) PyDateTime_GetYear(o) +#define PyDateTime_GET_MONTH(o) PyDateTime_GetMonth(o) +#define PyDateTime_GET_DAY(o) PyDateTime_GetDay(o) + +#define PyDateTime_DATE_GET_HOUR(o) PyDateTime_GetHour(o) +#define PyDateTime_DATE_GET_MINUTE(o) PyDateTime_GetMinute(o) +#define PyDateTime_DATE_GET_SECOND(o) PyDateTime_GetSecond(o) +#define PyDateTime_DATE_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o) +#define PyDateTime_DATE_GET_FOLD(o) PyDateTime_GetFold(o) + +#define PyDateTime_TIME_GET_HOUR(o) PyDateTime_GetHour(o) +#define PyDateTime_TIME_GET_MINUTE(o) PyDateTime_GetMinute(o) +#define PyDateTime_TIME_GET_SECOND(o) PyDateTime_GetSecond(o) +#define PyDateTime_TIME_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o) +#define PyDateTime_TIME_GET_FOLD(o) PyDateTime_GetFold(o) + +/* Define structure slightly similar to C API. */ +typedef struct { + PyObject *module; + /* type objects */ + PyTypeObject *DateType; + PyTypeObject *DateTimeType; + PyTypeObject *TimeType; + PyTypeObject *DeltaType; + PyTypeObject *TZInfoType; +} datetime_struc; + +LIBSHIBOKEN_API datetime_struc *init_DateTime(void); + +#define PyDateTime_IMPORT PyDateTimeAPI = init_DateTime() + +extern LIBSHIBOKEN_API datetime_struc *PyDateTimeAPI; + +#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) +#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) +#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) + +LIBSHIBOKEN_API PyObject *PyDate_FromDate(int year, int month, int day); +LIBSHIBOKEN_API PyObject *PyDateTime_FromDateAndTime( + int year, int month, int day, int hour, int min, int sec, int usec); +LIBSHIBOKEN_API PyObject *PyTime_FromTime( + int hour, int minute, int second, int usecond); + +#endif /* Py_LIMITED_API */ + +/***************************************************************************** + * + * Extra support for signature.cpp + * + */ + +#ifdef Py_LIMITED_API +extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr; +#else +#define PepStaticMethod_TypePtr &PyStaticMethod_Type +#endif + +/***************************************************************************** + * + * Module Initialization + * + */ + +LIBSHIBOKEN_API void Pep_Init(void); + +} // extern "C" + +#endif // PEP384IMPL_H diff --git a/sources/shiboken2/libshiboken/python25compat.h b/sources/shiboken2/libshiboken/python25compat.h index 42f78481d..fc25aa3e5 100644 --- a/sources/shiboken2/libshiboken/python25compat.h +++ b/sources/shiboken2/libshiboken/python25compat.h @@ -39,7 +39,7 @@ #ifndef PYTHON25COMPAT_H #define PYTHON25COMPAT_H -#include <Python.h> +#include "sbkpython.h" #include <cstring> /* diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp index e6a877a32..f69d0f937 100644 --- a/sources/shiboken2/libshiboken/qapp_macro.cpp +++ b/sources/shiboken2/libshiboken/qapp_macro.cpp @@ -119,8 +119,8 @@ MakeSingletonQAppWrapper(PyTypeObject *type) if (type == NULL) type = Py_NONE_TYPE; if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) { - const char *res_name = strrchr(Py_TYPE(qApp_content)->tp_name, '.')+1; - const char *type_name = strrchr(type->tp_name, '.')+1; + const char *res_name = PepType_GetNameStr(Py_TYPE(qApp_content)); + 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 NULL; diff --git a/sources/shiboken2/libshiboken/qt_attribution.json b/sources/shiboken2/libshiboken/qt_attribution.json new file mode 100644 index 000000000..a90cc604b --- /dev/null +++ b/sources/shiboken2/libshiboken/qt_attribution.json @@ -0,0 +1,12 @@ +{ + "Id": "python", + "Name": "Python", + "QDocModule": "QtForPython", + "QtUsage": "Used for Qt for Python in the signature extension.", + "Description": "Qt for Python is an add-on for Python. The libshiboken packages of PySide uses certain parts of the source files (typespec.cpp, typespec.h, bufferprocs27.cpp, bufferprocs27.h). See the folder sources/shiboken2/libshiboken .", + "Homepage": "http://www.python.org/", + "Version": "3.6.5", + "License": "PSF LICENSE AGREEMENT FOR PYTHON 3.6.5", + "LicenseFile": "bufferprocs27.h", + "Copyright": "© Copyright 2001-2018, Python Software Foundation." +} diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp index 1646c9117..58e0b18a8 100644 --- a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp @@ -162,7 +162,7 @@ static void sequenceToCppIntArray(PyObject *pyIn, void *cppOut) { ArrayHandle<int> *handle = reinterpret_cast<ArrayHandle<int> *>(cppOut); handle->allocate(PySequence_Size(pyIn)); - convertPySequence(pyIn, _PyLong_AsInt, handle->data()); + convertPySequence(pyIn, _PepLong_AsInt, handle->data()); } static PythonToCppFunc sequenceToCppIntArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp index 64884d601..d4d3ac899 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkconverter.cpp @@ -112,6 +112,8 @@ SbkConverter *createConverterObject(PyTypeObject *type, { SbkConverter* converter = new SbkConverter; converter->pythonType = type; + // PYSIDE-595: All types are heaptypes now, so provide reference. + Py_XINCREF(type); converter->pointerToPython = pointerToPythonFunc; converter->copyToPython = copyToPythonFunc; @@ -133,7 +135,7 @@ SbkConverter* createConverter(SbkObjectType* type, createConverterObject(reinterpret_cast<PyTypeObject *>(type), toCppPointerConvFunc, toCppPointerCheckFunc, pointerToPythonFunc, copyToPythonFunc); - type->d->converter = converter; + PepType_SOTP(type)->converter = converter; return converter; } @@ -172,12 +174,12 @@ void addPythonToCppValueConversion(SbkObjectType* type, PythonToCppFunc pythonToCppFunc, IsConvertibleToCppFunc isConvertibleToCppFunc) { - addPythonToCppValueConversion(type->d->converter, pythonToCppFunc, isConvertibleToCppFunc); + addPythonToCppValueConversion(PepType_SOTP(type)->converter, pythonToCppFunc, isConvertibleToCppFunc); } -PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn) +PyObject* pointerToPython(SbkObjectType *type, const void *cppIn) { - return pointerToPython(type->d->converter, cppIn); + return pointerToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) @@ -187,15 +189,15 @@ PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) Py_RETURN_NONE; if (!converter->pointerToPython) { warning(PyExc_RuntimeWarning, 0, "pointerToPython(): SbkConverter::pointerToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->pointerToPython(cppIn); } -PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn) +PyObject* referenceToPython(SbkObjectType *type, const void *cppIn) { - return referenceToPython(type->d->converter, cppIn); + return referenceToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) @@ -209,7 +211,7 @@ PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) } if (!converter->pointerToPython) { warning(PyExc_RuntimeWarning, 0, "referenceToPython(): SbkConverter::pointerToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->pointerToPython(cppIn); @@ -221,24 +223,24 @@ static inline PyObject* CopyCppToPython(const SbkConverter *converter, const voi Py_RETURN_NONE; if (!converter->copyToPython) { warning(PyExc_RuntimeWarning, 0, "CopyCppToPython(): SbkConverter::copyToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->copyToPython(cppIn); } -PyObject* copyToPython(const SbkObjectType *type, const void *cppIn) +PyObject* copyToPython(SbkObjectType *type, const void *cppIn) { - return CopyCppToPython(type->d->converter, cppIn); + return CopyCppToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* copyToPython(const SbkConverter *converter, const void *cppIn) { return CopyCppToPython(converter, cppIn); } -PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn) { assert(pyIn); - return type->d->converter->toCppPointerConversion.first(pyIn); + return PepType_SOTP(type)->converter->toCppPointerConversion.first(pyIn); } static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) @@ -252,9 +254,9 @@ static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *conve } return 0; } -PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn) { - return IsPythonToCppConvertible(type->d->converter, pyIn); + return IsPythonToCppConvertible(PepType_SOTP(type)->converter, pyIn); } PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) { @@ -272,7 +274,7 @@ PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter, return nullptr; } -PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn) { if (pyIn != Py_None) { PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn); @@ -329,10 +331,10 @@ static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void toCpp(pyIn, cppOut); } -void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut) +void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut) { assert(type); - _pythonToCppCopy(type->d->converter, pyIn, cppOut); + _pythonToCppCopy(PepType_SOTP(type)->converter, pyIn, cppOut); } void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut) @@ -340,16 +342,16 @@ void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut _pythonToCppCopy(converter, pyIn, cppOut); } -bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) +bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc) { // This is the Object Type or Value Type conversion that only // retrieves the C++ pointer held in the Python wrapper. - if (toCppFunc == type->d->converter->toCppPointerConversion.second) + if (toCppFunc == PepType_SOTP(type)->converter->toCppPointerConversion.second) return false; // Object Types doesn't have any kind of value conversion, // only C++ pointer retrieval. - if (type->d->converter->toCppConversions.empty()) + if (PepType_SOTP(type)->converter->toCppConversions.empty()) return false; // The first conversion of the non-pointer conversion list is @@ -359,7 +361,7 @@ bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) // Note that we don't check if the Python to C++ conversion is in // the list of the type's conversions, for it is expected that the // caller knows what he's doing. - ToCppConversionList::iterator conv = type->d->converter->toCppConversions.begin(); + ToCppConversionList::iterator conv = PepType_SOTP(type)->converter->toCppConversions.begin(); return toCppFunc != (*conv).second; } @@ -411,10 +413,10 @@ bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn) } return true; } -bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn) +bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn) { assert(type); - return convertibleSequenceTypes(type->d->converter, pyIn); + return convertibleSequenceTypes(PepType_SOTP(type)->converter, pyIn); } bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn) diff --git a/sources/shiboken2/libshiboken/sbkconverter.h b/sources/shiboken2/libshiboken/sbkconverter.h index da71db5b5..0effebf57 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.h +++ b/sources/shiboken2/libshiboken/sbkconverter.h @@ -191,7 +191,7 @@ LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkObjectType* type, * TYPE* var; * PyObject* pyVar = pointerToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* pointerToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn); /** @@ -203,7 +203,7 @@ LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const v * TYPE& var = SOMETHING; * PyObject* pyVar = referenceToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* referenceToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn); /** @@ -213,7 +213,7 @@ LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const * TYPE var; * PyObject* pyVar = copyToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* copyToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* copyToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void *cppIn); // Python -> C++ --------------------------------------------------------------------------- @@ -222,7 +222,7 @@ LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn); /** * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value. @@ -230,7 +230,7 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectT * convert the object to the expected \p type. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn); /** * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference. @@ -238,7 +238,7 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectTyp * or a new C++ value if it must be a implicit conversion. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn); /// This is the same as isPythonToCppValueConvertible function. LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn); @@ -257,7 +257,7 @@ LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, voi LIBSHIBOKEN_API void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut); /// Converts a Python object \p pyIn to C++, and copies the result in the C++ variable passed in \p cppOut. -LIBSHIBOKEN_API void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut); +LIBSHIBOKEN_API void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut); LIBSHIBOKEN_API void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut); /** @@ -271,7 +271,7 @@ LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut); * It is used when C++ expects a reference argument, so it may be the same object received * from Python, or another created through implicit conversion. */ -LIBSHIBOKEN_API bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCpp); +LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCpp); /// Registers a converter with a type name that may be used to retrieve the converter. LIBSHIBOKEN_API void registerConverterName(SbkConverter* converter, const char* typeName); @@ -289,7 +289,7 @@ LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn); LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn); /// Returns true if a Python sequence is comprised of objects of a type convertible to \p type. -LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn); /// Returns true if a Python sequence can be converted to a C++ pair. LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn); @@ -394,8 +394,9 @@ template<> inline PyTypeObject* SbkType<unsigned short>() { return &PyInt_Type; #define PyObject_Check(X) true #define SbkChar_Check(X) (SbkNumber_Check(X) || Shiboken::String::checkChar(X)) -struct _SbkGenericType { PyHeapTypeObject super; SbkConverter** converter; }; -#define SBK_CONVERTER(pyType) (*reinterpret_cast<_SbkGenericType*>(pyType)->converter) +struct _SbkGenericTypePrivate { + SbkConverter** converter; +}; #endif // SBK_CONVERTER_H diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 37649f6fa..5f753293c 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -54,14 +54,18 @@ extern "C" { -struct SbkEnumType +struct SbkEnumTypePrivate { - PyHeapTypeObject super; SbkConverter** converterPtr; SbkConverter* converter; const char* cppName; }; +struct SbkEnumType +{ + PepTypeObject type; +}; + struct SbkEnumObject { PyObject_HEAD @@ -73,21 +77,9 @@ static PyObject* SbkEnumObject_repr(PyObject* self) { const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); if (enumObj->ob_name) - return Shiboken::String::fromFormat("%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); - else - return Shiboken::String::fromFormat("%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); -} - -static int SbkEnumObject_print(PyObject* self, FILE* fp, int) -{ - Py_BEGIN_ALLOW_THREADS - const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); - if (enumObj->ob_name) - fprintf(fp, "%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); + return Shiboken::String::fromFormat("%s.%s", PepType((Py_TYPE(self)))->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); else - fprintf(fp, "%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); - Py_END_ALLOW_THREADS - return 0; + return Shiboken::String::fromFormat("%s(%ld)", PepType((Py_TYPE(self)))->tp_name, enumObj->ob_value); } static PyObject* SbkEnumObject_name(PyObject* self, void*) @@ -266,114 +258,54 @@ static PyGetSetDef SbkEnumGetSetList[] = { {0, 0, 0, 0, 0} // Sentinel }; -static PyNumberMethods enum_as_number = { - /* nb_add */ enum_add, - /* nb_subtract */ enum_subtract, - /* nb_multiply */ enum_multiply, -#ifndef IS_PY3K - /* nb_divide */ enum_divide, -#endif - /* nb_remainder */ 0, - /* nb_divmod */ 0, - /* nb_power */ 0, - /* nb_negative */ 0, - /* nb_positive */ enum_int, - /* nb_absolute */ 0, - /* nb_bool/nb_nonzero */ enum_bool, - /* nb_invert */ 0, - /* nb_lshift */ 0, - /* nb_rshift */ 0, - /* nb_and */ enum_and, - /* nb_xor */ enum_xor, - /* nb_or */ enum_or, +static void SbkEnumTypeDealloc(PyObject* pyObj); +static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); + +static PyType_Slot SbkEnumType_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkEnumTypeDealloc}, + {Py_nb_add, (void *)enum_add}, + {Py_nb_subtract, (void *)enum_subtract}, + {Py_nb_multiply, (void *)enum_multiply}, #ifndef IS_PY3K - /* nb_coerce */ 0, + {Py_nb_divide, (void *)enum_divide}, #endif - /* nb_int */ enum_int, + {Py_nb_positive, (void *)enum_int}, #ifdef IS_PY3K - /* nb_reserved */ 0, - /* nb_float */ 0, + {Py_nb_bool, (void *)enum_bool}, #else - /* nb_long */ enum_int, - /* nb_float */ 0, - /* nb_oct */ 0, - /* nb_hex */ 0, -#endif - - /* nb_inplace_add */ 0, - /* nb_inplace_subtract */ 0, - /* nb_inplace_multiply */ 0, -#ifndef IS_PY3K - /* nb_inplace_div */ 0, + {Py_nb_nonzero, (void *)enum_bool}, + {Py_nb_long, (void *)enum_int}, #endif - /* nb_inplace_remainder */ 0, - /* nb_inplace_power */ 0, - /* nb_inplace_lshift */ 0, - /* nb_inplace_rshift */ 0, - /* nb_inplace_and */ 0, - /* nb_inplace_xor */ 0, - /* nb_inplace_or */ 0, - - /* nb_floor_divide */ 0, - /* nb_true_divide */ 0, - /* nb_inplace_floor_divide */ 0, - /* nb_inplace_true_divide */ 0, - - /* nb_index */ enum_int + {Py_nb_and, (void *)enum_and}, + {Py_nb_xor, (void *)enum_xor}, + {Py_nb_or, (void *)enum_or}, + {Py_nb_int, (void *)enum_int}, + {Py_nb_index, (void *)enum_int}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_new, (void *)SbkEnumTypeTpNew}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {0, 0} +}; +static PyType_Spec SbkEnumType_Type_spec = { + "Shiboken.EnumType", + 0, // filled in later + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, + SbkEnumType_Type_slots, }; -static void SbkEnumTypeDealloc(PyObject* pyObj); -static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); -PyTypeObject SbkEnumType_Type = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "Shiboken.EnumType", - /*tp_basicsize*/ sizeof(SbkEnumType), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkEnumTypeDealloc, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ &enum_as_number, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ PyType_GenericAlloc, - /*tp_new*/ SbkEnumTypeTpNew, - /*tp_free*/ PyObject_GC_Del, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}; +PyTypeObject *SbkEnumType_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + SbkEnumType_Type_spec.basicsize = + PepHeapType_SIZE + sizeof(SbkEnumTypePrivate); + type = (PyTypeObject *)PyType_FromSpec(&SbkEnumType_Type_spec); + } + return type; +} void SbkEnumTypeDealloc(PyObject* pyObj) { @@ -381,15 +313,16 @@ void SbkEnumTypeDealloc(PyObject* pyObj) PyObject_GC_UnTrack(pyObj); Py_TRASHCAN_SAFE_BEGIN(pyObj); - if (sbkType->converter) { - Shiboken::Conversions::deleteConverter(sbkType->converter); + if (PepType_SETP(sbkType)->converter) { + Shiboken::Conversions::deleteConverter(PepType_SETP(sbkType)->converter); } Py_TRASHCAN_SAFE_END(pyObj); } PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) { - SbkEnumType* newType = reinterpret_cast<SbkEnumType*>(PyType_Type.tp_new(metatype, args, kwds)); + newfunc type_new = reinterpret_cast<newfunc>(PyType_GetSlot(&PyType_Type, Py_tp_new)); + SbkEnumType *newType = reinterpret_cast<SbkEnumType*>(type_new(metatype, args, kwds)); if (!newType) return 0; return reinterpret_cast<PyObject*>(newType); @@ -417,14 +350,14 @@ namespace Enum { bool check(PyObject* pyObj) { - return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; + return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) { PyObject *key, *value; Py_ssize_t pos = 0; - PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast<char*>("values")); + PyObject *values = PyDict_GetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values")); while (PyDict_Next(values, &pos, &key, &value)) { SbkEnumObject *obj = reinterpret_cast<SbkEnumObject *>(value); @@ -438,9 +371,7 @@ PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) static PyTypeObject* createEnum(const char* fullName, const char* cppName, const char* shortName, PyTypeObject* flagsType) { - PyTypeObject* enumType = newTypeWithName(fullName, cppName); - if (flagsType) - enumType->tp_as_number = flagsType->tp_as_number; + PyTypeObject* enumType = newTypeWithName(fullName, cppName, flagsType); if (PyType_Ready(enumType) < 0) return 0; return enumType; @@ -451,7 +382,8 @@ PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* f PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); if (enumType && PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(enumType)) < 0) return 0; - if (flagsType && PyModule_AddObject(module, flagsType->tp_name, reinterpret_cast<PyObject *>(flagsType)) < 0) + if (flagsType && PyModule_AddObject(module, PepType_GetNameStr(flagsType), + reinterpret_cast<PyObject *>(flagsType)) < 0) return 0; return enumType; } @@ -459,17 +391,20 @@ PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* f PyTypeObject* createScopedEnum(SbkObjectType* scope, const char* name, const char* fullName, const char* cppName, PyTypeObject* flagsType) { PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); - if (enumType && PyDict_SetItemString(scope->super.ht_type.tp_dict, name, reinterpret_cast<PyObject *>(enumType)) < 0) - return 0; - if (flagsType && PyDict_SetItemString(scope->super.ht_type.tp_dict, flagsType->tp_name, reinterpret_cast<PyObject *>(flagsType)) < 0) - return 0; + if (enumType && PyDict_SetItemString(PepType(scope)->tp_dict, name, + reinterpret_cast<PyObject *>(enumType)) < 0) + return nullptr; + if (flagsType && PyDict_SetItemString(PepType(scope)->tp_dict, + PepType_GetNameStr(flagsType), + reinterpret_cast<PyObject *>(flagsType)) < 0) + return nullptr; return enumType; } static PyObject* createEnumItem(PyTypeObject* enumType, const char* itemName, long itemValue) { PyObject* enumItem = newItem(enumType, itemValue, itemName); - if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) + if (PyDict_SetItemString(PepType(enumType)->tp_dict, itemName, enumItem) < 0) return 0; Py_DECREF(enumItem); return enumItem; @@ -496,7 +431,7 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, const char *itemName, long itemValue) { if (PyObject *enumItem = createEnumItem(enumType, itemName, itemValue)) { - if (PyDict_SetItemString(scope->tp_dict, itemName, enumItem) < 0) + if (PyDict_SetItemString(PepType(scope)->tp_dict, itemName, enumItem) < 0) return false; Py_DECREF(enumItem); return true; @@ -506,15 +441,17 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) { - return createScopedEnumItem(enumType, &scope->super.ht_type, itemName, itemValue); + return createScopedEnumItem(enumType, reinterpret_cast<PyTypeObject *>(scope), itemName, itemValue); } -PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) +PyObject * +newItem(PyTypeObject *enumType, long itemValue, const char *itemName) { bool newValue = true; SbkEnumObject* enumObj; if (!itemName) { - enumObj = reinterpret_cast<SbkEnumObject*>(getEnumItemFromValue(enumType, itemValue)); + enumObj = reinterpret_cast<SbkEnumObject*>( + getEnumItemFromValue(enumType, itemValue)); if (enumObj) return reinterpret_cast<PyObject*>(enumObj); @@ -529,10 +466,10 @@ PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) enumObj->ob_value = itemValue; if (newValue) { - PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast<char*>("values")); + PyObject* values = PyDict_GetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values")); if (!values) { values = PyDict_New(); - PyDict_SetItemString(enumType->tp_dict, const_cast<char*>("values"), values); + PyDict_SetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values"), values); Py_DECREF(values); // ^ values still alive, because setitemstring incref it } PyDict_SetItemString(values, itemName, reinterpret_cast<PyObject*>(enumObj)); @@ -541,39 +478,140 @@ PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) return reinterpret_cast<PyObject*>(enumObj); } -PyTypeObject* newType(const char* name) -{ - return newTypeWithName(name, ""); -} +static PyType_Slot SbkNewType_slots[] = { + {Py_tp_repr, (void *)SbkEnumObject_repr}, + {Py_tp_str, (void *)SbkEnumObject_repr}, + {Py_tp_getset, (void *)SbkEnumGetSetList}, + {Py_tp_new, (void *)SbkEnum_tp_new}, + {Py_nb_add, (void *)enum_add}, + {Py_nb_subtract, (void *)enum_subtract}, + {Py_nb_multiply, (void *)enum_multiply}, +#ifndef IS_PY3K + {Py_nb_divide, (void *)enum_divide}, +#endif + {Py_nb_positive, (void *)enum_int}, +#ifdef IS_PY3K + {Py_nb_bool, (void *)enum_bool}, +#else + {Py_nb_nonzero, (void *)enum_bool}, + {Py_nb_long, (void *)enum_int}, +#endif + {Py_nb_and, (void *)enum_and}, + {Py_nb_xor, (void *)enum_xor}, + {Py_nb_or, (void *)enum_or}, + {Py_nb_int, (void *)enum_int}, + {Py_nb_index, (void *)enum_int}, + {Py_tp_richcompare, (void *)enum_richcompare}, + {Py_tp_hash, (void *)enum_hash}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec SbkNewType_spec = { + "missing Enum name", // to be inserted later + sizeof(SbkEnumObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, + SbkNewType_slots, +}; -PyTypeObject* newTypeWithName(const char* name, const char* cppName) +static void +copyNumberMethods(PyTypeObject *flagsType, + PyType_Slot number_slots[], + int *pidx) { - PyTypeObject* type = reinterpret_cast<PyTypeObject*>(new SbkEnumType); - ::memset(type, 0, sizeof(SbkEnumType)); - Py_TYPE(type) = &SbkEnumType_Type; - type->tp_basicsize = sizeof(SbkEnumObject); - type->tp_print = &SbkEnumObject_print; - type->tp_repr = &SbkEnumObject_repr; - type->tp_str = &SbkEnumObject_repr; - type->tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES; - type->tp_name = name; - type->tp_getset = SbkEnumGetSetList; - type->tp_new = SbkEnum_tp_new; - type->tp_as_number = &enum_as_number; - type->tp_richcompare = &enum_richcompare; - type->tp_hash = &enum_hash; + int idx = *pidx; +#ifdef IS_PY3K +# define SLOT slot +#else +# define SLOT slot_ +#endif +#define PUT_SLOT(name) \ + number_slots[idx].SLOT = (name); \ + number_slots[idx].pfunc = PyType_GetSlot(flagsType, (name)); \ + ++idx; + + PUT_SLOT(Py_nb_absolute); + PUT_SLOT(Py_nb_add); + PUT_SLOT(Py_nb_and); +#ifdef IS_PY3K + PUT_SLOT(Py_nb_bool); +#else + PUT_SLOT(Py_nb_nonzero); +#endif + PUT_SLOT(Py_nb_divmod); + PUT_SLOT(Py_nb_float); + PUT_SLOT(Py_nb_floor_divide); + PUT_SLOT(Py_nb_index); + PUT_SLOT(Py_nb_inplace_add); + PUT_SLOT(Py_nb_inplace_and); + PUT_SLOT(Py_nb_inplace_floor_divide); + PUT_SLOT(Py_nb_inplace_lshift); + PUT_SLOT(Py_nb_inplace_multiply); + PUT_SLOT(Py_nb_inplace_or); + PUT_SLOT(Py_nb_inplace_power); + PUT_SLOT(Py_nb_inplace_remainder); + PUT_SLOT(Py_nb_inplace_rshift); + PUT_SLOT(Py_nb_inplace_subtract); + PUT_SLOT(Py_nb_inplace_true_divide); + PUT_SLOT(Py_nb_inplace_xor); + PUT_SLOT(Py_nb_int); + PUT_SLOT(Py_nb_invert); + PUT_SLOT(Py_nb_lshift); + PUT_SLOT(Py_nb_multiply); + PUT_SLOT(Py_nb_negative); + PUT_SLOT(Py_nb_or); + PUT_SLOT(Py_nb_positive); + PUT_SLOT(Py_nb_power); + PUT_SLOT(Py_nb_remainder); + PUT_SLOT(Py_nb_rshift); + PUT_SLOT(Py_nb_subtract); + PUT_SLOT(Py_nb_true_divide); + PUT_SLOT(Py_nb_xor); +#ifndef IS_PY3K + PUT_SLOT(Py_nb_long); + PUT_SLOT(Py_nb_divide); +#endif +#undef PUT_SLOT + *pidx = idx; +} + +PyTypeObject * +newTypeWithName(const char* name, + const char* cppName, + PyTypeObject *numbers_fromFlag) +{ + // Careful: PyType_FromSpec does not allocate the string. + PyType_Slot newslots[99] = {}; // enough but not too big for the stack + PyType_Spec *newspec = new PyType_Spec; + newspec->name = strdup(name); + newspec->basicsize = SbkNewType_spec.basicsize; + newspec->itemsize = SbkNewType_spec.itemsize; + newspec->flags = SbkNewType_spec.flags; + // we must append all the number methods, so rebuild everything: + int idx = 0; + while (SbkNewType_slots[idx].SLOT) { + newslots[idx].SLOT = SbkNewType_slots[idx].SLOT; + newslots[idx].pfunc = SbkNewType_slots[idx].pfunc; + ++idx; + } + if (numbers_fromFlag) + copyNumberMethods(numbers_fromFlag, newslots, &idx); + newspec->slots = newslots; + PyTypeObject *type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(newspec)); + Py_TYPE(type) = SbkEnumType_TypeF(); + Py_INCREF(Py_TYPE(type)); SbkEnumType* enumType = reinterpret_cast<SbkEnumType*>(type); - enumType->cppName = cppName; - enumType->converterPtr = &enumType->converter; + PepType_SETP(enumType)->cppName = cppName; + PepType_SETP(enumType)->converterPtr = &PepType_SETP(enumType)->converter; DeclaredEnumTypes::instance().addEnumType(type); return type; } const char* getCppName(PyTypeObject* enumType) { - assert(Py_TYPE(enumType) == &SbkEnumType_Type); - return reinterpret_cast<SbkEnumType*>(enumType)->cppName;; + assert(Py_TYPE(enumType) == SbkEnumType_TypeF()); + return PepType_SETP(reinterpret_cast<SbkEnumType*>(enumType))->cppName; } long int getValue(PyObject* enumItem) @@ -585,13 +623,13 @@ long int getValue(PyObject* enumItem) void setTypeConverter(PyTypeObject* enumType, SbkConverter* converter) { //reinterpret_cast<SbkEnumType*>(enumType)->converter = converter; - SBK_CONVERTER(enumType) = converter; + *PepType_SGTP(enumType)->converter = converter; } SbkConverter* getTypeConverter(PyTypeObject* enumType) { //return reinterpret_cast<SbkEnumType*>(enumType)->converter; - return SBK_CONVERTER(enumType); + return *PepType_SGTP(enumType)->converter; } } // namespace Enum @@ -609,8 +647,17 @@ DeclaredEnumTypes::DeclaredEnumTypes() DeclaredEnumTypes::~DeclaredEnumTypes() { std::list<PyTypeObject*>::const_iterator it = m_enumTypes.begin(); - for (; it != m_enumTypes.end(); ++it) - delete *it; + for (; it != m_enumTypes.end(); ++it) { + /* + * PYSIDE-595: This was "delete *it;" before introducing 'PyType_FromSpec'. + * XXX what should I do now? + * Refcounts in tests are 30 or 0 at end. + * When I add the default tp_dealloc, we get negative refcounts! + * So right now I am doing nothing. Surely wrong but no crash. + * See also the comment in function 'createGlobalEnumItem'. + */ + //fprintf(stderr, "ttt %d %s\n", Py_REFCNT(*it), PepType(*it)->tp_name); + } m_enumTypes.clear(); } diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h index 4e4665423..c1ec7c4c1 100644 --- a/sources/shiboken2/libshiboken/sbkenum.h +++ b/sources/shiboken2/libshiboken/sbkenum.h @@ -46,9 +46,11 @@ extern "C" { -extern LIBSHIBOKEN_API PyTypeObject SbkEnumType_Type; +extern LIBSHIBOKEN_API PyTypeObject *SbkEnumType_TypeF(void); struct SbkObjectType; struct SbkConverter; +struct SbkEnumType; +struct SbkEnumTypePrivate; } // extern "C" @@ -57,7 +59,7 @@ namespace Shiboken inline bool isShibokenEnum(PyObject* pyObj) { - return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; + return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } namespace Enum @@ -101,9 +103,8 @@ namespace Enum LIBSHIBOKEN_API PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName = 0); - /// \deprecated Use 'newTypeWithName' - SBK_DEPRECATED(LIBSHIBOKEN_API PyTypeObject* newType(const char* name)); - LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName); + LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName, + PyTypeObject *numbers_fromFlag=nullptr); LIBSHIBOKEN_API const char* getCppName(PyTypeObject* type); LIBSHIBOKEN_API long getValue(PyObject* enumItem); diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h index 6d90f4086..5fe364a29 100644 --- a/sources/shiboken2/libshiboken/sbkpython.h +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -40,8 +40,15 @@ #ifndef SBKPYTHON_H #define SBKPYTHON_H -#include "Python.h" +#include "sbkversion.h" + +#include <Python.h> +#include <structmember.h> +// Now we have the usual variables from Python.h . #include "python25compat.h" +#include "shibokenmacros.h" +#include "pep384impl.h" +#include "typespec.h" #if PY_MAJOR_VERSION >= 3 #define IS_PY3K diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index 58f58d286..b92674383 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -108,7 +108,7 @@ const char* toCString(PyObject* str, Py_ssize_t* len) } // Return unicode from str instead of uniStr, because the lifetime of the returned pointer // depends on the lifetime of str. - return _PyUnicode_AsString(str); + return _PepUnicode_AsString(str); } #endif if (PyBytes_Check(str)) { diff --git a/sources/shiboken2/libshiboken/sbkversion.h.in b/sources/shiboken2/libshiboken/sbkversion.h.in index 447376c1b..99ee7f93e 100644 --- a/sources/shiboken2/libshiboken/sbkversion.h.in +++ b/sources/shiboken2/libshiboken/sbkversion.h.in @@ -46,5 +46,8 @@ #define SHIBOKEN_MICRO_VERSION @shiboken_MICRO_VERSION@ #define SHIBOKEN_RELEASE_LEVEL "final" #define SHIBOKEN_SERIAL 0 +#define PYTHON_VERSION_MAJOR @PYTHON_VERSION_MAJOR@ +#define PYTHON_VERSION_MINOR @PYTHON_VERSION_MINOR@ +#define PYTHON_VERSION_PATCH @PYTHON_VERSION_PATCH@ #endif diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp index 2404aeb66..05b68dade 100644 --- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp +++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp @@ -84,7 +84,9 @@ PyObject* Shiboken::Buffer::newObject(void* memory, Py_ssize_t size, Type type) view.itemsize = sizeof(char); Py_ssize_t shape[] = { size }; view.shape = shape; - return PyMemoryView_FromBuffer(&view); + // Pep384: This is way too complicated and impossible with the limited api: + //return PyMemoryView_FromBuffer(&view); + return PyMemoryView_FromMemory((char *)view.buf, size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE); #else return type == ReadOnly ? PyBuffer_FromMemory(memory, size) : PyBuffer_FromReadWriteMemory(memory, size); #endif diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index b266784c0..fc83f89cd 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -114,7 +114,7 @@ extern "C" #if EXTENSION_ENABLED // These constants were needed in former versions of the module: -#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03060000) +#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03030000) #define PYTHON_HAS_UNICODE (PY_VERSION_HEX >= 0x03000000) #define PYTHON_HAS_WEAKREF_PYCFUNCTION (PY_VERSION_HEX >= 0x030500A0) #define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000) @@ -124,15 +124,16 @@ extern "C" #define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE) #define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3) #define PYTHON_EXPOSES_METHODDESCR (PYTHON_IS_PYTHON3) +#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3 || Py_LIMITED_API) // These constants are still in use: #define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000) -#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3) typedef struct safe_globals_struc { // init part 1: get arg_dict PyObject *helper_module; PyObject *arg_dict; + PyObject *map_dict; // init part 2: run module PyObject *sigparse_func; PyObject *createsig_func; @@ -164,9 +165,9 @@ CreateSignature(PyObject *props, const char *sig_kind) } static PyObject * -pyside_cf_get___signature__(PyCFunctionObject *func) +pyside_cf_get___signature__(PyObject *func) { - return GetSignature_Function(func); + return GetSignature_Function((PyCFunctionObject *)func); } static PyObject * @@ -180,22 +181,107 @@ pyside_sm_get___signature__(PyObject *sm) return ret; } +#ifdef Py_LIMITED_API + +static int +build_qualname_to_func(PyObject *obtype) +{ + PyTypeObject *type = (PyTypeObject *)obtype; + PyMethodDef *meth = PepType(type)->tp_methods; + + if (meth == 0) + return 0; + + for (; meth->ml_name != NULL; meth++) { + PyObject *func = PyCFunction_NewEx(meth, obtype, NULL); + PyObject *qualname = PyObject_GetAttrString(func, "__qualname__"); + if (func == NULL || qualname == NULL) { + return -1; + } + if (PyDict_SetItem(pyside_globals->map_dict, qualname, func) < 0) { + return -1; + } + Py_DECREF(func); + Py_DECREF(qualname); + } + return 0; +} + static PyObject * -pyside_md_get___signature__(PyMethodDescrObject *descr) +qualname_to_typename(PyObject *qualname) { - PyCFunctionObject *func; - PyObject *result; + PyObject *func = PyObject_GetAttrString(qualname, "split"); + PyObject *list = func ? PyObject_CallFunction(func, (char *)"(s)", ".") + : NULL; + PyObject *res = list ? PyList_GetItem(list, 0) : NULL; + Py_XINCREF(res); + Py_XDECREF(func); + Py_XDECREF(list); + return res; +} + +static PyObject * +qualname_to_func(PyObject *ob) +{ + /* + * If we have __qualname__, then we can easily build a mapping + * from __qualname__ to PyCFunction. This is necessary when + * the limited API does not let us go easily from descriptor + * to PyMethodDef. + */ + PyObject *ret; + PyObject *qualname = PyObject_GetAttrString((PyObject *)ob, + "__qualname__"); + if (qualname != NULL) { + ret = PyDict_GetItem(pyside_globals->map_dict, qualname); + if (ret == NULL) { + // do a lazy initialization + PyObject *type_name = qualname_to_typename(qualname); + PyObject *type = PyDict_GetItem(pyside_globals->map_dict, + type_name); + Py_XDECREF(type_name); + if (type == NULL) + Py_RETURN_NONE; + if (build_qualname_to_func(type) < 0) + return NULL; + ret = PyDict_GetItem(pyside_globals->map_dict, qualname); + } + Py_XINCREF(ret); + Py_DECREF(qualname); + } + else + Py_RETURN_NONE; + return ret; +} +#endif - func = (PyCFunctionObject *) - PyCFunction_NewEx(descr->d_method, -#if PYTHON_USES_D_COMMON - (PyObject *)descr->d_common.d_type, NULL +static PyObject * +pyside_md_get___signature__(PyObject *ob) +{ + PyObject *func; + PyObject *result; +#ifndef Py_LIMITED_API + PyMethodDescrObject *descr = (PyMethodDescrObject *)ob; + +# if PYTHON_USES_D_COMMON + func = PyCFunction_NewEx(descr->d_method, + (PyObject *)descr->d_common.d_type, NULL); +# else + func = PyCFunction_NewEx(descr->d_method, + (PyObject *)descr->d_type, NULL); +# endif #else - (PyObject *)descr->d_type, NULL + /* + * With limited access, we cannot use the fields of a method descriptor, + * but in Python 3 we have the __qualname__ field which allows us to + * grab the method object from our registry. + */ + func = qualname_to_func(ob); #endif - ); + if (func == Py_None) + return Py_None; if (func == NULL) - return NULL; + Py_FatalError("missing mapping in MethodDescriptor"); result = pyside_cf_get___signature__(func); Py_DECREF(func); return result; @@ -215,16 +301,15 @@ GetSignature_Function(PyCFunctionObject *func) const char *sig_kind; int flags; - selftype = func->m_self; - if (selftype == NULL) { -#if PYTHON_NO_TYPE_IN_FUNCTIONS - selftype = PyDict_GetItem(pyside_globals->arg_dict, (PyObject *)func); - } + selftype = PyCFunction_GET_SELF((PyObject *)func); + if (selftype == NULL) + selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func); if (selftype == NULL) { -#endif if (!PyErr_Occurred()) { PyErr_Format(PyExc_SystemError, - "the signature for \"%s\" should exist", func->m_ml->ml_name); + "the signature for \"%s\" should exist", + PepCFunction_GET_NAMESTR(func) + ); } return NULL; } @@ -251,7 +336,7 @@ GetSignature_Function(PyCFunctionObject *func) props = PyDict_GetItem(dict, func_name); if (props == NULL) Py_RETURN_NONE; - flags = PyCFunction_GET_FLAGS(func); + flags = PyCFunction_GET_FLAGS((PyObject *)func); if (flags & METH_CLASS) sig_kind = "classmethod"; else if (flags & METH_STATIC) @@ -347,6 +432,11 @@ init_phase_1(void) goto error; Py_DECREF(v); + // build a dict for diverse mappings + p->map_dict = PyDict_New(); + if (p->map_dict == NULL) + goto error; + // Build a dict for the prepared arguments p->arg_dict = PyDict_New(); if (p->arg_dict == NULL) @@ -387,7 +477,7 @@ error: static int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp) { - PyObject *dict = type->tp_dict; + PyObject *dict = PepType(type)->tp_dict; for (; gsp->name != NULL; gsp++) { PyObject *descr; @@ -479,16 +569,17 @@ PySideType_Ready(PyTypeObject *type) // PyMethodDescr_Type 'type(str.__dict__["split"])' // PyClassMethodDescr_Type. 'type(dict.__dict__["fromkeys"])' // The latter is not needed until we use class methods in PySide. - md = PyDict_GetItemString(PyString_Type.tp_dict, "split"); + md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); if (md == NULL || PyType_Ready(Py_TYPE(md)) < 0 || add_more_getsets(Py_TYPE(md), new_PyMethodDescr_getsets) < 0 || add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0 - || add_more_getsets(&PyStaticMethod_Type, new_PyStaticMethod_getsets) < 0 + || add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0 || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0) return -1; + Py_DECREF(md); #ifndef _WIN32 - // we enable the stack trace in CI, only. + // We enable the stack trace in CI, only. const char *testEnv = getenv("QTEST_ENVIRONMENT"); if (testEnv && strstr(testEnv, "ci")) signal(SIGSEGV, handler); // install our handler @@ -498,20 +589,12 @@ PySideType_Ready(PyTypeObject *type) return PyType_Ready(type); } -#if PYTHON_NO_TYPE_IN_FUNCTIONS - -typedef struct { - PyObject_HEAD - PyObject *sm_callable; - PyObject *sm_dict; -} staticmethod; - static int build_func_to_type(PyObject *obtype) { PyTypeObject *type = (PyTypeObject *)obtype; - PyObject *dict = type->tp_dict; - PyMethodDef *meth = type->tp_methods; + PyObject *dict = PepType(type)->tp_dict; + PyMethodDef *meth = PepType(type)->tp_methods; if (meth == 0) return 0; @@ -521,19 +604,16 @@ build_func_to_type(PyObject *obtype) PyObject *descr = PyDict_GetItemString(dict, meth->ml_name); if (descr == NULL) return -1; - staticmethod *sm = (staticmethod *)descr; - PyObject *cfunc = sm->sm_callable; - if (cfunc == NULL) - return -1; - if (PyDict_SetItem(pyside_globals->arg_dict, cfunc, obtype) < 0) + PyObject *func = PyObject_GetAttrString(descr, "__func__"); + if (func == NULL || + PyDict_SetItem(pyside_globals->map_dict, func, obtype) < 0) return -1; + Py_DECREF(func); } } return 0; } -#endif - static int PySide_BuildSignatureArgs(PyObject *module, PyObject *type, const char *signatures) @@ -574,6 +654,12 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type, return -1; if (PyDict_SetItem(pyside_globals->arg_dict, type_name, arg_tup) < 0) return -1; + /* + * We record also a mapping from type name to type. This helps to lazily + * initialize the Py_LIMITED_API in qualname_to_func(). + */ + if (PyDict_SetItem(pyside_globals->map_dict, type_name, type) < 0) + return -1; return 0; } @@ -650,13 +736,16 @@ PySide_FinishSignatures(PyObject *module, const char *signatures) if (PySide_BuildSignatureArgs(module, module, signatures) < 0) return -1; -#if PYTHON_NO_TYPE_IN_FUNCTIONS /* * Python2 does not abuse the 'm_self' field for the type. So we need to * supply this for all static methods. * * Note: This function crashed when called from PySide_BuildSignatureArgs. * Probably this was too early. + * + * Pep384: We need to switch this always on since we have no access + * to the PyCFunction attributes. Therefore I simplified things + * and always use our own mapping. */ { PyObject *key, *value; @@ -668,12 +757,12 @@ PySide_FinishSignatures(PyObject *module, const char *signatures) while (PyDict_Next(dict, &pos, &key, &value)) { if (PyType_Check(value)) { - if (build_func_to_type(value) < 0) + PyObject *type = value; + if (build_func_to_type(type) < 0) return -1; } } } -#endif return 0; } #endif // EXTENSION_ENABLED diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp index 7c20b9b58..8e351cedd 100644 --- a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp @@ -180,7 +180,7 @@ void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut) { assert(pyIn); assert(cppOut); - SbkObjectType* inType = (SbkObjectType*)pyIn->ob_type; + SbkObjectType* inType = (SbkObjectType*)Py_TYPE(pyIn); if (ObjectType::hasCast(inType)) *((void**)cppOut) = ObjectType::cast(inType, (SbkObject*)pyIn, (PyTypeObject*)type); else diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h index f139a491a..cc9ea7a19 100644 --- a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h @@ -41,7 +41,7 @@ #define SBK_CONVERTER_H #include <limits> -#include <Python.h> +#include "sbkpython.h" #include "shibokenmacros.h" #include "basewrapper.h" diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp new file mode 100644 index 000000000..d532c97ed --- /dev/null +++ b/sources/shiboken2/libshiboken/typespec.cpp @@ -0,0 +1,776 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "typespec.h" +#include <structmember.h> + +#if PY_MAJOR_VERSION < 3 + +extern "C" +{ + +// for some reason python 2.7 needs this on Windows +#ifdef WIN32 +static PyGC_Head *_PyGC_generation0; +#endif + +// from pymacro.h +#ifndef Py_PYMACRO_H +#define Py_PYMACRO_H + +/* Minimum value between x and y */ +#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +/* Maximum value between x and y */ +#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +/* Absolute value of the number x */ +#define Py_ABS(x) ((x) < 0 ? -(x) : (x)) + +#define _Py_XSTRINGIFY(x) #x + +/* Convert the argument to a string. For example, Py_STRINGIFY(123) is replaced + with "123" by the preprocessor. Defines are also replaced by their value. + For example Py_STRINGIFY(__LINE__) is replaced by the line number, not + by "__LINE__". */ +#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x) + +/* Get the size of a structure member in bytes */ +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) + +/* Argument must be a char or an int in [-128, 127] or [0, 255]. */ +#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff)) + +/* Assert a build-time dependency, as an expression. + + Your compile will fail if the condition isn't true, or can't be evaluated + by the compiler. This can be used in an expression: its value is 0. + + Example: + + #define foo_to_char(foo) \ + ((char *)(foo) \ + + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) + + Written by Rusty Russell, public domain, http://ccodearchive.net/ */ +#define Py_BUILD_ASSERT_EXPR(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +#define Py_BUILD_ASSERT(cond) do { \ + (void)Py_BUILD_ASSERT_EXPR(cond); \ + } while (0) + +/* Get the number of elements in a visible array + + This does not work on pointers, or arrays declared as [], or function + parameters. With correct compiler support, such usage will cause a build + error (see Py_BUILD_ASSERT_EXPR). + + Written by Rusty Russell, public domain, http://ccodearchive.net/ + + Requires at GCC 3.1+ */ +// Simplified by "0 &&" +#if 0 && (defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ + (((__GNUC__ == 3) && (__GNU_MINOR__ >= 1)) || (__GNUC__ >= 4))) +/* Two gcc extensions. + &a[0] degrades to a pointer: a different type from an array */ +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0]) \ + + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \ + typeof(&(array)[0])))) +#else +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0])) +#endif + + +/* Define macros for inline documentation. */ +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif + +/* Below "a" is a power of 2. */ +/* Round down size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_DOWN(n, a) ((size_t)(n) & ~(size_t)((a) - 1)) +/* Round up size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_UP(n, a) (((size_t)(n) + \ + (size_t)((a) - 1)) & ~(size_t)((a) - 1)) +/* Round pointer "p" down to the closest "a"-aligned address <= "p". */ +#define _Py_ALIGN_DOWN(p, a) ((void *)((uintptr_t)(p) & ~(uintptr_t)((a) - 1))) +/* Round pointer "p" up to the closest "a"-aligned address >= "p". */ +#define _Py_ALIGN_UP(p, a) ((void *)(((uintptr_t)(p) + \ + (uintptr_t)((a) - 1)) & ~(uintptr_t)((a) - 1))) +/* Check if pointer "p" is aligned to "a"-bytes boundary. */ +#define _Py_IS_ALIGNED(p, a) (!((uintptr_t)(p) & (uintptr_t)((a) - 1))) + +#ifdef __GNUC__ +#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +#else +#define Py_UNUSED(name) _unused_ ## name +#endif + +#endif /* Py_PYMACRO_H */ + +// from typeobject.c +static int +extra_ivars(PyTypeObject *type, PyTypeObject *base) +{ + size_t t_size = type->tp_basicsize; + size_t b_size = base->tp_basicsize; + + assert(t_size >= b_size); /* Else type smaller than base! */ + if (type->tp_itemsize || base->tp_itemsize) { + /* If itemsize is involved, stricter rules */ + return t_size != b_size || + type->tp_itemsize != base->tp_itemsize; + } + if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && + type->tp_weaklistoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) + t_size -= sizeof(PyObject *); + if (type->tp_dictoffset && base->tp_dictoffset == 0 && + type->tp_dictoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) + t_size -= sizeof(PyObject *); + + return t_size != b_size; +} + +static void +clear_slots(PyTypeObject *type, PyObject *self) +{ + Py_ssize_t i, n; + PyMemberDef *mp; + + n = Py_SIZE(type); + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + *(PyObject **)addr = NULL; + Py_DECREF(obj); + } + } + } +} + +static void +subtype_dealloc(PyObject *self) +{ + PyTypeObject *type, *base; + destructor basedealloc; + PyThreadState *tstate = PyThreadState_GET(); + + /* Extract the type; we expect it to be a heap type */ + type = Py_TYPE(self); + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + + /* Test whether the type has GC exactly once */ + + if (!PyType_IS_GC(type)) { + /* It's really rare to find a dynamic type that doesn't have + GC; it can only happen when deriving from 'object' and not + adding any slots or instance variables. This allows + certain simplifications: there's no need to call + clear_slots(), or DECREF the dict, or clear weakrefs. */ + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + type->tp_del(self); + if (self->ob_refcnt > 0) + return; + } + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + assert(Py_SIZE(base) == 0); + base = base->tp_base; + assert(base); + } + + /* Extract the type again; tp_del may have changed it */ + type = Py_TYPE(self); + + /* Call the base tp_dealloc() */ + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + /* Done */ + return; + } + + /* We get here only if the type has GC */ + + /* UnTrack and re-Track around the trashcan macro, alas */ + /* See explanation at end of function for full disclosure */ + PyObject_GC_UnTrack(self); + ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; + Py_TRASHCAN_SAFE_BEGIN(self); + --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; + /* DO NOT restore GC tracking at this point. weakref callbacks + * (if any, and whether directly here or indirectly in something we + * call) may trigger GC, and if self is tracked at that point, it + * will look like trash to GC and GC will try to delete self again. + */ + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + base = base->tp_base; + assert(base); + } + + /* If we added a weaklist, we clear it. Do this *before* calling + the finalizer (__del__), clearing slots, or clearing the instance + dict. */ + + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) + PyObject_ClearWeakRefs(self); + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + _PyObject_GC_TRACK(self); + type->tp_del(self); + if (self->ob_refcnt > 0) + goto endlabel; /* resurrected */ + else + _PyObject_GC_UNTRACK(self); + /* New weakrefs could be created during the finalizer call. + If this occurs, clear them out without calling their + finalizers since they might rely on part of the object + being finalized that has already been destroyed. */ + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) { + /* Modeled after GET_WEAKREFS_LISTPTR() */ + PyWeakReference **list = (PyWeakReference **) \ + PyObject_GET_WEAKREFS_LISTPTR(self); + while (*list) + _PyWeakref_ClearRef(*list); + } + } + + /* Clear slots up to the nearest base with a different tp_dealloc */ + base = type; + while (base->tp_dealloc == subtype_dealloc) { + if (Py_SIZE(base)) + clear_slots(base, self); + base = base->tp_base; + assert(base); + } + + /* If we added a dict, DECREF it */ + if (type->tp_dictoffset && !base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict != NULL) { + Py_DECREF(dict); + *dictptr = NULL; + } + } + } + + /* Extract the type again; tp_del may have changed it */ + type = Py_TYPE(self); + + /* Call the base tp_dealloc(); first retrack self if + * basedealloc knows about gc. + */ + if (PyType_IS_GC(base)) + _PyObject_GC_TRACK(self); + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + endlabel: + ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; + Py_TRASHCAN_SAFE_END(self); + --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; + + /* Explanation of the weirdness around the trashcan macros: + + Q. What do the trashcan macros do? + + A. Read the comment titled "Trashcan mechanism" in object.h. + For one, this explains why there must be a call to GC-untrack + before the trashcan begin macro. Without understanding the + trashcan code, the answers to the following questions don't make + sense. + + Q. Why do we GC-untrack before the trashcan and then immediately + GC-track again afterward? + + A. In the case that the base class is GC-aware, the base class + probably GC-untracks the object. If it does that using the + UNTRACK macro, this will crash when the object is already + untracked. Because we don't know what the base class does, the + only safe thing is to make sure the object is tracked when we + call the base class dealloc. But... The trashcan begin macro + requires that the object is *untracked* before it is called. So + the dance becomes: + + GC untrack + trashcan begin + GC track + + Q. Why did the last question say "immediately GC-track again"? + It's nowhere near immediately. + + A. Because the code *used* to re-track immediately. Bad Idea. + self has a refcount of 0, and if gc ever gets its hands on it + (which can happen if any weakref callback gets invoked), it + looks like trash to gc too, and gc also tries to delete self + then. But we're already deleting self. Double deallocation is + a subtle disaster. + + Q. Why the bizarre (net-zero) manipulation of + _PyTrash_delete_nesting around the trashcan macros? + + A. Some base classes (e.g. list) also use the trashcan mechanism. + The following scenario used to be possible: + + - suppose the trashcan level is one below the trashcan limit + + - subtype_dealloc() is called + + - the trashcan limit is not yet reached, so the trashcan level + is incremented and the code between trashcan begin and end is + executed + + - this destroys much of the object's contents, including its + slots and __dict__ + + - basedealloc() is called; this is really list_dealloc(), or + some other type which also uses the trashcan macros + + - the trashcan limit is now reached, so the object is put on the + trashcan's to-be-deleted-later list + + - basedealloc() returns + + - subtype_dealloc() decrefs the object's type + + - subtype_dealloc() returns + + - later, the trashcan code starts deleting the objects from its + to-be-deleted-later list + + - subtype_dealloc() is called *AGAIN* for the same object + + - at the very least (if the destroyed slots and __dict__ don't + cause problems) the object's type gets decref'ed a second + time, which is *BAD*!!! + + The remedy is to make sure that if the code between trashcan + begin and end in subtype_dealloc() is called, the code between + trashcan begin and end in basedealloc() will also be called. + This is done by decrementing the level after passing into the + trashcan block, and incrementing it just before leaving the + block. + + But now it's possible that a chain of objects consisting solely + of objects whose deallocator is subtype_dealloc() will defeat + the trashcan mechanism completely: the decremented level means + that the effective level never reaches the limit. Therefore, we + *increment* the level *before* entering the trashcan block, and + matchingly decrement it after leaving. This means the trashcan + code will trigger a little early, but that's no big deal. + + Q. Are there any live examples of code in need of all this + complexity? + + A. Yes. See SF bug 668433 for code that crashed (when Python was + compiled in debug mode) before the trashcan level manipulations + were added. For more discussion, see SF patches 581742, 575073 + and bug 574207. + */ +} + +static PyTypeObject * +solid_base(PyTypeObject *type) +{ + PyTypeObject *base; + + if (type->tp_base) + base = solid_base(type->tp_base); + else + base = &PyBaseObject_Type; + if (extra_ivars(type, base)) + return type; + else + return base; +} + +/* Calculate the best base amongst multiple base classes. + This is the first one that's on the path to the "solid base". */ + +static PyTypeObject * +best_base(PyObject *bases) +{ + Py_ssize_t i, n; + PyTypeObject *base, *winner, *candidate, *base_i; + PyObject *base_proto; + + assert(PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + assert(n > 0); + base = NULL; + winner = NULL; + for (i = 0; i < n; i++) { + base_proto = PyTuple_GET_ITEM(bases, i); + if (PyClass_Check(base_proto)) + continue; + if (!PyType_Check(base_proto)) { + PyErr_SetString( + PyExc_TypeError, + "bases must be types"); + return NULL; + } + base_i = (PyTypeObject *)base_proto; + if (base_i->tp_dict == NULL) { + if (PyType_Ready(base_i) < 0) + return NULL; + } + if (!PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base_i->tp_name); + return NULL; + } + candidate = solid_base(base_i); + if (winner == NULL) { + winner = candidate; + base = base_i; + } + else if (PyType_IsSubtype(winner, candidate)) + ; + else if (PyType_IsSubtype(candidate, winner)) { + winner = candidate; + base = base_i; + } + else { + PyErr_SetString( + PyExc_TypeError, + "multiple bases have " + "instance lay-out conflict"); + return NULL; + } + } + if (base == NULL) + PyErr_SetString(PyExc_TypeError, + "a new-style class can't have only classic bases"); + return base; +} + +static const short slotoffsets[] = { + -1, /* invalid slot_ */ +/* Generated by typeslots.py */ +0, +0, +offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), +offsetof(PyHeapTypeObject, as_mapping.mp_length), +offsetof(PyHeapTypeObject, as_mapping.mp_subscript), +offsetof(PyHeapTypeObject, as_number.nb_absolute), +offsetof(PyHeapTypeObject, as_number.nb_add), +offsetof(PyHeapTypeObject, as_number.nb_and), +offsetof(PyHeapTypeObject, as_number.nb_nonzero), +offsetof(PyHeapTypeObject, as_number.nb_divmod), +offsetof(PyHeapTypeObject, as_number.nb_float), +offsetof(PyHeapTypeObject, as_number.nb_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_index), +offsetof(PyHeapTypeObject, as_number.nb_inplace_add), +offsetof(PyHeapTypeObject, as_number.nb_inplace_and), +offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply), +offsetof(PyHeapTypeObject, as_number.nb_inplace_or), +offsetof(PyHeapTypeObject, as_number.nb_inplace_power), +offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder), +offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract), +offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_xor), +offsetof(PyHeapTypeObject, as_number.nb_int), +offsetof(PyHeapTypeObject, as_number.nb_invert), +offsetof(PyHeapTypeObject, as_number.nb_lshift), +offsetof(PyHeapTypeObject, as_number.nb_multiply), +offsetof(PyHeapTypeObject, as_number.nb_negative), +offsetof(PyHeapTypeObject, as_number.nb_or), +offsetof(PyHeapTypeObject, as_number.nb_positive), +offsetof(PyHeapTypeObject, as_number.nb_power), +offsetof(PyHeapTypeObject, as_number.nb_remainder), +offsetof(PyHeapTypeObject, as_number.nb_rshift), +offsetof(PyHeapTypeObject, as_number.nb_subtract), +offsetof(PyHeapTypeObject, as_number.nb_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_xor), +offsetof(PyHeapTypeObject, as_sequence.sq_ass_item), +offsetof(PyHeapTypeObject, as_sequence.sq_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_contains), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat), +offsetof(PyHeapTypeObject, as_sequence.sq_item), +offsetof(PyHeapTypeObject, as_sequence.sq_length), +offsetof(PyHeapTypeObject, as_sequence.sq_repeat), +offsetof(PyHeapTypeObject, ht_type.tp_alloc), +offsetof(PyHeapTypeObject, ht_type.tp_base), +offsetof(PyHeapTypeObject, ht_type.tp_bases), +offsetof(PyHeapTypeObject, ht_type.tp_call), +offsetof(PyHeapTypeObject, ht_type.tp_clear), +offsetof(PyHeapTypeObject, ht_type.tp_dealloc), +offsetof(PyHeapTypeObject, ht_type.tp_del), +offsetof(PyHeapTypeObject, ht_type.tp_descr_get), +offsetof(PyHeapTypeObject, ht_type.tp_descr_set), +offsetof(PyHeapTypeObject, ht_type.tp_doc), +offsetof(PyHeapTypeObject, ht_type.tp_getattr), +offsetof(PyHeapTypeObject, ht_type.tp_getattro), +offsetof(PyHeapTypeObject, ht_type.tp_hash), +offsetof(PyHeapTypeObject, ht_type.tp_init), +offsetof(PyHeapTypeObject, ht_type.tp_is_gc), +offsetof(PyHeapTypeObject, ht_type.tp_iter), +offsetof(PyHeapTypeObject, ht_type.tp_iternext), +offsetof(PyHeapTypeObject, ht_type.tp_methods), +offsetof(PyHeapTypeObject, ht_type.tp_new), +offsetof(PyHeapTypeObject, ht_type.tp_repr), +offsetof(PyHeapTypeObject, ht_type.tp_richcompare), +offsetof(PyHeapTypeObject, ht_type.tp_setattr), +offsetof(PyHeapTypeObject, ht_type.tp_setattro), +offsetof(PyHeapTypeObject, ht_type.tp_str), +offsetof(PyHeapTypeObject, ht_type.tp_traverse), +offsetof(PyHeapTypeObject, ht_type.tp_members), +offsetof(PyHeapTypeObject, ht_type.tp_getset), +offsetof(PyHeapTypeObject, ht_type.tp_free), +offsetof(PyHeapTypeObject, as_number.nb_long), +offsetof(PyHeapTypeObject, as_number.nb_divide), +offsetof(PyHeapTypeObject, as_sequence.sq_slice), +}; + +PyObject * +PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) +{ + PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); + PyTypeObject *type, *base; + PyObject *modname; + char *s; + char *res_start = (char*)res; + PyType_Slot *slot_; + + /* Set the type name and qualname */ + s = (char *)strrchr(spec->name, '.'); // C++11 + if (s == NULL) + s = (char*)spec->name; + else + s++; + + if (res == NULL) + return NULL; + type = &res->ht_type; + /* The flags must be initialized early, before the GC traverses us */ + type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; + // was PyUnicode_FromString in Python 3 + res->ht_name = PyString_FromString(s); + if (!res->ht_name) + goto fail; + // no ht_qualname in Python 2 + // res->ht_qualname = res->ht_name; + // Py_INCREF(res->ht_qualname); + type->tp_name = spec->name; + if (!type->tp_name) + goto fail; + + /* Adjust for empty tuple bases */ + if (!bases) { + base = &PyBaseObject_Type; + /* See whether Py_tp_base(s) was specified */ + for (slot_ = spec->slots; slot_->slot_; slot_++) { + if (slot_->slot_ == Py_tp_base) + base = (PyTypeObject *)slot_->pfunc; // C++11 + else if (slot_->slot_ == Py_tp_bases) { + bases = (PyObject *)slot_->pfunc; // C++11 + Py_INCREF(bases); + } + } + if (!bases) + bases = PyTuple_Pack(1, base); + if (!bases) + goto fail; + } + else + Py_INCREF(bases); + + /* Calculate best base, and check that all bases are type objects */ + base = best_base(bases); + if (base == NULL) { + goto fail; + } + if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base->tp_name); + goto fail; + } + + /* Initialize essential fields */ + // no async in Python 2 + // type->tp_as_async = &res->as_async; + type->tp_as_number = &res->as_number; + type->tp_as_sequence = &res->as_sequence; + type->tp_as_mapping = &res->as_mapping; + type->tp_as_buffer = &res->as_buffer; + /* Set tp_base and tp_bases */ + type->tp_bases = bases; + bases = NULL; + Py_INCREF(base); + type->tp_base = base; + + type->tp_basicsize = spec->basicsize; + type->tp_itemsize = spec->itemsize; + + for (slot_ = spec->slots; slot_->slot_; slot_++) { + if (slot_->slot_ < 0 + || (size_t)slot_->slot_ >= Py_ARRAY_LENGTH(slotoffsets)) { + PyErr_SetString(PyExc_RuntimeError, "invalid slot_ offset"); + goto fail; + } + if (slot_->slot_ == Py_tp_base || slot_->slot_ == Py_tp_bases) + /* Processed above */ + continue; + *(void**)(res_start + slotoffsets[slot_->slot_]) = slot_->pfunc; + + /* need to make a copy of the docstring slot_, which usually + points to a static string literal */ + if (slot_->slot_ == Py_tp_doc) { + // No signature in Python 2 + // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot_->pfunc); + const char *old_doc = (const char *)slot_->pfunc; + size_t len = strlen(old_doc)+1; + char *tp_doc = (char *)PyObject_MALLOC(len); // C++11 + if (tp_doc == NULL) { + PyErr_NoMemory(); + goto fail; + } + memcpy(tp_doc, old_doc, len); + type->tp_doc = tp_doc; + } + } + if (type->tp_dealloc == NULL) { + /* It's a heap type, so needs the heap types' dealloc. + subtype_dealloc will call the base type's tp_dealloc, if + necessary. */ + type->tp_dealloc = subtype_dealloc; + } + + if (PyType_Ready(type) < 0) + goto fail; + + // no ht_hached_keys in Python 2 + // if (type->tp_dictoffset) { + // res->ht_cached_keys = _PyDict_NewKeysForClass(); + // } + + /* Set type.__module__ */ + s = (char *)strrchr(spec->name, '.'); // c++11 + if (s != NULL) { + int err; + // was PyUnicode_FromStringAndSize in Python 3 + modname = PyString_FromStringAndSize( + spec->name, (Py_ssize_t)(s - spec->name)); + if (modname == NULL) { + goto fail; + } + // no PyId_ things in Python 2 + // err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + err = PyDict_SetItemString(type->tp_dict, "__module__", modname); + Py_DECREF(modname); + if (err != 0) + goto fail; + } else { + // no PyErr_WarnFormat in Python 2 + // if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + // "builtin type %.200s has no __module__ attribute", + // spec->name)) + char msg[250]; + sprintf(msg, "builtin type %.200s has no __module__ attribute", spec->name); + if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) + goto fail; + } + + return (PyObject*)res; + + fail: + Py_DECREF(res); + return NULL; +} + +PyObject * +PyType_FromSpec(PyType_Spec *spec) +{ + return PyType_FromSpecWithBases(spec, NULL); +} + +void * +PyType_GetSlot(PyTypeObject *type, int slot_) +{ + if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot_ < 0) { + PyErr_BadInternalCall(); + return NULL; + } + if ((size_t)slot_ >= Py_ARRAY_LENGTH(slotoffsets)) { + /* Extension module requesting slot_ from a future version */ + return NULL; + } + return *(void**)(((char*)type) + slotoffsets[slot_]); +} + +} // extern "C" +#endif // PY_MAJOR_VERSION < 3 diff --git a/sources/shiboken2/libshiboken/typespec.h b/sources/shiboken2/libshiboken/typespec.h new file mode 100644 index 000000000..799fcb1b8 --- /dev/null +++ b/sources/shiboken2/libshiboken/typespec.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TYPESPEC_H +#define TYPESPEC_H + +#include <Python.h> +#include "shibokenmacros.h" + +#if PY_MAJOR_VERSION < 3 +extern "C" +{ + +typedef struct{ + int slot_; // slot is somehow reserved in Qt /* slot id, see below */ + void *pfunc; /* function pointer */ +} PyType_Slot; + +typedef struct{ + const char* name; + int basicsize; + int itemsize; + unsigned int flags; + PyType_Slot *slots; /* terminated by slot==0. */ +} PyType_Spec; + +LIBSHIBOKEN_API PyObject *PyType_FromSpec(PyType_Spec*); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +LIBSHIBOKEN_API PyObject *PyType_FromSpecWithBases(PyType_Spec*, PyObject*); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 +LIBSHIBOKEN_API void* PyType_GetSlot(PyTypeObject*, int); +#endif + +// from typeslots.h +/* Do not renumber the file; these numbers are part of the stable ABI. */ +/* Disabled, see #10181 */ +#undef Py_bf_getbuffer +#undef Py_bf_releasebuffer +#define Py_mp_ass_subscript 3 +#define Py_mp_length 4 +#define Py_mp_subscript 5 +#define Py_nb_absolute 6 +#define Py_nb_add 7 +#define Py_nb_and 8 +#define Py_nb_nonzero 9 +#define Py_nb_divmod 10 +#define Py_nb_float 11 +#define Py_nb_floor_divide 12 +#define Py_nb_index 13 +#define Py_nb_inplace_add 14 +#define Py_nb_inplace_and 15 +#define Py_nb_inplace_floor_divide 16 +#define Py_nb_inplace_lshift 17 +#define Py_nb_inplace_multiply 18 +#define Py_nb_inplace_or 19 +#define Py_nb_inplace_power 20 +#define Py_nb_inplace_remainder 21 +#define Py_nb_inplace_rshift 22 +#define Py_nb_inplace_subtract 23 +#define Py_nb_inplace_true_divide 24 +#define Py_nb_inplace_xor 25 +#define Py_nb_int 26 +#define Py_nb_invert 27 +#define Py_nb_lshift 28 +#define Py_nb_multiply 29 +#define Py_nb_negative 30 +#define Py_nb_or 31 +#define Py_nb_positive 32 +#define Py_nb_power 33 +#define Py_nb_remainder 34 +#define Py_nb_rshift 35 +#define Py_nb_subtract 36 +#define Py_nb_true_divide 37 +#define Py_nb_xor 38 +#define Py_sq_ass_item 39 +#define Py_sq_concat 40 +#define Py_sq_contains 41 +#define Py_sq_inplace_concat 42 +#define Py_sq_inplace_repeat 43 +#define Py_sq_item 44 +#define Py_sq_length 45 +#define Py_sq_repeat 46 +#define Py_tp_alloc 47 +#define Py_tp_base 48 +#define Py_tp_bases 49 +#define Py_tp_call 50 +#define Py_tp_clear 51 +#define Py_tp_dealloc 52 +#define Py_tp_del 53 +#define Py_tp_descr_get 54 +#define Py_tp_descr_set 55 +#define Py_tp_doc 56 +#define Py_tp_getattr 57 +#define Py_tp_getattro 58 +#define Py_tp_hash 59 +#define Py_tp_init 60 +#define Py_tp_is_gc 61 +#define Py_tp_iter 62 +#define Py_tp_iternext 63 +#define Py_tp_methods 64 +#define Py_tp_new 65 +#define Py_tp_repr 66 +#define Py_tp_richcompare 67 +#define Py_tp_setattr 68 +#define Py_tp_setattro 69 +#define Py_tp_str 70 +#define Py_tp_traverse 71 +#define Py_tp_members 72 +#define Py_tp_getset 73 +#define Py_tp_free 74 +#define Py_nb_long 75 +#define Py_nb_divide 76 +#define Py_sq_slice 77 +} // extern "C" +#endif // PY_MAJOR_VERSION < 3 +#endif // TYPESPEC_H diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index 790297595..afb3f4040 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -55,7 +55,8 @@ typedef struct { PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - SbkVoidPtrObject *self = reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc(type, 0)); + SbkVoidPtrObject *self = + reinterpret_cast<SbkVoidPtrObject *>(PepType(type)->tp_alloc); if (self != 0) { self->cptr = 0; @@ -66,7 +67,7 @@ PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwd return reinterpret_cast<PyObject *>(self); } -#define SbkVoidPtr_Check(op) (Py_TYPE(op) == &SbkVoidPtrType) +#define SbkVoidPtr_Check(op) (Py_TYPE(op) == SbkVoidPtrTypeF()) int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) @@ -168,62 +169,6 @@ PyObject *SbkVoidPtrObject_int(PyObject *v) return PyLong_FromVoidPtr(sbkObject->cptr); } -static PyNumberMethods SbkVoidPtrObjectAsNumber = { - /* nb_add */ 0, - /* nb_subtract */ 0, - /* nb_multiply */ 0, -#ifndef IS_PY3K - /* nb_divide */ 0, -#endif - /* nb_remainder */ 0, - /* nb_divmod */ 0, - /* nb_power */ 0, - /* nb_negative */ 0, - /* nb_positive */ 0, - /* nb_absolute */ 0, - /* nb_bool/nb_nonzero */ 0, - /* nb_invert */ 0, - /* nb_lshift */ 0, - /* nb_rshift */ 0, - /* nb_and */ 0, - /* nb_xor */ 0, - /* nb_or */ 0, -#ifndef IS_PY3K - /* nb_coerce */ 0, -#endif - /* nb_int */ SbkVoidPtrObject_int, -#ifdef IS_PY3K - /* nb_reserved */ 0, - /* nb_float */ 0, -#else - /* nb_long */ 0, - /* nb_float */ 0, - /* nb_oct */ 0, - /* nb_hex */ 0, -#endif - - /* nb_inplace_add */ 0, - /* nb_inplace_subtract */ 0, - /* nb_inplace_multiply */ 0, -#ifndef IS_PY3K - /* nb_inplace_div */ 0, -#endif - /* nb_inplace_remainder */ 0, - /* nb_inplace_power */ 0, - /* nb_inplace_lshift */ 0, - /* nb_inplace_rshift */ 0, - /* nb_inplace_and */ 0, - /* nb_inplace_xor */ 0, - /* nb_inplace_or */ 0, - - /* nb_floor_divide */ 0, - /* nb_true_divide */ 0, - /* nb_inplace_floor_divide */ 0, - /* nb_inplace_true_divide */ 0, - - /* nb_index */ 0 -}; - static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); @@ -235,19 +180,6 @@ static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) return sbkObject->size; } -static PySequenceMethods SbkVoidPtrObjectAsSequence = { - /* sq_length */ SbkVoidPtrObject_length, - /* sq_concat */ 0, - /* sq_repeat */ 0, - /* sq_item */ 0, - /* sq_slice */ 0, - /* sq_ass_item */ 0, - /* sq_ass_slice */ 0, - /* sq_contains */ 0, - /* sq_inplace_concat */ 0, - /* sq_inplace_repeat */ 0 -}; - static const char trueString[] = "True" ; static const char falseString[] = "False" ; @@ -257,7 +189,7 @@ PyObject *SbkVoidPtrObject_repr(PyObject *v) SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); PyObject *s = PyBytes_FromFormat("%s(%p, %zd, %s)", - Py_TYPE(sbkObject)->tp_name, + PepType((Py_TYPE(sbkObject)))->tp_name, sbkObject->cptr, sbkObject->size, sbkObject->isWritable ? trueString : falseString); @@ -269,7 +201,7 @@ PyObject *SbkVoidPtrObject_str(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); PyObject *s = PyBytes_FromFormat("%s(Address %p, Size %zd, isWritable %s)", - Py_TYPE(sbkObject)->tp_name, + PepType((Py_TYPE(sbkObject)))->tp_name, sbkObject->cptr, sbkObject->size, sbkObject->isWritable ? trueString : falseString); @@ -279,61 +211,35 @@ PyObject *SbkVoidPtrObject_str(PyObject *v) // Void pointer type definition. -PyTypeObject SbkVoidPtrType = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) /*ob_size*/ - "VoidPtr", /*tp_name*/ - sizeof(SbkVoidPtrObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - SbkVoidPtrObject_repr, /*tp_repr*/ - &SbkVoidPtrObjectAsNumber, /*tp_as_number*/ - &SbkVoidPtrObjectAsSequence, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - SbkVoidPtrObject_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Void pointer wrapper", /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - SbkVoidPtrObject_richcmp, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - SbkVoidPtrObject_init, /*tp_init*/ - 0, /*tp_alloc*/ - SbkVoidPtrObject_new, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0, /*tp_del*/ - 0, /*tp_version_tag*/ -#if PY_MAJOR_VERSION > 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4 - 0 /*tp_finalize*/ -#endif +static PyType_Slot SbkVoidPtrType_slots[] = { + {Py_tp_repr, (void *)SbkVoidPtrObject_repr}, + {Py_nb_int, (void *)SbkVoidPtrObject_int}, + {Py_sq_length, (void *)SbkVoidPtrObject_length}, + {Py_tp_str, (void *)SbkVoidPtrObject_str}, + {Py_tp_richcompare, (void *)SbkVoidPtrObject_richcmp}, + {Py_tp_init, (void *)SbkVoidPtrObject_init}, + {Py_tp_new, (void *)SbkVoidPtrObject_new}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec SbkVoidPtrType_spec = { + "shiboken2.libshiboken.VoidPtr", + sizeof(SbkVoidPtrObject), + 0, + Py_TPFLAGS_DEFAULT, + SbkVoidPtrType_slots, +}; + } +PyTypeObject *SbkVoidPtrTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&SbkVoidPtrType_spec); + return type; +} namespace VoidPtr { @@ -341,7 +247,7 @@ static int voidPointerInitialized = false; void init() { - if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkVoidPtrType)) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkVoidPtrTypeF())) < 0) Py_FatalError("[libshiboken] Failed to initialize Shiboken.VoidPtr type."); else voidPointerInitialized = true; @@ -350,9 +256,9 @@ void init() void addVoidPtrToModule(PyObject *module) { if (voidPointerInitialized) { - Py_INCREF(&SbkVoidPtrType); - PyModule_AddObject(module, SbkVoidPtrType.tp_name, - reinterpret_cast<PyObject *>(&SbkVoidPtrType)); + Py_INCREF(SbkVoidPtrTypeF()); + PyModule_AddObject(module, PepType_GetNameStr(SbkVoidPtrTypeF()), + reinterpret_cast<PyObject *>(SbkVoidPtrTypeF())); } } @@ -361,7 +267,7 @@ static PyObject *createVoidPtr(void *cppIn, Py_ssize_t size = 0, bool isWritable if (!cppIn) Py_RETURN_NONE; - SbkVoidPtrObject *result = PyObject_NEW(SbkVoidPtrObject, &SbkVoidPtrType); + SbkVoidPtrObject *result = PyObject_New(SbkVoidPtrObject, SbkVoidPtrTypeF()); if (!result) Py_RETURN_NONE; @@ -434,7 +340,7 @@ static PythonToCppFunc PythonBufferToCppIsConvertible(PyObject *pyIn) SbkConverter *createConverter() { - SbkConverter *converter = Shiboken::Conversions::createConverter(&SbkVoidPtrType, toPython); + SbkConverter *converter = Shiboken::Conversions::createConverter(SbkVoidPtrTypeF(), toPython); Shiboken::Conversions::addPythonToCppValueConversion(converter, VoidPtrToCpp, VoidPtrToCppIsConvertible); diff --git a/sources/shiboken2/libshiboken/voidptr.h b/sources/shiboken2/libshiboken/voidptr.h index 240895df8..e74c1045e 100644 --- a/sources/shiboken2/libshiboken/voidptr.h +++ b/sources/shiboken2/libshiboken/voidptr.h @@ -40,7 +40,7 @@ #ifndef VOIDPTR_H #define VOIDPTR_H -#include <Python.h> +#include "sbkpython.h" #include "shibokenmacros.h" #include "sbkconverter.h" @@ -48,7 +48,7 @@ extern "C" { // Void pointer type declaration. -extern LIBSHIBOKEN_API PyTypeObject SbkVoidPtrType; +extern LIBSHIBOKEN_API PyTypeObject *SbkVoidPtrTypeF(void); } // extern "C" diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt index 7edb0290a..b8b6417d1 100644 --- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt @@ -26,7 +26,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libminimal_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(minimal MODULE ${minimal_SRC}) set_property(TARGET minimal PROPERTY PREFIX "") set_property(TARGET minimal PROPERTY OUTPUT_NAME "minimal${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt index 7d4dd5b55..186766b41 100644 --- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt @@ -32,7 +32,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${libsample_SOURCE_DIR}/.. ${sample_BINARY_DIR} ${sample_BINARY_DIR}/sample - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(other MODULE ${other_SRC}) set_property(TARGET other PROPERTY PREFIX "") set_property(TARGET other PROPERTY OUTPUT_NAME "other${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt index 78ddfca0a..32117e44a 100644 --- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -136,7 +136,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libsample_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(sample MODULE ${sample_SRC}) set_property(TARGET sample PROPERTY PREFIX "") set_property(TARGET sample PROPERTY OUTPUT_NAME "sample${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp index 8f01b4a0a..322387088 100644 --- a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp +++ b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp @@ -33,7 +33,7 @@ extern "C" { static Py_ssize_t SbkByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) - *lenp = self->ob_type->tp_as_sequence->sq_length(self); + *lenp = Py_TYPE(self)->tp_as_sequence->sq_length(self); return 1; } static Py_ssize_t SbkByteArray_readbufferproc(PyObject* self, Py_ssize_t segment, void** ptrptr) diff --git a/sources/shiboken2/tests/samplebinding/namespace_test.py b/sources/shiboken2/tests/samplebinding/namespace_test.py index a5065c7a6..5fcdab974 100644 --- a/sources/shiboken2/tests/samplebinding/namespace_test.py +++ b/sources/shiboken2/tests/samplebinding/namespace_test.py @@ -33,12 +33,7 @@ import unittest from sample import * -from py3kcompat import IS_PY3K -if IS_PY3K: - TYPE_STR = "class" -else: - TYPE_STR = "type" class TestEnumUnderNamespace(unittest.TestCase): def testInvisibleNamespace(self): @@ -59,11 +54,16 @@ class TestClassesUnderNamespace(unittest.TestCase): self.assertEqual(res, 4) def testTpNames(self): - self.assertEqual(str(SampleNamespace.SomeClass), "<%s 'sample.SampleNamespace.SomeClass'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.ProtectedEnum'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass), + "<class 'sample.SampleNamespace.SomeClass'>") + self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), + "<class 'sample.SampleNamespace.SomeClass.ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>") if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 3cc80860d..5f0a9206b 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -1666,7 +1666,7 @@ Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning: --> <inject-code class="target" position="beginning"> - %PYTHONTYPEOBJECT.tp_str = InjectCode_tpstr; + PepType(&%PYTHONTYPEOBJECT)->tp_str = InjectCode_tpstr; </inject-code> <!-- Tested in InjectCodeTest.testFunctionTargetBeginning_FunctionTargetEnd --> @@ -2178,7 +2178,7 @@ </add-function> <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> - ByteArray b(((PyObject*)%PYSELF)->ob_type->tp_name); + ByteArray b(PepType(Py_TYPE(%PYSELF))->tp_name); PyObject* aux = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); if (PyUnicode_CheckExact(aux)) { PyObject* tmp = PyUnicode_AsASCIIString(aux); diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt index aab2121d3..faaa797b6 100644 --- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt @@ -27,7 +27,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libsmart_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(smart MODULE ${smart_SRC}) set_property(TARGET smart PROPERTY PREFIX "") set_property(TARGET smart PROPERTY OUTPUT_NAME "smart${PYTHON_EXTENSION_SUFFIX}") |