aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2018-10-14 11:13:40 +0200
committerChristian Tismer <tismer@stackless.com>2018-11-15 10:24:23 +0000
commit2533dab013455bf94da2d4766e54abaf4d735e1e (patch)
tree506f169c2f3a44fed3bfe623c1f626d40836a379 /sources
parent93b54f123771c5b7da9880e9a2f372562893707f (diff)
Signature: Implement Nested Classes and Functions for Shiboken
This patch again contains a complete overhaul of the signature module. The code was re-implemented to properly support nested classes. Also, the code was reduced by AutoDecRef and by adopting a concise C++ style. Note.. We will add a shiboken signature test and complete mapping.py after the split into three projects is done. The split changes a lot and is needed right now! Signatures were quite complete for PySide, but the support for Shiboken was under-developed. Since we are planning to generally enhance error messages by using the Signature module, we should be able to rely on them to always produce a signature. Therefore, a general overhaul was needed to resolve all cornes cases for Python 2 and 3. Nested classes are supported, as well as plain module functions. The usage of the typing module might improve over time, but the Signature implementation is now considered complete. The loader will respect now the path settings which might not be the package dir but the build dir. This is more consistens with COIN testing. Task-number: PYSIDE-795 Change-Id: I246449d4df895dadf2bcb4d997eaa13d78463d9b Reviewed-by: Simo Fält <simo.falt@qt.io>
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside2/PySide2/__init__.py.in2
-rw-r--r--sources/pyside2/PySide2/support/signature/__init__.py2
-rw-r--r--sources/pyside2/PySide2/support/signature/layout.py16
-rw-r--r--sources/pyside2/PySide2/support/signature/lib/enum_sig.py62
-rw-r--r--sources/pyside2/PySide2/support/signature/mapping.py42
-rw-r--r--sources/pyside2/tests/registry/init_platform.py10
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp31
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp575
8 files changed, 447 insertions, 293 deletions
diff --git a/sources/pyside2/PySide2/__init__.py.in b/sources/pyside2/PySide2/__init__.py.in
index 631f5f13a..ac75f52b6 100644
--- a/sources/pyside2/PySide2/__init__.py.in
+++ b/sources/pyside2/PySide2/__init__.py.in
@@ -21,8 +21,6 @@ def _setupQtDirectories():
import shiboken2
pyside_package_dir = os.path.abspath(os.path.dirname(__file__))
- # Used by signature module.
- os.environ["PYSIDE_PACKAGE_DIR"] = pyside_package_dir
if sys.platform == 'win32':
# PATH has to contain the package directory, otherwise plugins
diff --git a/sources/pyside2/PySide2/support/signature/__init__.py b/sources/pyside2/PySide2/support/signature/__init__.py
index 14e63a5fb..49224bf92 100644
--- a/sources/pyside2/PySide2/support/signature/__init__.py
+++ b/sources/pyside2/PySide2/support/signature/__init__.py
@@ -42,5 +42,5 @@ from __future__ import print_function, absolute_import
from .loader import inspect
from PySide2 import QtCore
if QtCore.QProcess.__signature__:
- pass # trigger initialization
+ pass # trigger initialization phase 2, so we can import:
from signature_loader import get_signature
diff --git a/sources/pyside2/PySide2/support/signature/layout.py b/sources/pyside2/PySide2/support/signature/layout.py
index ac7833f03..e18cb2172 100644
--- a/sources/pyside2/PySide2/support/signature/layout.py
+++ b/sources/pyside2/PySide2/support/signature/layout.py
@@ -58,6 +58,7 @@ used literally as strings like "signature", "existence", etc.
from textwrap import dedent
from .loader import inspect
+
class SimpleNamespace(object):
# From types.rst, because the builtin is implemented in Python 3, only.
def __init__(self, **kwargs):
@@ -71,6 +72,7 @@ class SimpleNamespace(object):
def __eq__(self, other):
return self.__dict__ == other.__dict__
+
class SignatureLayout(SimpleNamespace):
"""
Configure a signature.
@@ -140,6 +142,7 @@ typeerror = SignatureLayout(definition=False,
return_annotation=False,
parameter_names=False)
+
def define_nameless_parameter():
"""
Create Nameless Parameters
@@ -168,8 +171,10 @@ def define_nameless_parameter():
body["__str__"] = __str__
return type(newname, bases, body)
+
NamelessParameter = define_nameless_parameter()
+
def make_signature_nameless(signature):
"""
Make a Signature Nameless
@@ -178,7 +183,8 @@ def make_signature_nameless(signature):
The signature looks different, but is totally intact.
"""
for key in signature.parameters.keys():
- Signature.parameters[key].__class__ = NamelessParameter
+ signature.parameters[key].__class__ = NamelessParameter
+
def create_signature(props, key):
if not props:
@@ -193,7 +199,7 @@ def create_signature(props, key):
else:
sig_kind, modifier = key, "signature"
- layout = globals()[modifier] # lookup of the modifier, here
+ layout = globals()[modifier] # lookup of the modifier in this module
if not isinstance(layout, SignatureLayout):
raise SystemError("Modifiers must be names of a SignatureLayout "
"instance")
@@ -201,14 +207,16 @@ def create_signature(props, key):
# this is the basic layout of a signature
varnames = props["varnames"]
if layout.definition:
- if sig_kind == "method":
+ if sig_kind == "function":
+ pass
+ elif sig_kind == "method":
varnames = ("self",) + varnames
elif sig_kind == "staticmethod":
pass
elif sig_kind == "classmethod":
varnames = ("klass",) + varnames
else:
- raise SystemError("Methods must be normal, staticmethod or "
+ raise SystemError("Methods must be function, method, staticmethod or "
"classmethod")
# calculate the modifications
defaults = props["defaults"][:]
diff --git a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
index 702ee7ebd..c043f04f8 100644
--- a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
+++ b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
@@ -37,6 +37,8 @@
##
#############################################################################
+from __future__ import print_function, absolute_import
+
import sys
from PySide2.support.signature import inspect, get_signature
@@ -58,7 +60,11 @@ class ExactEnumerator(object):
with self.fmt.module(mod_name):
module = sys.modules[mod_name]
members = inspect.getmembers(module, inspect.isclass)
+ functions = inspect.getmembers(module, inspect.isroutine)
ret = self.result_type()
+ self.fmt.class_name = None
+ for func_name, func in functions:
+ ret.update(self.function(func_name, func))
for class_name, klass in members:
ret.update(self.klass(class_name, klass))
return ret
@@ -79,8 +85,15 @@ class ExactEnumerator(object):
# class_members = inspect.getmembers(klass)
# gives us also the inherited things.
class_members = sorted(list(klass.__dict__.items()))
- for func_name, func in class_members:
- ret.update(self.function(func_name, func))
+ subclasses = []
+ for thing_name, thing in class_members:
+ if inspect.isclass(thing):
+ subclass_name = ".".join((class_name, thing_name))
+ subclasses.append((subclass_name, thing))
+ else:
+ ret.update(self.function(thing_name, thing))
+ for subclass_name, subclass in subclasses:
+ ret.update(self.klass(subclass_name, subclass))
return ret
def function(self, func_name, func):
@@ -92,6 +105,27 @@ class ExactEnumerator(object):
return ret
+def simplify(signature):
+ if isinstance(signature, list):
+ # remove duplicates which still sometimes occour:
+ ret = set(simplify(sig) for sig in signature)
+ return sorted(ret) if len(ret) > 1 else list(ret)[0]
+ ret = []
+ for pv in signature.parameters.values():
+ txt = str(pv)
+ if ":" not in txt: # 'self' or '*args'
+ continue
+ txt = txt[txt.index(":") + 1:]
+ if "=" in txt:
+ txt = txt[:txt.index("=")]
+ quote = txt[0]
+ if quote in ("'", '"') and txt[-1] == quote:
+ txt = txt[1:-1]
+ ret.append(txt.strip())
+ return tuple(ret)
+
+
+### disabled for now:
class SimplifyingEnumerator(ExactEnumerator):
"""
SimplifyingEnumerator enumerates all signatures in a module filtered.
@@ -109,5 +143,27 @@ class SimplifyingEnumerator(ExactEnumerator):
signature = get_signature(func, 'existence')
if signature is not None and func_name not in ("next", "__next__"):
with self.fmt.function(func_name, signature) as key:
- ret[key] = signature
+ ret[key] = str(signature)
+ return ret
+
+
+class SimplifyingEnumerator(ExactEnumerator):
+ """
+ SimplifyingEnumerator enumerates all signatures in a module filtered.
+
+ There are no default values, no variable
+ names and no self parameter. Only types are present after simplification.
+ The functions 'next' resp. '__next__' are removed
+ to make the output identical for Python 2 and 3.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = getattr(func, '__signature__', None)
+ sig = simplify(signature) if signature is not None else None
+ if sig is not None and func_name not in ("next", "__next__", "__div__"):
+ with self.fmt.function(func_name, sig) as key:
+ ret[key] = sig
return ret
diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/pyside2/PySide2/support/signature/mapping.py
index 6b7d1ad01..23ba6a7f1 100644
--- a/sources/pyside2/PySide2/support/signature/mapping.py
+++ b/sources/pyside2/PySide2/support/signature/mapping.py
@@ -56,6 +56,11 @@ import sys
import struct
import PySide2
try:
+ import sample
+except ImportError:
+ pass
+
+try:
from . import typing
except ImportError:
import typing
@@ -64,10 +69,12 @@ ellipsis = "..."
Char = typing.Union[str, int] # how do I model the limitation to 1 char?
StringList = typing.List[str]
IntList = typing.List[int]
+IntMatrix = typing.List[IntList]
Variant = typing.Any
ModelIndexList = typing.List[int]
QImageCleanupFunction = typing.Callable
-FloatMatrix = typing.List[typing.List[float]]
+FloatList = typing.List[float]
+FloatMatrix = typing.List[FloatList]
# Pair could be more specific, but we loose the info in the generator.
Pair = typing.Tuple[typing.Any, typing.Any]
MultiMap = typing.DefaultDict[str, typing.List[str]]
@@ -132,7 +139,7 @@ class Instance(_NotCalled):
class Reloader(object):
def __init__(self):
self.sys_module_count = 0
- self.uninitialized = PySide2.__all__[:]
+ self.uninitialized = PySide2.__all__[:] + ["sample"]
def update(self):
if self.sys_module_count == len(sys.modules):
@@ -140,7 +147,7 @@ class Reloader(object):
self.sys_module_count = len(sys.modules)
g = globals()
for mod_name in self.uninitialized[:]:
- if "PySide2." + mod_name in sys.modules:
+ if "PySide2." + mod_name in sys.modules or mod_name == "sample":
self.uninitialized.remove(mod_name)
proc_name = "init_" + mod_name
if proc_name in g:
@@ -289,6 +296,7 @@ def init_QtCore():
"PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
"QVariantMap": dict,
"PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
+ "PySide2.QtCore.double": float,
})
try:
type_map.update({
@@ -299,6 +307,7 @@ def init_QtCore():
pass
return locals()
+
def init_QtGui():
import PySide2.QtGui
type_map.update({
@@ -328,6 +337,7 @@ def init_QtGui():
})
return locals()
+
def init_QtWidgets():
import PySide2.QtWidgets
from PySide2.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex
@@ -364,6 +374,7 @@ def init_QtWidgets():
})
return locals()
+
def init_QtSql():
import PySide2.QtSql
from PySide2.QtSql import QSqlDatabase
@@ -373,6 +384,7 @@ def init_QtSql():
})
return locals()
+
def init_QtNetwork():
import PySide2.QtNetwork
type_map.update({
@@ -383,6 +395,7 @@ def init_QtNetwork():
})
return locals()
+
def init_QtXmlPatterns():
import PySide2.QtXmlPatterns
from PySide2.QtXmlPatterns import QXmlName
@@ -392,6 +405,7 @@ def init_QtXmlPatterns():
})
return locals()
+
def init_QtMultimedia():
import PySide2.QtMultimedia
import PySide2.QtMultimediaWidgets
@@ -401,6 +415,7 @@ def init_QtMultimedia():
})
return locals()
+
def init_QtOpenGL():
import PySide2.QtOpenGL
type_map.update({
@@ -417,6 +432,7 @@ def init_QtOpenGL():
})
return locals()
+
def init_QtQml():
import PySide2.QtQml
type_map.update({
@@ -429,6 +445,7 @@ def init_QtQml():
})
return locals()
+
def init_QtQuick():
import PySide2.QtQuick
type_map.update({
@@ -440,6 +457,7 @@ def init_QtQuick():
})
return locals()
+
def init_QtScript():
import PySide2.QtScript
type_map.update({
@@ -447,6 +465,7 @@ def init_QtScript():
})
return locals()
+
def init_QtTest():
import PySide2.QtTest
type_map.update({
@@ -471,6 +490,23 @@ def init_QtWinExtras():
})
return locals()
+def init_sample():
+ type_map.update({
+ "sample.int": int,
+ "Complex": complex,
+ "sample.OddBool": bool,
+ "sample.bool": bool,
+ "sample.PStr": str,
+ "double[]": FloatList,
+ "OddBool": bool,
+ "PStr": str,
+ "sample.char": Char,
+ "double[][]": FloatMatrix,
+ "int[]": IntList,
+ "int[][]": IntMatrix,
+ })
+ return locals()
+
# Here was testbinding, actually the source of all evil.
# end of file
diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py
index 22875a63e..66ec6f566 100644
--- a/sources/pyside2/tests/registry/init_platform.py
+++ b/sources/pyside2/tests/registry/init_platform.py
@@ -143,7 +143,10 @@ class Formatter(object):
@contextmanager
def function(self, func_name, signature):
- key = viskey = "{}.{}".format(self.class_name, func_name)
+ if self.class_name is None:
+ key = viskey = "{}".format(func_name)
+ else:
+ key = viskey = "{}.{}".format(self.class_name, func_name)
if key.endswith("lY"):
# Some classes like PySide2.QtGui.QContextMenuEvent have functions
# globalX and the same with Y. The gerrit robot thinks that this
@@ -176,8 +179,9 @@ def generate_all():
This file contains the simplified signatures for all functions in PySide
for module '{}'. There are no default values, no variable
names and no self parameter. Only types are present after simplification.
- The functions 'next' resp. '__next__' are removed
- to make the output identical for Python 2 and 3.
+ The functions 'next' resp. '__next__' are removed to make the output
+ identical for Python 2 and 3. '__div__' is also removed,
+ since it exists in Python 2, only.
"""
'''.format(module)))
fmt.print("import sys")
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 99947d347..393f8a850 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -5415,10 +5415,10 @@ bool CppGenerator::finishGeneration()
s << "#include <sbkpython.h>" << endl;
s << "#include <shiboken.h>" << endl;
s << "#include <algorithm>" << endl;
+ s << "#include <signature.h>" << endl;
if (usePySideExtensions()) {
s << includeQDebug;
s << "#include <pyside.h>" << endl;
- s << "#include <signature.h>" << endl;
s << "#include <qapp_macro.h>" << endl;
}
@@ -5714,22 +5714,25 @@ bool CppGenerator::finishGeneration()
// cleanup staticMetaObject attribute
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;
- s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl;
- QString line;
- while (signatureStream.readLineInto(&line))
- s << INDENT << '"' << line << "\\n\"" << endl;
- s << ';' << endl;
- // finish the rest of __signature__ initialization.
- s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
- << "_SignaturesString);" << 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;
+ s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl;
+ QString line;
+ while (signatureStream.readLineInto(&line))
+ s << INDENT << '"' << line << "\\n\"" << endl;
+ s << ';' << endl;
+ // finish the rest of __signature__ initialization.
+ s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
+ << "_SignaturesString);" << endl;
+
+ if (usePySideExtensions()) {
// initialize the qApp module.
- s << INDENT << "NotifyModuleForQApp(module);" << endl << endl;
+ s << INDENT << "NotifyModuleForQApp(module);" << endl;
}
-
+ s << endl;
s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
return file.done() != FileOut::Failure;
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index 24d60acc4..962e50d46 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "basewrapper.h"
+#include "autodecref.h"
extern "C"
{
@@ -77,7 +78,9 @@ typedef struct safe_globals_struc {
static safe_globals pyside_globals = 0;
-static PyObject *GetSignature_Function(PyCFunctionObject *, const char *);
+static PyObject *GetClassKey(PyObject *ob);
+
+static PyObject *GetSignature_Function(PyObject *, const char *);
static PyObject *GetSignature_TypeMod(PyObject *, const char *);
static PyObject *GetSignature_Wrapper(PyObject *, const char *);
static PyObject *get_signature(PyObject *self, PyObject *args);
@@ -108,24 +111,85 @@ CreateSignature(PyObject *props, PyObject *key)
static PyObject *
pyside_cf_get___signature__(PyObject *func, const char *modifier)
{
- return GetSignature_Function((PyCFunctionObject *)func, modifier);
+ return GetSignature_Function(func, modifier);
}
static PyObject *
pyside_sm_get___signature__(PyObject *sm, const char *modifier)
{
- PyObject *func, *ret;
+ Shiboken::AutoDecRef func(PyObject_GetAttrString(sm, "__func__"));
+ return GetSignature_Function(func, modifier);
+}
- func = PyObject_GetAttrString(sm, "__func__");
- ret = GetSignature_Function((PyCFunctionObject *)func, modifier);
- Py_XDECREF(func);
- return ret;
+static PyObject *
+_get_class_of_cf(PyObject *ob_cf)
+{
+ PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
+ if (selftype == NULL)
+ selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)ob_cf);
+ if (selftype == NULL) {
+ if (!PyErr_Occurred())
+ Py_RETURN_NONE;
+ return NULL;
+ }
+ PyObject *typemod = (PyType_Check(selftype) || PyModule_Check(selftype))
+ ? selftype : (PyObject *)Py_TYPE(selftype);
+ // do we support module functions?
+ Py_INCREF(typemod);
+ return typemod;
+}
+
+static PyObject *
+_get_class_of_sm(PyObject *ob_sm)
+{
+ Shiboken::AutoDecRef func(PyObject_GetAttrString(ob_sm, "__func__"));
+ return _get_class_of_cf(func);
}
-#ifdef Py_LIMITED_API
+static PyObject *
+_get_class_of_descr(PyObject *ob)
+{
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__"));
+ return PyObject_GetAttrString(ob, "__objclass__");
+}
+
+static PyObject *
+GetClassOfFunc(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return ob;
+ if (Py_TYPE(ob) == &PyCFunction_Type)
+ return _get_class_of_cf(ob);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return _get_class_of_sm(ob);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return _get_class_of_descr(ob);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return _get_class_of_descr(ob);
+ Py_FatalError("unexpected type in GetClassOfFunc");
+ return nullptr;
+}
+
+static PyObject *
+compute_name_key(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return GetClassKey(GetClassOfFunc(ob));
+ PyObject *func = ob;
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ func = PyObject_GetAttrString(ob, "__func__");
+ else
+ Py_INCREF(func);
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(func, "__name__"));
+ Py_DECREF(func);
+ if (func_name.isNull())
+ Py_FatalError("unexpected name problem in compute_name_key");
+ Shiboken::AutoDecRef type_key(GetClassKey(GetClassOfFunc(ob)));
+ return Py_BuildValue("(OO)", type_key.object(), func_name.object());
+}
static int
-build_qualname_to_func(PyObject *obtype)
+build_name_key_to_func(PyObject *obtype)
{
PyTypeObject *type = (PyTypeObject *)obtype;
PyMethodDef *meth = type->tp_methods;
@@ -134,98 +198,53 @@ build_qualname_to_func(PyObject *obtype)
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) {
+ Shiboken::AutoDecRef func(PyCFunction_NewEx(meth, obtype, NULL));
+ Shiboken::AutoDecRef name_key(compute_name_key(func));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
return -1;
- }
- if (PyDict_SetItem(pyside_globals->map_dict, qualname, func) < 0) {
- return -1;
- }
- Py_DECREF(func);
- Py_DECREF(qualname);
}
return 0;
}
static PyObject *
-qualname_to_typename(PyObject *qualname)
-{
- 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)
+name_key_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.
+ * We build a mapping from name_key to function.
+ * This could also be computed directly, but the Limited API
+ * makes this impossible. So we always build our own mapping.
*/
- 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
+ Shiboken::AutoDecRef name_key(compute_name_key(ob));
+ if (name_key.isNull())
Py_RETURN_NONE;
+
+ PyObject *ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ if (ret == NULL) {
+ // do a lazy initialization
+ Shiboken::AutoDecRef type_key(GetClassKey(GetClassOfFunc(ob)));
+ PyObject *type = PyDict_GetItem(pyside_globals->map_dict,
+ type_key);
+ if (type == nullptr)
+ Py_RETURN_NONE;
+ assert(PyType_Check(type));
+ if (build_name_key_to_func(type) < 0)
+ return NULL;
+ ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ }
+ Py_XINCREF(ret);
return ret;
}
-#endif
static PyObject *
-pyside_md_get___signature__(PyObject *ob, const char *modifier)
-{
- 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
- /*
- * 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)
+pyside_md_get___signature__(PyObject *ob_md, const char *modifier)
+{
+ Shiboken::AutoDecRef func(name_key_to_func(ob_md));
+ if (func.object() == Py_None)
return Py_None;
- if (func == NULL)
+ if (func.isNull())
Py_FatalError("missing mapping in MethodDescriptor");
- result = pyside_cf_get___signature__(func, modifier);
- Py_DECREF(func);
- return result;
+ return pyside_cf_get___signature__(func, modifier);
}
static PyObject *
@@ -245,30 +264,44 @@ static PyObject *
GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier);
static PyObject *
-GetSignature_Function(PyCFunctionObject *func, const char *modifier)
+GetClassKey(PyObject *ob)
{
- PyObject *typemod, *type_name, *dict, *props, *selftype;
- PyObject *func_name = PyObject_GetAttrString((PyObject *)func, "__name__");
- const char *sig_kind;
- int flags;
+ assert(PyType_Check(ob) || PyModule_Check(ob));
+ /*
+ * We obtain a unique key using the module name and the class name.
+ *
+ * The class name is a bit funny when modules are nested.
+ * Example:
+ *
+ * "sample.Photon.ValueIdentity" is a class.
+ * name: "ValueIdentity"
+ * module: "sample.Photon"
+ *
+ * This is the PyCFunction behavior, as opposed to Python functions.
+ */
+ Shiboken::AutoDecRef class_name(PyObject_GetAttrString(ob, "__name__"));
+ Shiboken::AutoDecRef module_name(PyObject_GetAttrString(ob, "__module__"));
- selftype = PyCFunction_GET_SELF((PyObject *)func);
- if (selftype == NULL)
- selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func);
- if (selftype == NULL) {
- if (!PyErr_Occurred())
- Py_RETURN_NONE;
- 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)
+ if (module_name.isNull())
+ PyErr_Clear();
+
+ // Note: if we have a module, then __module__ is null, and we get
+ // the module name through __name__ .
+ if (class_name.isNull())
+ return nullptr;
+ if (module_name.object())
+ return Py_BuildValue("(OO)", module_name.object(), class_name.object());
+ return Py_BuildValue("O", class_name.object());
+}
+
+static PyObject *
+GetSignature_Function(PyObject *ob_func, const char *modifier)
+{
+ Shiboken::AutoDecRef typemod(GetClassOfFunc(ob_func));
+ Shiboken::AutoDecRef type_key(GetClassKey(typemod));
+ if (type_key.isNull())
Py_RETURN_NONE;
- dict = PyDict_GetItem(pyside_globals->arg_dict, type_name);
- Py_DECREF(type_name);
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
if (dict == NULL)
Py_RETURN_NONE;
if (PyTuple_Check(dict)) {
@@ -280,31 +313,35 @@ GetSignature_Function(PyCFunctionObject *func, const char *modifier)
if (dict == NULL)
Py_RETURN_NONE;
}
- props = PyDict_GetItem(dict, func_name);
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob_func, "__name__"));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
if (props == NULL)
Py_RETURN_NONE;
- flags = PyCFunction_GET_FLAGS((PyObject *)func);
- if (flags & METH_CLASS)
+
+ int flags = PyCFunction_GET_FLAGS(ob_func);
+ const char *sig_kind;
+ if (PyModule_Check(typemod))
+ sig_kind = "function";
+ else if (flags & METH_CLASS)
sig_kind = "classmethod";
else if (flags & METH_STATIC)
sig_kind = "staticmethod";
else
sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ PyObject *ret = GetSignature_Cached(props, sig_kind, modifier);
+ return ret;
}
static PyObject *
GetSignature_Wrapper(PyObject *ob, const char *modifier)
{
- PyObject *dict, *props;
- PyObject *func_name = PyObject_GetAttrString(ob, "__name__");
- PyObject *objclass = PyObject_GetAttrString(ob, "__objclass__");
- PyObject *class_name = PyObject_GetAttrString(objclass, "__name__");
- const char *sig_kind;
+ Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__"));
+ Shiboken::AutoDecRef objclass(PyObject_GetAttrString(ob, "__objclass__"));
+ Shiboken::AutoDecRef class_key(GetClassKey(objclass));
- if (func_name == nullptr || objclass == nullptr || class_name == nullptr)
+ if (func_name.isNull() || objclass.isNull() || class_key.isNull())
return nullptr;
- dict = PyDict_GetItem(pyside_globals->arg_dict, class_name);
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, class_key);
if (dict == NULL)
Py_RETURN_NONE;
if (PyTuple_Check(dict)) {
@@ -316,65 +353,51 @@ GetSignature_Wrapper(PyObject *ob, const char *modifier)
if (dict == NULL)
Py_RETURN_NONE;
}
- props = PyDict_GetItem(dict, func_name);
- Py_DECREF(func_name);
- Py_DECREF(objclass);
- Py_DECREF(class_name);
+ PyObject *props = PyDict_GetItem(dict, func_name);
if (props == NULL)
Py_RETURN_NONE;
- sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ return GetSignature_Cached(props, "method", modifier);
}
static PyObject *
GetSignature_TypeMod(PyObject *ob, const char *modifier)
{
- PyObject *ob_name, *dict, *props;
- const char *sig_kind;
+ Shiboken::AutoDecRef ob_name(PyObject_GetAttrString(ob, "__name__"));
+ Shiboken::AutoDecRef ob_key(GetClassKey(ob));
- ob_name = PyObject_GetAttrString(ob, "__name__");
- dict = PyDict_GetItem(pyside_globals->arg_dict, ob_name);
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, ob_key);
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);
+ PyObject *props = PyDict_GetItem(dict, ob_name);
if (props == NULL)
Py_RETURN_NONE;
- sig_kind = "method";
- return GetSignature_Cached(props, sig_kind, modifier);
+ return GetSignature_Cached(props, "method", modifier);
}
static PyObject *
GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
{
- PyObject *key, *value;
-
- if (modifier == nullptr)
- key = Py_BuildValue("s", sig_kind);
- else
- key = Py_BuildValue("(ss)", sig_kind, modifier);
- if (key == nullptr)
- return nullptr;
- value = PyDict_GetItem(props, key);
+ Shiboken::AutoDecRef key(modifier == nullptr
+ ? Py_BuildValue("s", sig_kind)
+ : Py_BuildValue("(ss)", sig_kind, modifier));
+ PyObject *value = PyDict_GetItem(props, key);
if (value == nullptr) {
// we need to compute a signature object
value = CreateSignature(props, key);
if (value != nullptr) {
- if (PyDict_SetItem(props, key, value) < 0) {
+ if (PyDict_SetItem(props, key, value) < 0)
// this is an error
- Py_DECREF(key);
return nullptr;
- }
}
else {
// key not found
- Py_DECREF(key);
Py_RETURN_NONE;
}
}
@@ -385,15 +408,14 @@ static const char PySide_PythonCode[] =
"from __future__ import print_function, absolute_import\n" R"~(if True:
import sys, os, traceback
-
- pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR')
- if pyside_package_dir is None:
- # This happens in shiboken running ctest.
- from distutils.sysconfig import get_python_lib
- pyside_package_dir = os.path.join(get_python_lib(), 'PySide2')
- __file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')
+ # We avoid imports in phase 1 that could fail. "import shiboken" of the
+ # binary would even crash in FinishSignatureInitialization.
def bootstrap():
+ global __file__
+ import PySide2 as root
+ rp = os.path.realpath(os.path.dirname(root.__file__))
+ __file__ = os.path.join(rp, 'support', 'signature', 'loader.py')
try:
with open(__file__) as _f:
exec(compile(_f.read(), __file__, 'exec'))
@@ -407,10 +429,9 @@ static const char PySide_PythonCode[] =
static safe_globals_struc *
init_phase_1(void)
{
- safe_globals_struc *p;
PyObject *d, *v;
-
- p = (safe_globals_struc *)malloc(sizeof(safe_globals_struc));
+ safe_globals_struc *p = (safe_globals_struc *)
+ malloc(sizeof(safe_globals_struc));
if (p == NULL)
goto error;
p->helper_module = PyImport_AddModule((char *) helper_module_name);
@@ -431,11 +452,10 @@ init_phase_1(void)
if (p->map_dict == NULL)
goto error;
- // Build a dict for the prepared arguments
+ // 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)
+ if (p->arg_dict == NULL
+ || PyObject_SetAttrString(p->helper_module, arg_name, p->arg_dict) < 0)
goto error;
return p;
@@ -450,30 +470,25 @@ init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
PyObject *bootstrap_func, *v = nullptr;
PyMethodDef *ml;
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != NULL; ml++) {
+ v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr
+ || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0)
+ goto error;
+ Py_DECREF(v);
+ }
bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name);
- if (bootstrap_func == NULL)
+ if (bootstrap_func == NULL
+ || PyObject_CallFunction(bootstrap_func, (char *)"()") == NULL)
goto error;
- if (PyObject_CallFunction(bootstrap_func, (char *)"()") == NULL)
- goto error;
- // now the loader is initialized
+ // now the loader should be 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;
-
- // The single function to be called, but maybe more to come.
- for (ml = methods; ml->ml_name != NULL; ml++) {
- v = PyCFunction_NewEx(ml, nullptr, nullptr);
- if (v == nullptr) {
- goto error;
- }
- if (PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) {
- goto error;
- }
- Py_DECREF(v);
- }
return 0;
error:
@@ -485,23 +500,17 @@ error:
static int
add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp)
{
- PyObject *dict;
-
assert(PyType_Check(type));
PyType_Ready(type);
- dict = type->tp_dict;
+ 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)
+ Shiboken::AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+ if (descr.isNull())
return -1;
- if (PyDict_SetItemString(dict, gsp->name, descr) < 0) {
- Py_DECREF(descr);
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
return -1;
- }
- Py_DECREF(descr);
}
return 0;
}
@@ -611,13 +620,12 @@ void handler(int sig) {
static int
PySideType_Ready(PyTypeObject *type)
{
- PyObject *md, *wd;
static int init_done = 0;
if (!init_done) {
- md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); // method-descriptor
- wd = PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__"); // wrapper-descriptor
- if (md == nullptr || wd == nullptr
+ Shiboken::AutoDecRef md(PyObject_GetAttrString((PyObject *)&PyString_Type, "split")); // method-descriptor
+ Shiboken::AutoDecRef wd(PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__")); // wrapper-descriptor
+ if (md.isNull() || wd.isNull()
|| PyType_Ready(Py_TYPE(md)) < 0
|| add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets) < 0
|| add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0
@@ -626,8 +634,6 @@ PySideType_Ready(PyTypeObject *type)
|| add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets) < 0
)
return -1;
- Py_DECREF(md);
- Py_DECREF(wd);
#ifndef _WIN32
// We enable the stack trace in CI, only.
const char *testEnv = getenv("QTEST_ENVIRONMENT");
@@ -639,31 +645,6 @@ PySideType_Ready(PyTypeObject *type)
return PyType_Ready(type);
}
-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;
- 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;
-}
-
static void
init_module_1(void)
{
@@ -680,20 +661,26 @@ static int
PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
const char *signatures)
{
- PyObject *type_name, *arg_tup;
- const char *name = NULL;
+ PyObject *type_key, *arg_tup;
- init_module_1();;
+ init_module_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;
+ /*
+ * We either get a module name or the dict of an EnclosingObject.
+ * We can ignore the EnclosingObject since we get full name info
+ * from the type.
+ */
+ if (PyModule_Check(module)) {
+ const char *name = PyModule_GetName(module);
+ if (name == NULL)
+ return -1;
+ if (strcmp(name, "testbinding") == 0)
+ return 0;
+ }
+ else
+ assert(PyDict_Check(module));
/*
* Normally, we would now just call the Python function with the
* arguments and then continue processing.
@@ -705,16 +692,17 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
* - by calling the python function late, we can freely import PySide
* without recursion problems.
*/
- type_name = PyObject_GetAttrString(type, "__name__");
- if (type_name == NULL)
+ type_key = GetClassKey(type);
+ if (type_key == nullptr)
return -1;
- if (PyDict_SetItem(pyside_globals->arg_dict, type_name, arg_tup) < 0)
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, 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().
+ * We record also a mapping from type key to type. This helps to lazily
+ * initialize the Py_LIMITED_API in name_key_to_func().
*/
- if (PyDict_SetItem(pyside_globals->map_dict, type_name, type) < 0)
+
+ if (PyDict_SetItem(pyside_globals->map_dict, type_key, type) < 0)
return -1;
return 0;
}
@@ -728,18 +716,20 @@ static PyMethodDef signature_methods[] = {
static void
init_module_2(void)
{
- static int init_done = 0;
+ static int init_done = 0, initializing = 0;
if (!init_done) {
+ if (initializing)
+ Py_FatalError("Init 2 called recursively!");
init_phase_2(pyside_globals, signature_methods);
init_done = 1;
+ initializing = 0;
}
}
static PyObject *
PySide_BuildSignatureProps(PyObject *classmod)
{
- PyObject *arg_tup, *dict, *type_name;
/*
* Here is the second part of the function.
* This part will be called on-demand when needed by some attribute.
@@ -747,20 +737,19 @@ PySide_BuildSignatureProps(PyObject *classmod)
* them by the function result.
*/
init_module_2();
- 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;
+ Shiboken::AutoDecRef type_key(GetClassKey(classmod));
+ if (type_key.isNull())
+ return nullptr;
+ PyObject *arg_tup = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ if (arg_tup == nullptr)
+ return nullptr;
+ PyObject *dict = PyObject_CallObject(pyside_globals->sigparse_func, arg_tup);
+ if (dict == nullptr)
+ return nullptr;
// 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);
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
+ return nullptr;
return dict;
}
@@ -779,17 +768,22 @@ SbkSpecial_Type_Ready(PyObject *module, PyTypeObject *type,
return ret;
}
+static int _finish_nested_classes(PyObject *dict);
+static int _build_func_to_type(PyObject *obtype);
+
static int
PySide_FinishSignatures(PyObject *module, const char *signatures)
{
- const char *name = NULL;
+ /*
+ * Initialization of module functions and resolving of static methods.
+ */
// CRUCIAL: Do not call this on "testbinding":
// The module is different and should not get signatures, anyway.
- name = PyModule_GetName(module);
+ const char *name = PyModule_GetName(module);
if (name == NULL)
return -1;
- if (strncmp(name, "PySide2.Qt", 10) != 0)
+ if (strcmp(name, "testbinding") == 0)
return 0;
// we abuse the call for types, since they both have a __name__ attribute.
@@ -797,9 +791,6 @@ PySide_FinishSignatures(PyObject *module, const char *signatures)
return -1;
/*
- * 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.
*
@@ -807,20 +798,72 @@ PySide_FinishSignatures(PyObject *module, const char *signatures)
* to the PyCFunction attributes. Therefore I simplified things
* and always use our own mapping.
*/
- {
- PyObject *key, *value;
- Py_ssize_t pos = 0;
- PyObject *dict = PyModule_GetDict(module);
+ PyObject *key, *func, *obdict = PyModule_GetDict(module);
+ Py_ssize_t pos = 0;
- if (dict == NULL)
- return -1;
+ while (PyDict_Next(obdict, &pos, &key, &func))
+ if (PyCFunction_Check(func))
+ if (PyDict_SetItem(pyside_globals->map_dict, func, module) < 0)
+ return -1;
+ if (_finish_nested_classes(obdict) < 0)
+ return -1;
+ return 0;
+}
+
+static int
+_finish_nested_classes(PyObject *obdict)
+{
+ PyObject *key, *value, *obtype;
+ PyTypeObject *subtype;
+ Py_ssize_t pos = 0;
- while (PyDict_Next(dict, &pos, &key, &value)) {
- if (PyType_Check(value)) {
- PyObject *type = value;
- if (build_func_to_type(type) < 0)
- return -1;
- }
+ if (obdict == NULL)
+ return -1;
+ while (PyDict_Next(obdict, &pos, &key, &value)) {
+ if (PyType_Check(value)) {
+ obtype = value;
+ if (_build_func_to_type(obtype) < 0)
+ return -1;
+ // now continue with nested cases
+ subtype = reinterpret_cast<PyTypeObject *>(obtype);
+ if (_finish_nested_classes(subtype->tp_dict) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+_build_func_to_type(PyObject *obtype)
+{
+ /*
+ * There is no general way to directly get the type of a static method.
+ * On Python 3, the type is hidden in an unused pointer in the
+ * PyCFunction structure, but the Limited API does not allow to access
+ * this, either.
+ *
+ * In the end, it was easier to avoid such tricks and build an explicit
+ * mapping from function to type.
+ *
+ * We walk through the method list of the type
+ * and record the mapping from function to this type in a dict.
+ */
+ PyTypeObject *type = reinterpret_cast<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;
+ Shiboken::AutoDecRef func(PyObject_GetAttrString(descr, "__func__"));
+ if (func.isNull() ||
+ PyDict_SetItem(pyside_globals->map_dict, func, obtype) < 0)
+ return -1;
}
}
return 0;
@@ -829,6 +872,12 @@ PySide_FinishSignatures(PyObject *module, const char *signatures)
void
FinishSignatureInitialization(PyObject *module, const char *signatures)
{
+ /*
+ * This function is called at the very end of a module
+ * initialization. SbkSpecial_Type_Ready has already been run
+ * with all the types.
+ * We now initialize module functions and resolve static methods.
+ */
if (PySide_FinishSignatures(module, signatures) < 0) {
PyErr_Print();
PyErr_SetNone(PyExc_ImportError);