aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2')
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp131
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h5
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp3
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h3
-rw-r--r--sources/shiboken2/libshiboken/CMakeLists.txt2
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp15
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h4
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp655
-rw-r--r--sources/shiboken2/libshiboken/signature.h53
9 files changed, 852 insertions, 19 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 06300fc00..6334834d3 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -348,6 +348,8 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
QTextStream md(&methodsDefinitions);
QString singleMethodDefinitions;
QTextStream smd(&singleMethodDefinitions);
+ QString signaturesString;
+ QTextStream signatureStream(&signaturesString);
s << endl << "// Target ---------------------------------------------------------" << endl << endl;
s << "extern \"C\" {" << endl;
@@ -383,10 +385,13 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (classContext.forSmartPointer())
continue;
writeConstructorWrapper(s, overloads, classContext);
+ writeSignatureInfo(signatureStream, overloads);
}
// call operators
- else if (rfunc->name() == QLatin1String("operator()"))
+ else if (rfunc->name() == QLatin1String("operator()")) {
writeMethodWrapper(s, overloads, classContext);
+ writeSignatureInfo(signatureStream, overloads);
+ }
else if (!rfunc->isOperatorOverload()) {
if (classContext.forSmartPointer()) {
@@ -417,6 +422,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
}
writeMethodWrapper(s, overloads, classContext);
+ writeSignatureInfo(signatureStream, overloads);
if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
QString methDefName = cpythonMethodDefinitionName(rfunc);
smd << "static PyMethodDef " << methDefName << " = {" << endl;
@@ -431,8 +437,10 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
QString className = cpythonTypeName(metaClass);
className.remove(QRegExp(QLatin1String("_Type$")));
- if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer())
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
writeCopyFunction(s, classContext);
+ signatureStream << INDENT << metaClass->fullName() << ".__copy__()" << endl;
+ }
// Write single method definitions
s << singleMethodDefinitions;
@@ -495,6 +503,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
continue;
writeMethodWrapper(s, overloads, classContext);
+ writeSignatureInfo(signatureStream, overloads);
}
}
@@ -567,7 +576,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
s << endl;
writeConverterFunctions(s, metaClass, classContext);
- writeClassRegister(s, metaClass, classContext);
+ writeClassRegister(s, metaClass, classContext, signatureStream);
// class inject-code native/end
if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
@@ -1976,7 +1985,7 @@ void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData)
strArg = QLatin1String("str");
else if (strArg == QLatin1String("PyBytes"))
strArg = QLatin1String("\" SBK_STR_NAME \"");
- else if (strArg == QLatin1String("PySequece"))
+ else if (strArg == QLatin1String("PySequence"))
strArg = QLatin1String("list");
else if (strArg == QLatin1String("PyTuple"))
strArg = QLatin1String("tuple");
@@ -4302,6 +4311,69 @@ void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunct
s << ',' << endl;
}
+static QString resolveRetOrArgType(const AbstractMetaType *someType)
+{
+ QString strRetArg;
+ if (CppGenerator::isCString(someType)) {
+ strRetArg = QLatin1String("str");
+ } else if (someType->isPrimitive()) {
+ const PrimitiveTypeEntry* ptp = static_cast<const PrimitiveTypeEntry*>(someType->typeEntry());
+ while (ptp->referencedTypeEntry())
+ ptp = ptp->referencedTypeEntry();
+ strRetArg = ptp->name();
+ } else {
+ strRetArg = someType->fullName();
+ }
+ strRetArg.replace(QLatin1String("::"), QLatin1String("."));
+ return strRetArg;
+}
+
+void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads)
+{
+ OverloadData overloadData(overloads, this);
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ QString funcName = fullPythonFunctionName(rfunc);
+
+ int idx = overloads.length() - 1;
+ bool multiple = idx > 0;
+
+// after merging, the #if may be removed!
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+ for (const AbstractMetaFunction *f : overloads) {
+ QStringList args;
+ const AbstractMetaArgumentList &arguments = f->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+#else
+ foreach (const AbstractMetaFunction *f, overloads) {
+ QStringList args;
+ const AbstractMetaArgumentList &arguments = f->arguments();
+ foreach (const AbstractMetaArgument *arg, arguments) {
+#endif
+ QString strArg = resolveRetOrArgType(arg->type());
+ if (!arg->defaultValueExpression().isEmpty()) {
+ strArg += QLatin1Char('=');
+ QString e = arg->defaultValueExpression();
+ e.replace(QLatin1String("::"), QLatin1String("."));
+ // the tests insert stuff like Str("<unknown>"):
+ e.replace(QLatin1Char('"'), QLatin1String("\\\""));
+ strArg += e;
+ }
+ args << arg->name() + QLatin1Char(':') + strArg;
+ }
+ s << INDENT;
+ // mark the multiple signatures as such, to make it easier to generate different code
+ if (multiple)
+ s << idx-- << ':';
+ // now calculate the return type.
+ s << funcName << '(' << args.join(QLatin1Char(',')) << ')';
+ AbstractMetaType *returnType = getTypeWithoutContainer(f->type());
+ if (returnType) {
+ s << "->" << resolveRetOrArgType(returnType);
+ }
+ s << endl;
+ }
+}
+
void CppGenerator::writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums)
{
if (enums.isEmpty())
@@ -4604,7 +4676,8 @@ QString CppGenerator::getInitFunctionName(GeneratorContext &context) const
void CppGenerator::writeClassRegister(QTextStream &s,
const AbstractMetaClass *metaClass,
- GeneratorContext &classContext)
+ GeneratorContext &classContext,
+ QTextStream &signatureStream)
{
const ComplexTypeEntry* classTypeEntry = metaClass->typeEntry();
@@ -4614,6 +4687,21 @@ void CppGenerator::writeClassRegister(QTextStream &s,
QString pyTypeName = cpythonTypeName(metaClass);
QString initFunctionName = getInitFunctionName(classContext);
+
+ // PYSIDE-510: Create a signatures string for the introspection feature.
+ s << "// The signatures string for the functions." << endl;
+ s << "// Multiple signatures have their index \"n:\" in front." << endl;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+ s << "const char " << initFunctionName << "_SignaturesString[] = R\"\"\"(\n"
+ << signatureStream.readAll() << ")\"\"\";" << endl << endl;
+#else
+ s << "const char " << initFunctionName << "_SignaturesString[] = \"\"" << endl;
+ QString line;
+ while (signatureStream.readLineInto(&line)) {
+ s << '"' << line << "\\n\"" << endl;
+ }
+ s << ';' << endl << endl;
+#endif
s << "void init_" << initFunctionName;
s << "(PyObject* " << enclosingObjectVariable << ")" << endl;
s << '{' << endl;
@@ -4640,11 +4728,11 @@ void CppGenerator::writeClassRegister(QTextStream &s,
}
if (!classContext.forSmartPointer())
- s << INDENT << cpythonTypeNameExt(classTypeEntry);
+ s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl;
else
- s << INDENT << cpythonTypeNameExt(classContext.preciseType());
+ s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl;
- s << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl;
+ s << INDENT << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl;
s << endl;
// Multiple inheritance
@@ -4681,7 +4769,8 @@ void CppGenerator::writeClassRegister(QTextStream &s,
s << "\"," << endl;
{
Indentation indent(INDENT);
- s << INDENT << "&" << pyTypeName;
+ s << INDENT << "&" << pyTypeName << "," << endl;
+ s << INDENT << initFunctionName << "_SignaturesString";
// Set destructor function
if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
@@ -5069,6 +5158,8 @@ bool CppGenerator::finishGeneration()
QTextStream s_globalFunctionImpl(&globalFunctionImpl);
QString globalFunctionDecl;
QTextStream s_globalFunctionDef(&globalFunctionDecl);
+ QString signaturesString;
+ QTextStream signatureStream(&signaturesString);
Indentation indent(INDENT);
@@ -5089,6 +5180,7 @@ bool CppGenerator::finishGeneration()
// Dummy context to satisfy the API.
GeneratorContext classContext;
writeMethodWrapper(s_globalFunctionImpl, overloads, classContext);
+ writeSignatureInfo(signatureStream, overloads);
writeMethodDefinition(s_globalFunctionDef, overloads);
}
@@ -5152,6 +5244,7 @@ bool CppGenerator::finishGeneration()
if (usePySideExtensions()) {
s << includeQDebug;
s << "#include <pyside.h>" << endl;
+ s << "#include <signature.h>" << endl;
}
s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl;
@@ -5458,7 +5551,25 @@ bool CppGenerator::finishGeneration()
}
// cleanup staticMetaObject attribute
- s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl;
+ s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl << endl;
+
+ // PYSIDE-510: Create a signatures string for the introspection feature.
+ s << "// The signatures string for the global functions." << endl;
+ s << "// Multiple signatures have their index \"n:\" in front." << endl;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+ s << "const char " << moduleName() << "_SignaturesString[] = R\"\"\"(\n"
+ << signatureStream.readAll() << ")\"\"\";" << endl << endl;
+#else
+ s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl;
+ QString line;
+ while (signatureStream.readLineInto(&line)) {
+ s << '"' << line << "\\n\"" << endl;
+ }
+ s << ';' << endl;
+#endif
+ // finish the rest of __signature__ initialization.
+ s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
+ << "_SignaturesString);" << endl << endl;
}
s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 5dc3f5a15..4877a1694 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -231,13 +231,14 @@ private:
void writeClassRegister(QTextStream &s,
const AbstractMetaClass *metaClass,
- GeneratorContext &classContext);
+ GeneratorContext &classContext,
+ QTextStream &signatureStream);
void writeClassDefinition(QTextStream &s,
const AbstractMetaClass *metaClass,
GeneratorContext &classContext);
void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads);
void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
-
+ void writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads);
/// Writes the implementation of all methods part of python sequence protocol
void writeSequenceMethods(QTextStream &s,
const AbstractMetaClass *metaClass,
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 7b664e105..670659854 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -324,6 +324,9 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* fu
else
funcName.prepend(fullName + QLatin1Char('.'));
}
+ else {
+ funcName = packageName() + QLatin1Char('.') + func->name();
+ }
return funcName;
}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index 837e7d640..d36962cf1 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -294,7 +294,8 @@ public:
QString wrapperName(const AbstractMetaClass* metaClass) const;
QString wrapperName(const AbstractMetaType *metaType) const;
- static QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ QString fullPythonFunctionName(const AbstractMetaFunction* func);
+
static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
static QString protectedFieldGetterName(const AbstractMetaField* field);
static QString protectedFieldSetterName(const AbstractMetaField* field);
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt
index 6d2d1c88f..3ea7a9f3b 100644
--- a/sources/shiboken2/libshiboken/CMakeLists.txt
+++ b/sources/shiboken2/libshiboken/CMakeLists.txt
@@ -37,6 +37,7 @@ bindingmanager.cpp
threadstatesaver.cpp
typeresolver.cpp
shibokenbuffer.cpp
+signature.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
@@ -69,6 +70,7 @@ install(FILES
typeresolver.h
shibokenbuffer.h
sbkpython.h
+ signature.h
"${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
DESTINATION include/shiboken2${shiboken2_SUFFIX})
install(TARGETS libshiboken EXPORT shiboken2
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index b319fea7e..3f3bcc7f5 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -51,6 +51,7 @@
#include <sstream>
#include <algorithm>
#include "threadstatesaver.h"
+#include "signature.h"
namespace {
void _destroyParentInfo(SbkObject* obj, bool keepReference);
@@ -723,10 +724,12 @@ void initPrivateData(SbkObjectType* self)
memset(self->d, 0, sizeof(SbkObjectTypePrivate));
}
-bool introduceWrapperType(PyObject* enclosingObject,
- const char* typeName, const char* originalName,
- SbkObjectType* type, ObjectDestructor cppObjDtor,
- SbkObjectType* baseType, PyObject* baseTypes,
+bool introduceWrapperType(PyObject *enclosingObject,
+ const char *typeName, const char *originalName,
+ SbkObjectType *type,
+ const char *signaturesString,
+ ObjectDestructor cppObjDtor,
+ SbkObjectType *baseType, PyObject *baseTypes,
bool isInnerClass)
{
initPrivateData(type);
@@ -744,7 +747,9 @@ bool introduceWrapperType(PyObject* enclosingObject,
}
}
- if (PyType_Ready(reinterpret_cast<PyTypeObject *>(type)) < 0)
+ // PySide-510
+ // here is the single change to support signatures.
+ if (SbkSpecial_Type_Ready(enclosingObject, reinterpret_cast<PyTypeObject *>(type), signaturesString) < 0)
return false;
if (isInnerClass)
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 002337f3c..a230c1337 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -207,7 +207,9 @@ LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self);
*/
LIBSHIBOKEN_API bool introduceWrapperType(PyObject* enclosingObject,
const char* typeName, const char* originalName,
- SbkObjectType* type, ObjectDestructor cppObjDtor = 0,
+ SbkObjectType* type,
+ const char* signaturesString,
+ ObjectDestructor cppObjDtor = 0,
SbkObjectType* baseType = 0, PyObject* baseTypes = 0,
bool isInnerClass = false);
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
new file mode 100644
index 000000000..7333870dd
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -0,0 +1,655 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $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 "basewrapper.h"
+
+extern "C"
+{
+
+/***************************************************************************
+ ***************************************************************************
+
+
+ The signature C extension
+ =========================
+
+ This module is a C extension for CPython 3.4 and up, and CPython 2.7.
+ It's purpose is to provide support for the __signature__ attribute
+ of builtin PyCFunction objects.
+
+
+ Short excursion on the topic
+ ----------------------------
+
+ Beginning with CPython 3.5, Python functions began to grow a __signature__
+ attribute for normal Python functions. This is totally optional and just
+ a nice-to-have feature in Python.
+
+ PySide, on the other hand, could use __signature__ very much, because the
+ typing info for the 14000+ PySide functions is really missing, and it
+ would be nice to have this info available directly in Python.
+
+
+ How this code works
+ -------------------
+
+ The basic idea is to create a dummy Python function and to use the inspect
+ module to create a signature object. Then, this object is ge to python:
+
+ I added the __signature__ attribute to every function.
+
+ That is a little change to Python that does not harm, but it saves us
+ tons of code, that was needed in the former versions.
+
+ The internal work is done in two steps:
+ All functions get their "signature text" when the module is imported.
+ The actual signature is created later, when the attribute is really used.
+
+ Example:
+
+ The PyCFunction 'QtWidgets.QApplication.palette' is interrogated for its
+ signature. That means 'pyside_sm_get___signature__()' is called.
+ It calls GetSignature_Function which returns the signature if it is found.
+
+ There are actually 2 locations where late initialization occurs:
+ - 'dict' can be no dict but a tuple. That is the argument tuple that
+ was saved by 'PySide_BuildSignatureArgs' at module load time.
+ If so, then 'pyside_type_init' in 'signature.py' will be called,
+ which parses the string and creates the dict.
+ - 'props' can be empty. Then 'create_signature' in 'signature_loader.py'
+ is called, which uses a dummy function to produce a signature instance
+ with the inspect module.
+
+ This module is dedicated to our lovebird "PĆ¼ppi", who died on 2017-09-15.
+
+ ****************************************************************************
+ ****************************************************************************/
+
+#include "signature.h"
+#include <structmember.h>
+
+#define EXTENSION_ENABLED \
+ PY_VERSION_HEX >= 0x03040000 || \
+ (PY_VERSION_HEX < 0x03000000 && PY_VERSION_HEX >= 0x02070000)
+
+#if EXTENSION_ENABLED
+
+// These constants were needed in former versions of the module:
+#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03060000)
+#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)
+#define PYTHON_HAS_KEYWORDONLY (PYTHON_IS_PYTHON3)
+#define PYTHON_USES_PERCENT_V_FORMAT (PYTHON_IS_PYTHON3)
+#define PYTHON_HAS_DESCR_REDUCE (PY_VERSION_HEX >= 0x03040000)
+#define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE)
+#define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3)
+#define PYTHON_EXPOSES_METHODDESCR (PYTHON_IS_PYTHON3)
+
+// 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;
+ // init part 2: run module
+ PyObject *sigparse_func;
+ PyObject *createsig_func;
+} safe_globals_struc, *safe_globals;
+
+static safe_globals pyside_globals = 0;
+
+static PyObject *GetSignature_Function(PyCFunctionObject *);
+static PyObject *GetSignature_TypeMod(PyObject *);
+
+static PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+
+const char helper_module_name[] = "signature_loader";
+const char bootstrap_name[] = "bootstrap";
+const char arg_name[] = "pyside_arg_dict";
+const char func_name[] = "pyside_type_init";
+
+static PyObject *
+CreateSignature(PyObject *props, const char *sig_kind)
+{
+ /*
+ * Here is the new function to create all signatures. It simply calls
+ * into Python and creates a signature object for a dummy-function.
+ * This is so much simpler than using all the attributes explicitly
+ * to support '_signature_is_functionlike()'.
+ */
+ return PyObject_CallFunction(pyside_globals->createsig_func,
+ (char *)"(Os)", props, sig_kind);
+}
+
+static PyObject *
+pyside_cf_get___signature__(PyCFunctionObject *func)
+{
+ return GetSignature_Function(func);
+}
+
+static PyObject *
+pyside_sm_get___signature__(PyObject *sm)
+{
+ PyObject *func, *ret;
+
+ func = PyObject_GetAttrString(sm, "__func__");
+ ret = GetSignature_Function((PyCFunctionObject *)func);
+ Py_XDECREF(func);
+ return ret;
+}
+
+static PyObject *
+pyside_md_get___signature__(PyMethodDescrObject *descr)
+{
+ PyCFunctionObject *func;
+ PyObject *result;
+
+ func = (PyCFunctionObject *)
+ PyCFunction_NewEx(descr->d_method,
+#if PYTHON_USES_D_COMMON
+ (PyObject *)descr->d_common.d_type, NULL
+#else
+ (PyObject *)descr->d_type, NULL
+#endif
+ );
+ if (func == NULL)
+ return NULL;
+ result = pyside_cf_get___signature__(func);
+ Py_DECREF(func);
+ return result;
+}
+
+static PyObject *
+pyside_tp_get___signature__(PyObject *typemod)
+{
+ return GetSignature_TypeMod(typemod);
+}
+
+static PyObject *
+GetSignature_Function(PyCFunctionObject *func)
+{
+ PyObject *typemod, *type_name, *dict, *props, *value, *selftype;
+ PyObject *func_name = PyObject_GetAttrString((PyObject *)func, "__name__");
+ 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);
+ }
+ if (selftype == NULL) {
+#endif
+ if (!PyErr_Occurred()) {
+ PyErr_Format(PyExc_SystemError,
+ "the signature for \"%s\" should exist", func->m_ml->ml_name);
+ }
+ return NULL;
+ }
+ if ((PyType_Check(selftype) || PyModule_Check(selftype)))
+ typemod = selftype;
+ else
+ typemod = (PyObject *)Py_TYPE(selftype);
+ type_name = PyObject_GetAttrString(typemod, "__name__");
+ if (type_name == NULL)
+ Py_RETURN_NONE;
+ dict = PyDict_GetItem(pyside_globals->arg_dict, type_name);
+ Py_DECREF(type_name);
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (PyTuple_Check(dict)) {
+ /*
+ * We do the initialization lazily.
+ * This has also the advantage that we can freely import PySide.
+ */
+ dict = PySide_BuildSignatureProps(typemod);
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ }
+ props = PyDict_GetItem(dict, func_name);
+ if (props == NULL)
+ Py_RETURN_NONE;
+ flags = PyCFunction_GET_FLAGS(func);
+ if (flags & METH_CLASS)
+ sig_kind = "classmethod";
+ else if (flags & METH_STATIC)
+ sig_kind = "staticmethod";
+ else
+ sig_kind = "method";
+ value = PyDict_GetItemString(props, sig_kind);
+ if (value == NULL) {
+ // we need to compute a signature object
+ value = CreateSignature(props, sig_kind);
+ if (value != NULL) {
+ if (PyDict_SetItemString(props, sig_kind, value) < 0)
+ return NULL;
+ }
+ else
+ Py_RETURN_NONE;
+ }
+ return Py_INCREF(value), value;
+}
+
+static PyObject *
+GetSignature_TypeMod(PyObject *ob)
+{
+ PyObject *ob_name, *dict, *props, *value;
+ const char *sig_kind;
+
+ ob_name = PyObject_GetAttrString(ob, "__name__");
+ dict = PyDict_GetItem(pyside_globals->arg_dict, ob_name);
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (PyTuple_Check(dict)) {
+ dict = PySide_BuildSignatureProps(ob);
+ if (dict == NULL) {
+ Py_RETURN_NONE;
+ }
+ }
+ props = PyDict_GetItem(dict, ob_name);
+ Py_DECREF(ob_name);
+ if (props == NULL)
+ Py_RETURN_NONE;
+ sig_kind = "method";
+ value = PyDict_GetItemString(props, sig_kind);
+ if (value == NULL) {
+ // we need to compute a signature object
+ value = CreateSignature(props, sig_kind);
+ if (value != NULL) {
+ if (PyDict_SetItemString(props, sig_kind, value) < 0)
+ return NULL;
+ }
+ else
+ Py_RETURN_NONE;
+ }
+ return Py_INCREF(value), value;
+}
+
+
+const char *PySide_PythonCode = (const char *)
+ "from __future__ import print_function, absolute_import\n"
+ "import sys, os, traceback\n"
+
+ "pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR', '.')\n"
+ "__file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')\n"
+
+ "def bootstrap():\n"
+ " try:\n"
+ " with open(__file__) as _f:\n"
+ " exec(compile(_f.read(), __file__, 'exec'))\n"
+ " except Exception as e:\n"
+ " print('Exception:', e)\n"
+ " traceback.print_exc(file=sys.stdout)\n"
+ " globals().update(locals())\n"
+ ;
+
+static safe_globals_struc *
+init_phase_1(void)
+{
+ safe_globals_struc *p;
+ PyObject *d, *v;
+
+ p = (safe_globals_struc *)malloc(sizeof(safe_globals_struc));
+ if (p == NULL)
+ goto error;
+ p->helper_module = PyImport_AddModule((char *) helper_module_name);
+ if (p->helper_module == NULL)
+ goto error;
+
+ // Initialize the module
+ d = PyModule_GetDict(p->helper_module);
+ if (PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins()) < 0)
+ goto error;
+ v = PyRun_String(PySide_PythonCode, Py_file_input, d, d);
+ if (v == NULL)
+ goto error;
+ Py_DECREF(v);
+
+ // Build a dict for the prepared arguments
+ p->arg_dict = PyDict_New();
+ if (p->arg_dict == NULL)
+ goto error;
+ if (PyObject_SetAttrString(p->helper_module, arg_name, p->arg_dict) < 0)
+ goto error;
+ return p;
+
+error:
+ PyErr_SetString(PyExc_SystemError, "could not initialize part 1");
+ return NULL;
+}
+
+static int
+init_phase_2(safe_globals_struc *p)
+{
+ PyObject *bootstrap_func;
+
+ bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name);
+ if (bootstrap_func == NULL)
+ goto error;
+ if (PyObject_CallFunction(bootstrap_func, (char *)"()") == NULL)
+ goto error;
+ // now the loader is initialized
+ p->sigparse_func = PyObject_GetAttrString(p->helper_module, func_name);
+ if (p->sigparse_func == NULL)
+ goto error;
+ p->createsig_func = PyObject_GetAttrString(p->helper_module, "create_signature");
+ if (p->createsig_func == NULL)
+ goto error;
+ return 0;
+
+error:
+ PyErr_SetString(PyExc_SystemError, "could not initialize part 2");
+ return -1;
+}
+
+static int
+add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp)
+{
+ PyObject *dict = type->tp_dict;
+
+ for (; gsp->name != NULL; gsp++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, gsp->name))
+ continue;
+ descr = PyDescr_NewGetSet(type, gsp);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0) {
+ Py_DECREF(descr);
+ return -1;
+ }
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Augmenting builtin types with a __signature__ attribute.
+//
+// This is a harmless change to Python, similar like __text_signature__.
+// We could avoid it, but then we would need to copy quite some module
+// initialization functions which are pretty version- and word size
+// dependent. I think this little patch is the lesser of the two evils.
+//
+// Please note that in fact we are modifying 'type', the metaclass of all
+// objects, because we add new functionality.
+//
+static PyGetSetDef new_PyCFunction_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_cf_get___signature__},
+ {0}
+};
+
+static PyGetSetDef new_PyStaticMethod_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_sm_get___signature__},
+ {0}
+};
+
+static PyGetSetDef new_PyMethodDescr_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_md_get___signature__},
+ {0}
+};
+
+static PyGetSetDef new_PyType_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_tp_get___signature__},
+ {0}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// This special Type_Ready does certain initializations earlier with
+// our new version.
+//
+static int
+PySideType_Ready(PyTypeObject *type)
+{
+ PyObject *md;
+ static int init_done = 0;
+
+ if (!init_done) {
+ // Python2 does not expose certain types. We look them up:
+ // 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");
+ 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(&PyType_Type, new_PyType_getsets) < 0)
+ return -1;
+ init_done = 1;
+ }
+ 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;
+
+ if (meth == 0)
+ return 0;
+
+ for (; meth->ml_name != NULL; meth++) {
+ if (meth->ml_flags & METH_STATIC) {
+ 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)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+static int
+PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
+ const char *signatures)
+{
+ PyObject *type_name, *arg_tup;
+ const char *name = NULL;
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1();
+ if (pyside_globals < 0)
+ return -1;
+ init_done = 1;
+ }
+ arg_tup = Py_BuildValue("(Os)", type, signatures);
+ if (arg_tup == NULL)
+ return -1;
+ if (!PyModule_Check(module))
+ return 0;
+ name = PyModule_GetName(module);
+ if (name == NULL)
+ return -1;
+ if (strncmp(name, "PySide2.Qt", 10) != 0)
+ return 0;
+ /*
+ * Normally, we would now just call the Python function with the
+ * arguments and then continue processing.
+ * But it is much better to delay the second part until it is
+ * really needed. Why?
+ *
+ * - by doing it late, we save initialization time when no signatures
+ * are requested,
+ * - by calling the python function late, we can freely import PySide
+ * without recursion problems.
+ */
+ type_name = PyObject_GetAttrString(type, "__name__");
+ if (type_name == NULL)
+ return -1;
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_name, arg_tup) < 0)
+ return -1;
+ return 0;
+}
+
+static PyObject *
+PySide_BuildSignatureProps(PyObject *classmod)
+{
+ PyObject *arg_tup, *dict, *type_name;
+ static int init_done = 0;
+
+ if (!init_done) {
+ if (init_phase_2(pyside_globals) < 0)
+ return NULL;
+ init_done = 1;
+ }
+ /*
+ * Here is the second part of the function.
+ * This part will be called on-demand when needed by some attribute.
+ * We simply pick up the arguments that we stored here and replace
+ * them by the function result.
+ */
+ type_name = PyObject_GetAttrString(classmod, "__name__");
+ if (type_name == NULL)
+ return NULL;
+ arg_tup = PyDict_GetItem(pyside_globals->arg_dict, type_name);
+ if (arg_tup == NULL)
+ return NULL;
+ dict = PyObject_CallObject(pyside_globals->sigparse_func, arg_tup);
+ if (dict == NULL)
+ return NULL;
+
+ // We replace the arguments by the result dict.
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_name, dict) < 0)
+ return NULL;
+ Py_DECREF(type_name);
+ return dict;
+}
+
+#endif // EXTENSION_ENABLED
+
+int
+SbkSpecial_Type_Ready(PyObject *module, PyTypeObject *type,
+ const char *signatures)
+{
+ int ret;
+#if EXTENSION_ENABLED
+ if (PySideType_Ready(type) < 0)
+ return -1;
+ ret = PySide_BuildSignatureArgs(module, (PyObject *)type, signatures);
+#else
+ ret = PyType_Ready(type);
+#endif
+ if (ret < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+ return ret;
+}
+
+static int
+PySide_FinishSignatures(PyObject *module, const char *signatures)
+{
+ const char *name = NULL;
+
+ // CRUCIAL: Do not call this on "testbinding":
+ // The module is different and should not get signatures, anyway.
+ name = PyModule_GetName(module);
+ if (name == NULL)
+ return -1;
+ if (strncmp(name, "PySide2.Qt", 10) != 0)
+ return 0;
+
+ // we abuse the call for types, since they both have a __name__ attribute.
+ 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.
+ */
+ {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ PyObject *dict = PyModule_GetDict(module);
+
+ if (dict == NULL)
+ return -1;
+
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ if (PyType_Check(value)) {
+ if (build_func_to_type(value) < 0)
+ return -1;
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+void
+FinishSignatureInitialization(PyObject *module, const char *signatures)
+{
+#if EXTENSION_ENABLED
+ if (PySide_FinishSignatures(module, signatures) < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+#endif
+}
+
+} //extern "C"
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
new file mode 100644
index 000000000..d134e4c82
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $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 SIGNATURE_H
+#define SIGNATURE_H
+
+#include "sbkpython.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char*);
+LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char*);
+
+} // extern "C"
+
+#endif // SIGNATURE_H