aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);