aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken/signature/signature.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken/signature/signature.cpp')
-rw-r--r--sources/shiboken6/libshiboken/signature/signature.cpp184
1 files changed, 111 insertions, 73 deletions
diff --git a/sources/shiboken6/libshiboken/signature/signature.cpp b/sources/shiboken6/libshiboken/signature/signature.cpp
index 624d55a3e..3255cb56d 100644
--- a/sources/shiboken6/libshiboken/signature/signature.cpp
+++ b/sources/shiboken6/libshiboken/signature/signature.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
////////////////////////////////////////////////////////////////////////////
//
@@ -49,13 +13,16 @@
// General documentation can be found in `signature_doc.rst`.
//
+#include "signature.h"
+#include "signature_p.h"
+
#include "basewrapper.h"
#include "autodecref.h"
#include "sbkstring.h"
#include "sbkstaticstrings.h"
#include "sbkstaticstrings_p.h"
+#include "sbkfeature_base.h"
-#include "signature_p.h"
#include <structmember.h>
using namespace Shiboken;
@@ -86,6 +53,11 @@ PyObject *GetClassOrModOf(PyObject *ob)
Py_INCREF(ob);
return ob;
}
+#ifdef PYPY_VERSION
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr)
+ return _get_class_of_bm(ob);
+#endif
if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
return _get_class_of_cf(ob);
if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
@@ -113,7 +85,7 @@ PyObject *GetTypeKey(PyObject *ob)
module_name.reset(PyObject_GetAttr(ob, PyMagicName::name()));
return Py_BuildValue("O", module_name.object());
}
- AutoDecRef class_name(_get_qualname(ob));
+ AutoDecRef class_name(PyObject_GetAttr(ob, PyMagicName::qualname()));
if (class_name.isNull()) {
Py_FatalError("Signature: missing class name in GetTypeKey");
return nullptr;
@@ -123,7 +95,7 @@ PyObject *GetTypeKey(PyObject *ob)
static PyObject *empty_dict = nullptr;
-PyObject *TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype)
+PyObject *TypeKey_to_PropsDict(PyObject *type_key)
{
PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
if (dict == nullptr) {
@@ -164,6 +136,24 @@ static PyObject *_GetSignature_Cached(PyObject *props, PyObject *func_kind, PyOb
return Py_INCREF(value), value;
}
+#ifdef PYPY_VERSION
+PyObject *GetSignature_Method(PyObject *obfunc, PyObject *modifier)
+{
+ AutoDecRef obtype_mod(GetClassOrModOf(obfunc));
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ if (type_key.isNull())
+ Py_RETURN_NONE;
+ PyObject *dict = TypeKey_to_PropsDict(type_key);
+ if (dict == nullptr)
+ return nullptr;
+ AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name()));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+#endif
+
PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
{
// make sure that we look into PyCFunction, only...
@@ -173,7 +163,7 @@ PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
AutoDecRef type_key(GetTypeKey(obtype_mod));
if (type_key.isNull())
Py_RETURN_NONE;
- PyObject *dict = TypeKey_to_PropsDict(type_key, obtype_mod);
+ PyObject *dict = TypeKey_to_PropsDict(type_key);
if (dict == nullptr)
return nullptr;
AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name()));
@@ -183,7 +173,7 @@ PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
int flags = PyCFunction_GET_FLAGS(obfunc);
PyObject *func_kind;
- if (PyModule_Check(obtype_mod))
+ if (PyModule_Check(obtype_mod.object()))
func_kind = PyName::function();
else if (flags & METH_CLASS)
func_kind = PyName::classmethod();
@@ -201,13 +191,13 @@ PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
AutoDecRef class_key(GetTypeKey(objclass));
if (func_name.isNull() || objclass.isNull() || class_key.isNull())
return nullptr;
- PyObject *dict = TypeKey_to_PropsDict(class_key, objclass);
+ PyObject *dict = TypeKey_to_PropsDict(class_key);
if (dict == nullptr)
return nullptr;
PyObject *props = PyDict_GetItem(dict, func_name);
if (props == nullptr) {
// handle `__init__` like the class itself
- if (strcmp(String::toCString(func_name), "__init__") == 0)
+ if (PyUnicode_CompareWithASCIIString(func_name, "__init__") == 0)
return GetSignature_TypeMod(objclass, modifier);
Py_RETURN_NONE;
}
@@ -219,7 +209,7 @@ PyObject *GetSignature_TypeMod(PyObject *ob, PyObject *modifier)
AutoDecRef ob_name(PyObject_GetAttr(ob, PyMagicName::name()));
AutoDecRef ob_key(GetTypeKey(ob));
- PyObject *dict = TypeKey_to_PropsDict(ob_key, ob);
+ PyObject *dict = TypeKey_to_PropsDict(ob_key);
if (dict == nullptr)
return nullptr;
PyObject *props = PyDict_GetItem(dict, ob_name);
@@ -237,9 +227,17 @@ PyObject *GetSignature_TypeMod(PyObject *ob, PyObject *modifier)
// The `modifier` argument is a string that is passed in from `loader.py`.
// Configuration what the modifiers mean is completely in Python.
//
+// PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+//
PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
{
+#ifdef PYPY_VERSION
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr) {
+ return pyside_bm_get___signature__(ob, modifier);
+ }
+#endif
if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
return pyside_cf_get___signature__(ob, modifier);
if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
@@ -250,6 +248,9 @@ PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
return pyside_tp_get___signature__(ob, modifier);
if (Py_TYPE(ob) == &PyWrapperDescr_Type)
return pyside_wd_get___signature__(ob, modifier);
+ // For classmethods we use the simple wrapper description implementation.
+ if (Py_TYPE(ob) == &PyClassMethodDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
return nullptr;
}
@@ -258,8 +259,6 @@ static PyObject *get_signature(PyObject * /* self */, PyObject *args)
PyObject *ob;
PyObject *modifier = nullptr;
- init_module_1();
-
if (!PyArg_ParseTuple(args, "O|O", &ob, &modifier))
return nullptr;
if (Py_TYPE(ob) == PepFunction_TypePtr)
@@ -291,14 +290,25 @@ static PyObject *feature_import(PyObject * /* self */, PyObject *args, PyObject
if (import_func == nullptr) {
Py_FatalError("builtins has no \"__orig_import__\" function");
}
- return PyObject_Call(import_func, args, kwds);
+ ret = PyObject_Call(import_func, args, kwds);
+ if (ret) {
+ // PYSIDE-2029: Intercept after the import to search for PySide usage.
+ PyObject *post = PyObject_CallFunctionObjArgs(pyside_globals->feature_imported_func,
+ ret, nullptr);
+ Py_XDECREF(post);
+ if (post == nullptr) {
+ Py_DECREF(ret);
+ return nullptr;
+ }
+ }
+ return ret;
}
PyMethodDef signature_methods[] = {
- {"__feature_import__", (PyCFunction)feature_import, METH_VARARGS | METH_KEYWORDS},
+ {"__feature_import__", (PyCFunction)feature_import, METH_VARARGS | METH_KEYWORDS, nullptr},
{"get_signature", (PyCFunction)get_signature, METH_VARARGS,
- "get the __signature__, but pass an optional string parameter"},
- {nullptr, nullptr}
+ "get the signature, passing an optional string parameter"},
+ {nullptr, nullptr, 0, nullptr}
};
////////////////////////////////////////////////////////////////////////////
@@ -321,7 +331,6 @@ PyMethodDef signature_methods[] = {
static int PySide_BuildSignatureArgs(PyObject *obtype_mod, const char *signatures[])
{
- init_module_1();
AutoDecRef type_key(GetTypeKey(obtype_mod));
/*
* PYSIDE-996: Avoid string overflow in MSVC, which has a limit of
@@ -349,7 +358,6 @@ PyObject *PySide_BuildSignatureProps(PyObject *type_key)
* We simply pick up the arguments that we stored here and replace
* them by the function result.
*/
- init_module_2();
if (type_key == nullptr)
return nullptr;
PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key);
@@ -379,8 +387,24 @@ PyObject *PySide_BuildSignatureProps(PyObject *type_key)
//
////////////////////////////////////////////////////////////////////////////
+#ifdef PYPY_VERSION
+static bool get_lldebug_flag()
+{
+ auto *dic = PySys_GetObject("pypy_translation_info");
+ int lldebug = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug"));
+ int lldebug0 = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug0"));
+ return lldebug || lldebug0;
+}
+
+#endif
+
static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
{
+#ifdef PYPY_VERSION
+ static const bool have_problem = get_lldebug_flag();
+ if (have_problem)
+ return 0; // crash with lldebug at `PyDict_Next`
+#endif
/*
* Initialization of module functions and resolving of static methods.
*/
@@ -407,8 +431,6 @@ static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
if (PyCFunction_Check(func))
if (PyDict_SetItem(pyside_globals->map_dict, func, module) < 0)
return -1;
- if (_finish_nested_classes(obdict) < 0)
- return -1;
// The finish_import function will not work the first time since phase 2
// was not yet run. But that is ok, because the first import is always for
// the shiboken module (or a test module).
@@ -430,9 +452,12 @@ static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
int InitSignatureStrings(PyTypeObject *type, const char *signatures[])
{
+ // PYSIDE-2404: This function now also builds the mapping for static methods.
+ // It was one missing spot to let Lazy import work.
+ init_shibokensupport_module();
auto *ob_type = reinterpret_cast<PyObject *>(type);
int ret = PySide_BuildSignatureArgs(ob_type, signatures);
- if (ret < 0) {
+ if (ret < 0 || _build_func_to_type(ob_type) < 0) {
PyErr_Print();
PyErr_SetNone(PyExc_ImportError);
}
@@ -449,7 +474,17 @@ void FinishSignatureInitialization(PyObject *module, const char *signatures[])
* Still, it is not possible to call init phase 2 from here,
* because the import is still running. Do it from Python!
*/
- if ( PySide_PatchTypes() < 0
+ init_shibokensupport_module();
+
+#ifndef PYPY_VERSION
+ static const bool patch_types = true;
+#else
+ // PYSIDE-535: On PyPy we cannot patch builtin types. This can be
+ // re-implemented later. For now, we use `get_signature`, instead.
+ static const bool patch_types = false;
+#endif
+
+ if ((patch_types && PySide_PatchTypes() < 0)
|| PySide_FinishSignatures(module, signatures) < 0) {
PyErr_Print();
PyErr_SetNone(PyExc_ImportError);
@@ -491,7 +526,11 @@ static PyObject *adjustFuncName(const char *func_name)
return nullptr;
// Run `eval` on the type string to get the object.
+ // PYSIDE-1710: If the eval does not work, return the given string.
AutoDecRef obtype(PyRun_String(_path, Py_eval_input, ns, ns));
+ if (obtype.isNull())
+ return String::fromCString(func_name);
+
if (PyModule_Check(obtype.object())) {
// This is a plain function. Return the unmangled name.
return String::fromCString(func_name);
@@ -500,8 +539,8 @@ static PyObject *adjustFuncName(const char *func_name)
// Find the feature flags
auto type = reinterpret_cast<PyTypeObject *>(obtype.object());
- auto dict = type->tp_dict;
- int id = SbkObjectType_GetReserved(type);
+ AutoDecRef dict(PepType_GetDict(type));
+ int id = currentSelectId(type);
id = id < 0 ? 0 : id; // if undefined, set to zero
auto lower = id & 0x01;
auto is_prop = id & 0x02;
@@ -509,7 +548,7 @@ static PyObject *adjustFuncName(const char *func_name)
// Compute all needed info.
PyObject *name = String::getSnakeCaseName(_name, lower);
- PyObject *prop_name;
+ PyObject *prop_name{};
if (is_prop) {
PyObject *prop_methods = PyDict_GetItem(dict, PyMagicName::property_methods());
prop_name = PyDict_GetItem(prop_methods, name);
@@ -521,36 +560,37 @@ static PyObject *adjustFuncName(const char *func_name)
// Finally, generate the correct path expression.
char _buf[250 + 1] = {};
- if (is_prop) {
+ if (prop_name) {
auto _prop_name = String::toCString(prop_name);
if (is_class_prop)
- sprintf(_buf, "%s.__dict__['%s'].fset", _path, _prop_name);
+ snprintf(_buf, sizeof(_buf), "%s.__dict__['%s'].fset", _path, _prop_name);
else
- sprintf(_buf, "%s.%s.fset", _path, _prop_name);
+ snprintf(_buf, sizeof(_buf), "%s.%s.fset", _path, _prop_name);
}
else {
auto _name = String::toCString(name);
- sprintf(_buf, "%s.%s", _path, _name);
+ snprintf(_buf, sizeof(_buf), "%s.%s", _path, _name);
}
return String::fromCString(_buf);
}
void SetError_Argument(PyObject *args, const char *func_name, PyObject *info)
{
+ init_shibokensupport_module();
/*
* This function replaces the type error construction with extra
* overloads parameter in favor of using the signature module.
* Error messages are rare, so we do it completely in Python.
*/
- init_module_1();
- init_module_2();
// PYSIDE-1305: Handle errors set by fillQtProperties.
if (PyErr_Occurred()) {
PyObject *e, *v, *t;
// Note: These references are all borrowed.
PyErr_Fetch(&e, &v, &t);
+ Py_DECREF(e);
info = v;
+ Py_XDECREF(t);
}
// PYSIDE-1019: Modify the function name expression according to feature.
AutoDecRef new_func_name(adjustFuncName(func_name));
@@ -581,21 +621,19 @@ void SetError_Argument(PyObject *args, const char *func_name, PyObject *info)
* But the __doc__ attribute existed already by inheritance, and calling
* PyType_Modified() is not supported. So we added the getsets explicitly
* to the metatype.
+ *
+ * PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
*/
-PyObject *Sbk_TypeGet___signature__(PyObject *ob, PyObject *modifier)
-{
- return pyside_tp_get___signature__(ob, modifier);
-}
-
PyObject *Sbk_TypeGet___doc__(PyObject *ob)
{
+ init_shibokensupport_module();
return pyside_tp_get___doc__(ob);
}
PyObject *GetFeatureDict()
{
- init_module_1();
+ init_shibokensupport_module();
return pyside_globals->feature_dict;
}