aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build_scripts/utils.py20
-rw-r--r--coin_test_instructions.py7
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp4
-rw-r--r--sources/pyside2/doc/deployment-briefcase.rst4
-rw-r--r--sources/pyside2/doc/deployment.rst2
-rw-r--r--sources/pyside2/doc/faq.rst4
-rw-r--r--sources/pyside2/doc/gettingstarted.rst3
-rw-r--r--sources/pyside2/doc/index.rst4
-rw-r--r--sources/pyside2/doc/tutorials/portingguide/chapter3/chapter3.rst2
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst14
-rw-r--r--sources/pyside2/libpyside/pysideclassinfo.cpp2
-rw-r--r--sources/pyside2/libpyside/pysidemetafunction.cpp2
-rw-r--r--sources/pyside2/libpyside/pysideproperty.cpp2
-rw-r--r--sources/pyside2/libpyside/pysidesignal.cpp6
-rw-r--r--sources/pyside2/libpyside/pysideslot.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp10
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.h10
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp93
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h15
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.cpp8
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.h8
-rw-r--r--sources/shiboken2/ApiExtractor/propertyspec.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/propertyspec.h6
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h2
-rw-r--r--sources/shiboken2/ApiExtractor/typesystemparser.cpp5
-rw-r--r--sources/shiboken2/doc/index.rst4
-rw-r--r--sources/shiboken2/doc/typesystem_manipulating_objects.rst61
-rw-r--r--sources/shiboken2/doc/typesystem_sequenceprotocol.rst2
-rw-r--r--sources/shiboken2/generator/generator.cpp12
-rw-r--r--sources/shiboken2/generator/generator.h6
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp6
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp166
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h11
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp35
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h20
-rw-r--r--sources/shiboken2/libshiboken/CMakeLists.txt12
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp7
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h1
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp1264
-rw-r--r--sources/shiboken2/libshiboken/signature.h4
-rw-r--r--sources/shiboken2/libshiboken/signature/signature.cpp479
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_doc.rst (renamed from sources/shiboken2/libshiboken/signature_doc.rst)2
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_extend.cpp294
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_globals.cpp295
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_helper.cpp364
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_p.h106
-rw-r--r--sources/shiboken2/tests/libsample/pen.cpp10
-rw-r--r--sources/shiboken2/tests/libsample/pen.h5
-rw-r--r--sources/shiboken2/tests/libsample/removednamespaces.h36
-rw-r--r--sources/shiboken2/tests/samplebinding/pen_test.py14
-rw-r--r--sources/shiboken2/tests/samplebinding/typesystem_sample.xml7
51 files changed, 1929 insertions, 1532 deletions
diff --git a/build_scripts/utils.py b/build_scripts/utils.py
index 2ed0e2a2c..ad17a7ba8 100644
--- a/build_scripts/utils.py
+++ b/build_scripts/utils.py
@@ -1080,13 +1080,23 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
_pExe = "python.exe"
# With windows we are creating building 32-bit target in 64-bit host
if hostArch == "X86_64" and targetArch == "X86":
- if python_ver == "3":
- _pExe = os.path.join(os.getenv("PYTHON3_32_PATH"), "python.exe")
+ if python_ver.startswith("3"):
+ print("Try to find python from {} env variable".format("PYTHON"+python_ver+"-32_PATH"))
+ _path = os.getenv("PYTHON"+python_ver+"-32_PATH", "")
+ _pExe = os.path.join(_path, "python.exe")
+ if not os.path.isfile(_pExe):
+ print("Can't find python.exe from {}, using default python3".format(_pExe))
+ _pExe = os.path.join(os.getenv("PYTHON3_32_PATH"), "python.exe")
else:
- _pExe = os.path.join(os.getenv("PYTHON2_32_PATH"), "python.exe")
+ _pExe = os.path.join(os.getenv("PYTHON2_32_PATH"), "python.exe")
else:
- if python_ver == "3":
- _pExe = os.path.join(os.getenv("PYTHON3_PATH"), "python.exe")
+ if python_ver.startswith("3"):
+ print("Try to find python from {} env variable".format("PYTHON"+python_ver+"-64_PATH"))
+ _path = os.getenv("PYTHON"+python_ver+"-64_PATH", "")
+ _pExe = os.path.join(_path, "python.exe")
+ if not os.path.isfile(_pExe):
+ print("Can't find python.exe from {}, using default python3".format(_pExe))
+ _pExe = os.path.join(os.getenv("PYTHON3_PATH"), "python.exe")
env_python = _env + "\\Scripts\\python.exe"
env_pip = _env + "\\Scripts\\pip.exe"
else:
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index 16ba601f7..30d808e25 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -110,7 +110,12 @@ def run_test_instructions():
testRun =+ 1
# We know that second build was with python3
if CI_RELEASE_CONF:
- call_testrunner("3", str(testRun))
+ # In win machines, there are additional python versions to test with
+ if CI_HOST_OS == "Windows":
+ call_testrunner("3.6.1", str(testRun))
+ call_testrunner("3.8.1", str(testRun))
+ else:
+ call_testrunner("3", str(testRun))
if __name__ == "__main__":
run_test_instructions()
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index a933876e4..fd470cd71 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -626,7 +626,7 @@ static const char *VolatileBool_SignatureStrings[] = {
void PySide::initQmlSupport(PyObject *module)
{
// Export QmlListProperty type
- if (SbkSpecial_Type_Ready(module, PropertyListTypeF(), PropertyList_SignatureStrings) < 0) {
+ if (InitSignatureStrings(PropertyListTypeF(), PropertyList_SignatureStrings) < 0) {
PyErr_Print();
qWarning() << "Error initializing PropertyList type.";
return;
@@ -639,7 +639,7 @@ void PySide::initQmlSupport(PyObject *module)
PyModule_AddObject(module, PepType_GetNameStr(PropertyListTypeF()),
reinterpret_cast<PyObject *>(PropertyListTypeF()));
- if (SbkSpecial_Type_Ready(module, QtQml_VolatileBoolTypeF(), VolatileBool_SignatureStrings) < 0) {
+ if (InitSignatureStrings(QtQml_VolatileBoolTypeF(), VolatileBool_SignatureStrings) < 0) {
PyErr_Print();
qWarning() << "Error initializing VolatileBool type.";
return;
diff --git a/sources/pyside2/doc/deployment-briefcase.rst b/sources/pyside2/doc/deployment-briefcase.rst
index fec5e0d56..a5179a279 100644
--- a/sources/pyside2/doc/deployment-briefcase.rst
+++ b/sources/pyside2/doc/deployment-briefcase.rst
@@ -160,7 +160,7 @@ It creates a subdirectory each for the different platforms.
This step takes longer as it adds the packages listed in `requires` sections in the `pyproject.toml` file.
Build the application
----------------
+---------------------
::
briefcase build
@@ -175,7 +175,7 @@ You'll get::
Run the application
------------
+-------------------
::
briefcase run
diff --git a/sources/pyside2/doc/deployment.rst b/sources/pyside2/doc/deployment.rst
index 414a468ed..3d6aa218e 100644
--- a/sources/pyside2/doc/deployment.rst
+++ b/sources/pyside2/doc/deployment.rst
@@ -101,7 +101,7 @@ these tools don't offer a mechanism to update your application packages.
To create update packages, use the `PyUpdater <https://www.pyupdater.org/>`_, which is a tool
built around PyInstaller.
-The `fbs <https://build-system.fman.io>`_ tool offers a nice UI for the user to install the
+The `fbs`_ tool offers a nice UI for the user to install the
application step-by-step.
.. note::
diff --git a/sources/pyside2/doc/faq.rst b/sources/pyside2/doc/faq.rst
index f1aa3ebcc..b7e9816c8 100644
--- a/sources/pyside2/doc/faq.rst
+++ b/sources/pyside2/doc/faq.rst
@@ -1,3 +1,7 @@
+.. _faq:
+
+:orphan:
+
Frequently Asked Questions
==========================
diff --git a/sources/pyside2/doc/gettingstarted.rst b/sources/pyside2/doc/gettingstarted.rst
index b8d6f9e45..197657493 100644
--- a/sources/pyside2/doc/gettingstarted.rst
+++ b/sources/pyside2/doc/gettingstarted.rst
@@ -7,10 +7,9 @@ with ``pip`` you need to run::
pip install pyside2
for more details, refer to our `Quick Start`_ guide. Additionally, you can
-check the `FAQ`_ related to the project.
+check the :ref:`FAQ <faq>` related to the project.
.. _Quick Start: quickstart.html
-.. _FAQ: faq.html
General Requirements
--------------------
diff --git a/sources/pyside2/doc/index.rst b/sources/pyside2/doc/index.rst
index 289a653f3..ed5aeb6b4 100644
--- a/sources/pyside2/doc/index.rst
+++ b/sources/pyside2/doc/index.rst
@@ -5,13 +5,13 @@
**Qt for Python** offers the official Python bindings for `Qt`_ (`PySide2`_),
so that you can use Qt5 APIs in your Python applications, and a binding generator tool
- (`Shiboken2 <shiboken2/index.html>`_) which can be used to expose C++ projects into Python.
+ (`Shiboken2 <shiboken2/index.html>`__) which can be used to expose C++ projects into Python.
.. ifconfig:: output_format == 'qthelp'
**Qt for Python** offers the official Python bindings for `Qt`_ (`PySide2`_),
so that you can use Qt5 APIs in your Python applications, and a binding generator tool
- (`Shiboken2 <../shiboken2/index.html>`_) which can be used to expose C++ projects into Python.
+ (`Shiboken2 <../shiboken2/index.html>`__) which can be used to expose C++ projects into Python.
|project| is available under the LGPLv3/GPLv3 and the Qt commercial license.
diff --git a/sources/pyside2/doc/tutorials/portingguide/chapter3/chapter3.rst b/sources/pyside2/doc/tutorials/portingguide/chapter3/chapter3.rst
index 71b254811..6d7db9ef5 100644
--- a/sources/pyside2/doc/tutorials/portingguide/chapter3/chapter3.rst
+++ b/sources/pyside2/doc/tutorials/portingguide/chapter3/chapter3.rst
@@ -34,7 +34,7 @@ C++ version
.. literalinclude:: bookwindow.cpp
:language: c++
:linenos:
- :lines: 47-115
+ :lines: 57-140
Python version
---------------
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst b/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
index c26d154ac..f675f7899 100644
--- a/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
+++ b/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
@@ -99,9 +99,10 @@ There are three properties that are almost always set when using ApplicationWind
Once we've set these, we have a properly sized, empty window ready to be filled with content.
There are two ways of laying out items in QML: `Item Positioners`_ and `Qt Quick Layouts`_.
-* Item positioners (`Row`_, `Column`_, and so on) are useful for situations where the size of items
+
+- Item positioners (`Row`_, `Column`_, and so on) are useful for situations where the size of items
is known or fixed, and all that is required is to neatly position them in a certain formation.
-* The layouts in Qt Quick Layouts can both position and resize items, making them well suited for
+- The layouts in Qt Quick Layouts can both position and resize items, making them well suited for
resizable user interfaces.
Below, we use `ColumnLayout`_ to vertically lay out a `ListView`_ and a `Pane`_.
@@ -205,14 +206,15 @@ if it doesn't already exist.
A few interesting things happen in the ``main`` function:
-* Declaring a :ref:`QGuiApplication`.
+
+- Declaring a :ref:`QGuiApplication`.
You should use a :ref:`QGuiApplication` instead of :ref:`QApplication` because we're not
using the **QtWidgets** module.
-* Connecting to the database,
-* Declaring a :ref:`QQmlApplicationEngine`.
+- Connecting to the database,
+- Declaring a :ref:`QQmlApplicationEngine`.
This allows you to access the QML context property to connect Python
and QML from the conversation model we built on ``sqlDialog.py``.
-* Loading the ``.qml`` file that defines the UI.
+- Loading the ``.qml`` file that defines the UI.
Finally, the Qt application runs, and your program starts.
diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp
index 375a31b57..aa47f97c1 100644
--- a/sources/pyside2/libpyside/pysideclassinfo.cpp
+++ b/sources/pyside2/libpyside/pysideclassinfo.cpp
@@ -184,7 +184,7 @@ static const char *ClassInfo_SignatureStrings[] = {
void init(PyObject *module)
{
- if (SbkSpecial_Type_Ready(module, PySideClassInfoTypeF(), ClassInfo_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideClassInfoTypeF(), ClassInfo_SignatureStrings) < 0)
return;
Py_INCREF(PySideClassInfoTypeF());
diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp
index 0326e0f11..0b7799af1 100644
--- a/sources/pyside2/libpyside/pysidemetafunction.cpp
+++ b/sources/pyside2/libpyside/pysidemetafunction.cpp
@@ -107,7 +107,7 @@ static const char *MetaFunction_SignatureStrings[] = {
void init(PyObject *module)
{
- if (SbkSpecial_Type_Ready(module, PySideMetaFunctionTypeF(), MetaFunction_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideMetaFunctionTypeF(), MetaFunction_SignatureStrings) < 0)
return;
Py_INCREF(PySideMetaFunctionTypeF());
diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp
index c902afc0c..79464541d 100644
--- a/sources/pyside2/libpyside/pysideproperty.cpp
+++ b/sources/pyside2/libpyside/pysideproperty.cpp
@@ -357,7 +357,7 @@ static const char *Property_SignatureStrings[] = {
void init(PyObject *module)
{
- if (SbkSpecial_Type_Ready(module, PySidePropertyTypeF(), Property_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySidePropertyTypeF(), Property_SignatureStrings) < 0)
return;
Py_INCREF(PySidePropertyTypeF());
diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
index 1a9e5e115..f3fb4e06d 100644
--- a/sources/pyside2/libpyside/pysidesignal.cpp
+++ b/sources/pyside2/libpyside/pysidesignal.cpp
@@ -635,17 +635,17 @@ static const char *SignalInstance_SignatureStrings[] = {
void init(PyObject *module)
{
- if (SbkSpecial_Type_Ready(module, PySideMetaSignalTypeF(), MetaSignal_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideMetaSignalTypeF(), MetaSignal_SignatureStrings) < 0)
return;
Py_INCREF(PySideMetaSignalTypeF());
PyModule_AddObject(module, "MetaSignal", reinterpret_cast<PyObject *>(PySideMetaSignalTypeF()));
- if (SbkSpecial_Type_Ready(module, PySideSignalTypeF(), Signal_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideSignalTypeF(), Signal_SignatureStrings) < 0)
return;
Py_INCREF(PySideSignalTypeF());
PyModule_AddObject(module, "Signal", reinterpret_cast<PyObject *>(PySideSignalTypeF()));
- if (SbkSpecial_Type_Ready(module, PySideSignalInstanceTypeF(), SignalInstance_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideSignalInstanceTypeF(), SignalInstance_SignatureStrings) < 0)
return;
Py_INCREF(PySideSignalInstanceTypeF());
PyModule_AddObject(module, "SignalInstance", reinterpret_cast<PyObject *>(PySideSignalInstanceTypeF()));
diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp
index 7bfd1719a..1ec24ab21 100644
--- a/sources/pyside2/libpyside/pysideslot.cpp
+++ b/sources/pyside2/libpyside/pysideslot.cpp
@@ -188,7 +188,7 @@ static const char *Slot_SignatureStrings[] = {
void init(PyObject *module)
{
- if (SbkSpecial_Type_Ready(module, PySideSlotTypeF(), Slot_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideSlotTypeF(), Slot_SignatureStrings) < 0)
return;
Py_INCREF(PySideSlotTypeF());
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 4dccbf09d..899d910bc 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -135,27 +135,27 @@ AbstractMetaBuilder::~AbstractMetaBuilder()
delete d;
}
-AbstractMetaClassList AbstractMetaBuilder::classes() const
+const AbstractMetaClassList &AbstractMetaBuilder::classes() const
{
return d->m_metaClasses;
}
-AbstractMetaClassList AbstractMetaBuilder::templates() const
+const AbstractMetaClassList &AbstractMetaBuilder::templates() const
{
return d->m_templates;
}
-AbstractMetaClassList AbstractMetaBuilder::smartPointers() const
+const AbstractMetaClassList &AbstractMetaBuilder::smartPointers() const
{
return d->m_smartPointers;
}
-AbstractMetaFunctionList AbstractMetaBuilder::globalFunctions() const
+const AbstractMetaFunctionList &AbstractMetaBuilder::globalFunctions() const
{
return d->m_globalFunctions;
}
-AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const
+const AbstractMetaEnumList &AbstractMetaBuilder::globalEnums() const
{
return d->m_globalEnums;
}
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
index 37022a544..d2dc080a2 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
@@ -63,11 +63,11 @@ public:
AbstractMetaBuilder();
virtual ~AbstractMetaBuilder();
- AbstractMetaClassList classes() const;
- AbstractMetaClassList templates() const;
- AbstractMetaClassList smartPointers() const;
- AbstractMetaFunctionList globalFunctions() const;
- AbstractMetaEnumList globalEnums() const;
+ const AbstractMetaClassList &classes() const;
+ const AbstractMetaClassList &templates() const;
+ const AbstractMetaClassList &smartPointers() const;
+ const AbstractMetaFunctionList &globalFunctions() const;
+ const AbstractMetaEnumList &globalEnums() const;
AbstractMetaEnum *findEnum(const TypeEntry *typeEntry) const;
/**
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index e300fd827..7d98d9ae8 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -1564,16 +1564,6 @@ void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
}
}
-bool AbstractMetaClass::hasFieldAccessors() const
-{
- for (const AbstractMetaField *field : m_fields) {
- if (field->getter() || field->setter())
- return true;
- }
-
- return false;
-}
-
bool AbstractMetaClass::hasDefaultToStringFunction() const
{
const AbstractMetaFunctionList &funcs = queryFunctionsByName(QLatin1String("toString"));
@@ -1769,12 +1759,6 @@ static bool functions_contains(const AbstractMetaFunctionList &l, const Abstract
AbstractMetaField::AbstractMetaField() = default;
-AbstractMetaField::~AbstractMetaField()
-{
- delete m_setter;
- delete m_getter;
-}
-
AbstractMetaField *AbstractMetaField::copy() const
{
auto *returned = new AbstractMetaField;
@@ -1806,55 +1790,6 @@ bool AbstractMetaField::isModifiedRemoved(int types) const
return false;
}
-static QString upCaseFirst(const QString &str)
-{
- Q_ASSERT(!str.isEmpty());
- QString s = str;
- s[0] = s.at(0).toUpper();
- return s;
-}
-
-static AbstractMetaFunction *createXetter(const AbstractMetaField *g, const QString &name,
- AbstractMetaAttributes::Attributes type)
-{
- auto *f = new AbstractMetaFunction;
-
- f->setName(name);
- f->setOriginalName(name);
- f->setOwnerClass(g->enclosingClass());
- f->setImplementingClass(g->enclosingClass());
- f->setDeclaringClass(g->enclosingClass());
-
- AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::FinalInTargetLang | type;
- if (g->isStatic())
- attr |= AbstractMetaAttributes::Static;
- if (g->isPublic())
- attr |= AbstractMetaAttributes::Public;
- else if (g->isProtected())
- attr |= AbstractMetaAttributes::Protected;
- else
- attr |= AbstractMetaAttributes::Private;
- f->setAttributes(attr);
- f->setOriginalAttributes(attr);
-
- const FieldModificationList &mods = g->modifications();
- for (const FieldModification &mod : mods) {
- if (mod.isRenameModifier())
- f->setName(mod.renamedTo());
- if (mod.isAccessModifier()) {
- if (mod.isPrivate())
- f->setVisibility(AbstractMetaAttributes::Private);
- else if (mod.isProtected())
- f->setVisibility(AbstractMetaAttributes::Protected);
- else if (mod.isPublic())
- f->setVisibility(AbstractMetaAttributes::Public);
- else if (mod.isFriendly())
- f->setVisibility(AbstractMetaAttributes::Friendly);
- }
- }
- return f;
-}
-
FieldModificationList AbstractMetaField::modifications() const
{
const FieldModificationList &mods = enclosingClass()->typeEntry()->fieldModifications();
@@ -1868,22 +1803,6 @@ FieldModificationList AbstractMetaField::modifications() const
return returned;
}
-const AbstractMetaFunction *AbstractMetaField::setter() const
-{
- if (!m_setter) {
- m_setter = createXetter(this,
- QLatin1String("set") + upCaseFirst(name()),
- AbstractMetaAttributes::SetterFunction);
- AbstractMetaArgumentList arguments;
- auto *argument = new AbstractMetaArgument;
- argument->setType(type()->copy());
- argument->setName(name());
- arguments.append(argument);
- m_setter->setArguments(arguments);
- }
- return m_setter;
-}
-
const AbstractMetaClass *EnclosingClassMixin::targetLangEnclosingClass() const
{
auto result = m_enclosingClass;
@@ -1892,18 +1811,6 @@ const AbstractMetaClass *EnclosingClassMixin::targetLangEnclosingClass() const
return result;
}
-const AbstractMetaFunction *AbstractMetaField::getter() const
-{
- if (!m_getter) {
- m_getter = createXetter(this,
- name(),
- AbstractMetaAttributes::GetterFunction);
- m_getter->setType(type());
- }
-
- return m_getter;
-}
-
#ifndef QT_NO_DEBUG_STREAM
static void formatMetaAttributes(QDebug &d, AbstractMetaAttributes::Attributes value)
{
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index c17051f45..466464807 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -717,10 +717,6 @@ class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttrib
{
public:
AbstractMetaField();
- ~AbstractMetaField();
-
- const AbstractMetaFunction *getter() const;
- const AbstractMetaFunction *setter() const;
FieldModificationList modifications() const;
@@ -733,10 +729,6 @@ public:
static AbstractMetaField *
find(const AbstractMetaFieldList &haystack, const QString &needle);
-
-private:
- mutable AbstractMetaFunction *m_getter = nullptr;
- mutable AbstractMetaFunction *m_setter = nullptr;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -1538,8 +1530,6 @@ public:
m_templateArgs = args;
}
- bool hasFieldAccessors() const;
-
// only valid during metabuilder's run
QStringList baseClassNames() const
{
@@ -1602,10 +1592,7 @@ public:
m_propertySpecs << spec;
}
- QVector<QPropertySpec *> propertySpecs() const
- {
- return m_propertySpecs;
- }
+ const QVector<QPropertySpec *> &propertySpecs() const { return m_propertySpecs; }
QPropertySpec *propertySpecByName(const QString &name) const;
QPropertySpec *propertySpecForRead(const QString &name) const;
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp
index 530ed0252..3fdd613ae 100644
--- a/sources/shiboken2/ApiExtractor/apiextractor.cpp
+++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp
@@ -121,25 +121,25 @@ void ApiExtractor::setDropTypeEntries(QString dropEntries)
TypeDatabase::instance()->setDropTypeEntries(entries);
}
-AbstractMetaEnumList ApiExtractor::globalEnums() const
+const AbstractMetaEnumList &ApiExtractor::globalEnums() const
{
Q_ASSERT(m_builder);
return m_builder->globalEnums();
}
-AbstractMetaFunctionList ApiExtractor::globalFunctions() const
+const AbstractMetaFunctionList &ApiExtractor::globalFunctions() const
{
Q_ASSERT(m_builder);
return m_builder->globalFunctions();
}
-AbstractMetaClassList ApiExtractor::classes() const
+const AbstractMetaClassList &ApiExtractor::classes() const
{
Q_ASSERT(m_builder);
return m_builder->classes();
}
-AbstractMetaClassList ApiExtractor::smartPointers() const
+const AbstractMetaClassList &ApiExtractor::smartPointers() const
{
Q_ASSERT(m_builder);
return m_builder->smartPointers();
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.h b/sources/shiboken2/ApiExtractor/apiextractor.h
index f6dd2ba8e..b0c2c696f 100644
--- a/sources/shiboken2/ApiExtractor/apiextractor.h
+++ b/sources/shiboken2/ApiExtractor/apiextractor.h
@@ -81,10 +81,10 @@ public:
LanguageLevel languageLevel() const;
void setLanguageLevel(LanguageLevel languageLevel);
- AbstractMetaEnumList globalEnums() const;
- AbstractMetaFunctionList globalFunctions() const;
- AbstractMetaClassList classes() const;
- AbstractMetaClassList smartPointers() const;
+ const AbstractMetaEnumList &globalEnums() const;
+ const AbstractMetaFunctionList &globalFunctions() const;
+ const AbstractMetaClassList &classes() const;
+ const AbstractMetaClassList &smartPointers() const;
AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;
PrimitiveTypeEntryList primitiveTypes() const;
ContainerTypeEntryList containerTypes() const;
diff --git a/sources/shiboken2/ApiExtractor/propertyspec.cpp b/sources/shiboken2/ApiExtractor/propertyspec.cpp
index fcb8286bf..f86a31d5b 100644
--- a/sources/shiboken2/ApiExtractor/propertyspec.cpp
+++ b/sources/shiboken2/ApiExtractor/propertyspec.cpp
@@ -48,7 +48,8 @@ QPropertySpec::QPropertySpec(const TypeSystemProperty &ts,
m_write(ts.write),
m_designable(ts.designable),
m_reset(ts.reset),
- m_type(type)
+ m_type(type),
+ m_generateGetSetDef(ts.generateGetSetDef)
{
}
diff --git a/sources/shiboken2/ApiExtractor/propertyspec.h b/sources/shiboken2/ApiExtractor/propertyspec.h
index 4abe75c84..611d4726e 100644
--- a/sources/shiboken2/ApiExtractor/propertyspec.h
+++ b/sources/shiboken2/ApiExtractor/propertyspec.h
@@ -79,6 +79,7 @@ public:
QString write() const { return m_write; }
void setWrite(const QString &write) { m_write = write; }
+ bool hasWrite() const { return !m_write.isEmpty(); }
QString designable() const { return m_designable; }
void setDesignable(const QString &designable) { m_designable = designable; }
@@ -89,6 +90,9 @@ public:
int index() const { return m_index; }
void setIndex(int index) {m_index = index; }
+ bool generateGetSetDef() const { return m_generateGetSetDef; }
+ void setGenerateGetSetDef(bool generateGetSetDef) { m_generateGetSetDef = generateGetSetDef; }
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const;
#endif
@@ -101,6 +105,8 @@ private:
QString m_reset;
const AbstractMetaType *m_type = nullptr;
int m_index = -1;
+ // Indicates whether actual code is generated instead of relying on libpyside.
+ bool m_generateGetSetDef = false;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h
index a4e96548b..fa3eae9fc 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.h
+++ b/sources/shiboken2/ApiExtractor/typesystem.h
@@ -563,6 +563,8 @@ struct TypeSystemProperty
QString write;
QString reset;
QString designable;
+ // Indicates whether actual code is generated instead of relying on libpyside.
+ bool generateGetSetDef = false;
};
class TypeEntry
diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp
index f54ad50f4..b71a247f3 100644
--- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp
@@ -70,6 +70,7 @@ static inline QString formatAttribute() { return QStringLiteral("format"); }
static inline QString generateUsingAttribute() { return QStringLiteral("generate-using"); }
static inline QString classAttribute() { return QStringLiteral("class"); }
static inline QString generateAttribute() { return QStringLiteral("generate"); }
+static inline QString generateGetSetDefAttribute() { return QStringLiteral("generate-getsetdef"); }
static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); }
static inline QString indexAttribute() { return QStringLiteral("index"); }
static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); }
@@ -2259,6 +2260,10 @@ bool TypeSystemParser::parseProperty(const QXmlStreamReader &, const StackElemen
property.type = attributes->takeAt(i).value().toString();
} else if (name == QLatin1String("set")) {
property.write = attributes->takeAt(i).value().toString();
+ } else if (name == generateGetSetDefAttribute()) {
+ property.generateGetSetDef =
+ convertBoolean(attributes->takeAt(i).value(),
+ generateGetSetDefAttribute(), false);
}
}
if (!property.isValid()) {
diff --git a/sources/shiboken2/doc/index.rst b/sources/shiboken2/doc/index.rst
index a6e1bccd4..ebde8d1ff 100644
--- a/sources/shiboken2/doc/index.rst
+++ b/sources/shiboken2/doc/index.rst
@@ -3,11 +3,11 @@ Shiboken
.. ifconfig:: output_format == 'html'
- Shiboken is a fundamental piece on the `Qt for Python <../index.html>`_ project that serves two purposes:
+ Shiboken is a fundamental piece on the `Qt for Python <../index.html>`__ project that serves two purposes:
.. ifconfig:: output_format == 'qthelp'
- Shiboken is a fundamental piece on the `Qt for Python <../pyside2/index.html>`_ project that serves two purposes:
+ Shiboken is a fundamental piece on the `Qt for Python <../pyside2/index.html>`__ project that serves two purposes:
* Generator_: Extract information from C or C++ headers and generate CPython_ code that allow
diff --git a/sources/shiboken2/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/doc/typesystem_manipulating_objects.rst
index 98f503074..d87b816a3 100644
--- a/sources/shiboken2/doc/typesystem_manipulating_objects.rst
+++ b/sources/shiboken2/doc/typesystem_manipulating_objects.rst
@@ -206,7 +206,7 @@ add-function
Within the signature, names for the function parameters can be specified by
enclosing them within the delimiter *@*:
- .. code-block:: c++
+ .. code-block::
void foo(int @parameter1@,float)
@@ -238,14 +238,23 @@ conversion-rule
property
^^^^^^^^
- The ``property`` element allows you to add properties complementing the
- properties obtained from the ``Q_PROPERTY`` macro in Qt-based code when using
- the PySide2 extension. It may appear as a child of a complex type such as
- ``object-type`` or ``value-type``.
+ The ``property`` element allows you to specify properties consisting of
+ a type and getter and setter functions.
+
+ It may appear as a child of a complex type such as ``object-type`` or
+ ``value-type``.
+
+ If the PySide2 extension is not present, code will be generated using the
+ ``PyGetSetDef`` struct, similar to what is generated for fields.
+
+ If the PySide2 extension is present, those properties complement the
+ properties obtained from the ``Q_PROPERTY`` macro in Qt-based code.
+ The properties will be handled in ``libpyside`` unless code generation
+ is forced.
.. code-block:: xml
- <property name="..." type="..." get="..." set="..." since="..."/>
+ <property name="..." type="..." get="..." set="..." " generate-getsetdef="yes | no" since="..."/>
The ``name`` attribute specifies the name of the property, the ``type``
attribute specifies the C++ type and the ``get`` attribute specifies the
@@ -253,15 +262,49 @@ property
The optional ``set`` attribute specifies name of the setter function.
+ The optional ``generate-getsetdef`` attribute specifies whether to generate
+ code for if the PySide2 extension is present (indicating this property is not
+ handled by libpyside). It defaults to *no*.
+
The optional ``since`` attribute specifies the API version when this
property appears.
- For example:
+ For a typical C++ class, like:
+
+ .. code-block:: c++
+
+ class Test {
+ public:
+ int getValue() const;
+ void setValue();
+ };
+
+ ``value`` can then be specified to be a property:
+
+ .. code-block:: xml
+
+ <value-type name="Test">
+ <property name="value" type="int" get="getValue" set="setValue"/>
+
+ With that, a more pythonic style can be used:
+
+ .. code-block:: python
+
+ test = Test()
+ test.value = 42
+
+ For Qt classes (with the PySide2 extension present), additional setters
+ and getters that do not appear as ``Q_PROPERTY``, can be specified to
+ be properties:
.. code-block:: xml
<object-type name="QMainWindow">
<property name="centralWidget" type="QWidget *" get="centralWidget" set="setCentralWidget"/>
- specifies ``centralWidget`` to be a Python property in addition to the normal properties
- of ``QMainWindow`` defined for Qt Designer usage.
+ in addition to the normal properties of ``QMainWindow`` defined for
+ Qt Designer usage.
+
+ .. note:: In the *Qt* coding style, the property name typically conflicts
+ with the getter name. It is recommended to exclude the getter from the
+ wrapper generation using the ``remove`` function modification.
diff --git a/sources/shiboken2/doc/typesystem_sequenceprotocol.rst b/sources/shiboken2/doc/typesystem_sequenceprotocol.rst
index 26ae3b220..742be3d70 100644
--- a/sources/shiboken2/doc/typesystem_sequenceprotocol.rst
+++ b/sources/shiboken2/doc/typesystem_sequenceprotocol.rst
@@ -22,7 +22,7 @@ function with parameters and return type defined by the table above.
The function needs to follow the same semantics of the *CPython equivalent*
function, the only way to do it is using the
-:doc:`inject-code <codeinjectionsemantics>` tag.
+:ref:`inject-code <codeinjectionsemantics>` tag.
A concrete example how to add sequence protocol support to a class can be found
on shiboken tests, more precisely in the definition of the Str class in
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index d3b52cdcb..5fa462bef 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -313,11 +313,9 @@ void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMeta
void Generator::collectInstantiatedContainersAndSmartPointers()
{
- const AbstractMetaFunctionList &funcs = globalFunctions();
- for (const AbstractMetaFunction *func : funcs)
+ for (const AbstractMetaFunction *func : globalFunctions())
collectInstantiatedContainersAndSmartPointers(func);
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList)
+ for (const AbstractMetaClass *metaClass : classes())
collectInstantiatedContainersAndSmartPointers(metaClass);
}
@@ -341,7 +339,7 @@ bool Generator::handleOption(const QString & /* key */, const QString & /* value
return false;
}
-AbstractMetaClassList Generator::classes() const
+const AbstractMetaClassList &Generator::classes() const
{
return m_d->apiextractor->classes();
}
@@ -351,12 +349,12 @@ AbstractMetaClassList Generator::classesTopologicalSorted(const Dependencies &ad
return m_d->apiextractor->classesTopologicalSorted(additionalDependencies);
}
-AbstractMetaFunctionList Generator::globalFunctions() const
+const AbstractMetaFunctionList &Generator::globalFunctions() const
{
return m_d->apiextractor->globalFunctions();
}
-AbstractMetaEnumList Generator::globalEnums() const
+const AbstractMetaEnumList &Generator::globalEnums() const
{
return m_d->apiextractor->globalEnums();
}
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
index 5a55422a1..324bb8474 100644
--- a/sources/shiboken2/generator/generator.h
+++ b/sources/shiboken2/generator/generator.h
@@ -216,7 +216,7 @@ public:
virtual bool handleOption(const QString &key, const QString &value);
/// Returns the classes used to generate the binding code.
- AbstractMetaClassList classes() const;
+ const AbstractMetaClassList &classes() const;
/// Returns the output directory
QString outputDirectory() const;
@@ -285,10 +285,10 @@ protected:
AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;
/// Returns all global functions found by APIExtractor
- AbstractMetaFunctionList globalFunctions() const;
+ const AbstractMetaFunctionList &globalFunctions() const;
/// Returns all global enums found by APIExtractor
- AbstractMetaEnumList globalEnums() const;
+ const AbstractMetaEnumList &globalEnums() const;
/// Returns all primitive types found by APIExtractor
PrimitiveTypeEntryList primitiveTypes() const;
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index 1386fd3d9..1a7c195b4 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -411,8 +411,7 @@ QString QtXmlToSphinx::expandFunction(const QString& function) const
const AbstractMetaClass *metaClass = nullptr;
if (firstDot != -1) {
const auto className = QStringView{function}.left(firstDot);
- const AbstractMetaClassList &classes = m_generator->classes();
- for (const AbstractMetaClass *cls : classes) {
+ for (const AbstractMetaClass *cls : m_generator->classes()) {
if (cls->name() == className) {
metaClass = cls;
break;
@@ -431,8 +430,7 @@ QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) const
const auto currentClass = QStringView{m_context}.split(QLatin1Char('.')).constLast();
const AbstractMetaClass *metaClass = nullptr;
- const AbstractMetaClassList &classes = m_generator->classes();
- for (const AbstractMetaClass *cls : classes) {
+ for (const AbstractMetaClass *cls : m_generator->classes()) {
if (cls->name() == currentClass) {
metaClass = cls;
break;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 851498f80..75633c072 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -317,6 +317,13 @@ static QString buildPropertyString(QPropertySpec *spec)
return text;
}
+static void writePyGetSetDefEntry(QTextStream &s, const QString &name,
+ const QString &getFunc, const QString &setFunc)
+{
+ s << "{const_cast<char *>(\"" << name << "\"), " << getFunc << ", "
+ << (setFunc.isEmpty() ? QLatin1String(NULL_PTR) : setFunc) << "},\n";
+}
+
/*!
Function used to write the class generated binding code on the buffer
\param s the output buffer
@@ -590,12 +597,14 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo
// PYSIDE-1019: Write a compressed list of all properties `name:getter[:setter]`.
// Default values are suppressed.
QStringList sorter;
- for (const auto spec : metaClass->propertySpecs())
- sorter.append(buildPropertyString(spec));
+ for (const auto spec : metaClass->propertySpecs()) {
+ if (!spec->generateGetSetDef())
+ sorter.append(buildPropertyString(spec));
+ }
sorter.sort();
s << '\n';
- s << "static const char *" << className << "_properties[] = {\n";
+ s << "static const char *" << className << "_PropertyStrings[] = {\n";
for (const auto &entry : qAsConst(sorter))
s << INDENT << entry << ",\n";
s << INDENT << NULL_PTR << " // Sentinel\n";
@@ -689,19 +698,34 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo
s << Qt::endl;
}
+ for (const QPropertySpec *property : metaClass->propertySpecs()) {
+ if (property->generateGetSetDef() || !usePySideExtensions()) {
+ writeGetterFunction(s, property, classContext);
+ if (property->hasWrite())
+ writeSetterFunction(s, property, classContext);
+ }
+ }
+
s << "// Getters and Setters for " << metaClass->name() << Qt::endl;
s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {\n";
for (const AbstractMetaField *metaField : fields) {
- if (metaField->isStatic())
- continue;
+ if (!metaField->isStatic()) {
+ s << INDENT;
+ const QString setter = canGenerateFieldSetter(metaField)
+ ? cpythonSetterFunctionName(metaField) : QString();
+ writePyGetSetDefEntry(s, metaField->name(),
+ cpythonGetterFunctionName(metaField), setter);
+ }
+ }
- s << INDENT << "{const_cast<char *>(\"" << metaField->name() << "\"), ";
- s << cpythonGetterFunctionName(metaField) << ", ";
- if (canGenerateFieldSetter(metaField))
- s << cpythonSetterFunctionName(metaField);
- else
- s << NULL_PTR;
- s << "},\n";
+ for (const QPropertySpec *property : metaClass->propertySpecs()) {
+ if (property->generateGetSetDef() || !usePySideExtensions()) {
+ s << INDENT;
+ const QString setter = property->hasWrite()
+ ? cpythonSetterFunctionName(property, metaClass) : QString();
+ writePyGetSetDefEntry(s, property->name(),
+ cpythonGetterFunctionName(property, metaClass), setter);
+ }
}
s << INDENT << '{' << NULL_PTR << "} // Sentinel\n";
s << "};\n\n";
@@ -3972,6 +3996,13 @@ bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass *metaClass)
if (!f->isStatic())
return true;
}
+ // Generate all user-added properties unless Pyside extensions are used,
+ // in which only the explicitly specified ones are generated (rest is handled
+ // in libpyside).
+ return usePySideExtensions()
+ ? std::any_of(metaClass->propertySpecs().cbegin(), metaClass->propertySpecs().cend(),
+ [] (const QPropertySpec *s) { return s->generateGetSetDef(); })
+ : !metaClass->propertySpecs().isEmpty();
return false;
}
@@ -4399,13 +4430,18 @@ void CppGenerator::writeCopyFunction(QTextStream &s, const GeneratorContext &con
s << Qt::endl;
}
+static inline void writeGetterFunctionStart(QTextStream &s, const QString &funcName)
+{
+ s << "static PyObject *" << funcName << "(PyObject *self, void *)\n";
+ s << "{\n";
+}
+
void CppGenerator::writeGetterFunction(QTextStream &s,
const AbstractMetaField *metaField,
const GeneratorContext &context)
{
ErrorCode errorCode(QString::fromLatin1(NULL_PTR));
- s << "static PyObject *" << cpythonGetterFunctionName(metaField) << "(PyObject *self, void *)\n";
- s << "{\n";
+ writeGetterFunctionStart(s, cpythonGetterFunctionName(metaField));
writeCppSelfDefinition(s, context);
@@ -4453,11 +4489,16 @@ void CppGenerator::writeGetterFunction(QTextStream &s,
<< "reinterpret_cast<SbkObject *>(self), reinterpret_cast<SbkObjectType *>("
<< cpythonTypeNameExt(fieldType)
<< ")));\n";
- s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n";
+ s << INDENT << "if (pyOut) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_IncRef(pyOut);\n"
+ << INDENT << "return pyOut;\n";
+ }
+ s << INDENT << "}\n";
}
- s << INDENT << "}\n";
// Check if field wrapper has already been created.
- s << INDENT << "else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n";
+ s << INDENT << "} else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n";
{
Indentation indent(INDENT);
s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper("
@@ -4481,12 +4522,35 @@ void CppGenerator::writeGetterFunction(QTextStream &s,
s << "}\n";
}
-void CppGenerator::writeSetterFunction(QTextStream &s,
- const AbstractMetaField *metaField,
+// Write a getter for QPropertySpec
+void CppGenerator::writeGetterFunction(QTextStream &s, const QPropertySpec *property,
const GeneratorContext &context)
{
ErrorCode errorCode(0);
- s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject *self, PyObject *pyIn, void *)\n";
+ writeGetterFunctionStart(s, cpythonGetterFunctionName(property, context.metaClass()));
+ writeCppSelfDefinition(s, context);
+ const QString value = QStringLiteral("value");
+ s << INDENT << "auto " << value << " = " << CPP_SELF_VAR << "->" << property->read() << "();\n"
+ << INDENT << "auto pyResult = ";
+ writeToPythonConversion(s, property->type(), context.metaClass(), value);
+ s << ";\n"
+ << INDENT << "if (PyErr_Occurred() || !pyResult) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_XDECREF(pyResult);\n"
+ << INDENT << " return {};\n";
+ }
+ s << INDENT << "}\n"
+ << INDENT << "return pyResult;\n}\n\n";
+}
+
+// Write setter function preamble (type checks on "pyIn")
+void CppGenerator::writeSetterFunctionPreamble(QTextStream &s, const QString &name,
+ const QString &funcName,
+ const AbstractMetaType *type,
+ const GeneratorContext &context)
+{
+ s << "static int " << funcName << "(PyObject *self, PyObject *pyIn, void *)\n";
s << "{\n";
writeCppSelfDefinition(s, context);
@@ -4495,24 +4559,33 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'";
- s << metaField->name() << "' may not be deleted\");\n";
+ s << name << "' may not be deleted\");\n";
s << INDENT << "return -1;\n";
}
s << INDENT << "}\n";
- AbstractMetaType *fieldType = metaField->type();
-
s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};\n";
s << INDENT << "if (!";
- writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry()));
+ writeTypeCheck(s, type, QLatin1String("pyIn"), isNumber(type->typeEntry()));
s << ") {\n";
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '";
- s << metaField->name() << "', '" << fieldType->name() << "' or convertible type expected\");\n";
+ s << name << "', '" << type->name() << "' or convertible type expected\");\n";
s << INDENT << "return -1;\n";
}
s << INDENT<< "}\n\n";
+}
+
+void CppGenerator::writeSetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ const GeneratorContext &context)
+{
+ ErrorCode errorCode(0);
+
+ AbstractMetaType *fieldType = metaField->type();
+ writeSetterFunctionPreamble(s, metaField->name(), cpythonSetterFunctionName(metaField),
+ fieldType, context);
QString cppField = QString::fromLatin1("%1->%2").arg(QLatin1String(CPP_SELF_VAR), metaField->name());
s << INDENT;
@@ -4546,6 +4619,26 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
s << "}\n";
}
+// Write a setter for QPropertySpec
+void CppGenerator::writeSetterFunction(QTextStream &s, const QPropertySpec *property,
+ const GeneratorContext &context)
+{
+ ErrorCode errorCode(0);
+ writeSetterFunctionPreamble(s, property->name(),
+ cpythonSetterFunctionName(property, context.metaClass()),
+ property->type(), context);
+
+ s << INDENT << "auto cppOut = " << CPP_SELF_VAR << "->" << property->read() << "();\n"
+ << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);\n"
+ << INDENT << "if (PyErr_Occurred())\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return -1;\n";
+ }
+ s << INDENT << CPP_SELF_VAR << "->" << property->write() << "(cppOut);\n"
+ << INDENT << "return 0;\n}\n\n";
+}
+
void CppGenerator::writeRichCompareFunction(QTextStream &s, const GeneratorContext &context)
{
const AbstractMetaClass *metaClass = context.metaClass();
@@ -5139,10 +5232,7 @@ void CppGenerator::writeClassRegister(QTextStream &s,
// 4:typeSpec
s << INDENT << '&' << chopType(pyTypeName) << "_spec,\n";
- // 5:signatureStrings
- s << INDENT << initFunctionName << "_SignatureStrings,\n";
-
- // 6:cppObjDtor
+ // 5:cppObjDtor
s << INDENT;
if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
QString dtorClassName = metaClass->qualifiedCppName();
@@ -5158,7 +5248,7 @@ void CppGenerator::writeClassRegister(QTextStream &s,
s << "0,\n";
}
- // 7:baseType
+ // 6:baseType
const auto base = metaClass->isNamespace()
? metaClass->extendedNamespace() : metaClass->baseClass();
if (base) {
@@ -5168,13 +5258,13 @@ void CppGenerator::writeClassRegister(QTextStream &s,
s << INDENT << "0,\n";
}
- // 8:baseTypes
+ // 7:baseTypes
if (metaClass->baseClassNames().size() > 1)
s << INDENT << pyTypeBasesVariable << ',' << Qt::endl;
else
s << INDENT << "0,\n";
- // 9:wrapperflags
+ // 8:wrapperflags
QByteArrayList wrapperFlags;
if (enc)
wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
@@ -5188,11 +5278,12 @@ void CppGenerator::writeClassRegister(QTextStream &s,
s << INDENT << ");\n";
s << INDENT << Qt::endl;
- if (usePySideExtensions()) {
- QString className = metaClass->qualifiedCppName();
+ s << INDENT << "auto pyType = reinterpret_cast<PyTypeObject *>(" << typePtr << ");\n";
+ s << INDENT << "InitSignatureStrings(pyType, " << initFunctionName << "_SignatureStrings);\n";
+
+ if (usePySideExtensions())
s << INDENT << "SbkObjectType_SetPropertyStrings(reinterpret_cast<PyTypeObject *>(" << typePtr << "), "
- << chopType(pyTypeName) << "_properties);\n";
- }
+ << chopType(pyTypeName) << "_PropertyStrings);\n";
if (!classContext.forSmartPointer())
s << INDENT << cpythonTypeNameExt(classTypeEntry) << Qt::endl;
@@ -5746,8 +5837,7 @@ bool CppGenerator::finishGeneration()
// Global enums
AbstractMetaEnumList globalEnums = this->globalEnums();
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList) {
+ for (const AbstractMetaClass *metaClass : classes()) {
const AbstractMetaClass *encClass = metaClass->enclosingClass();
if (!encClass || !NamespaceTypeEntry::isVisibleScope(encClass->typeEntry()))
lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 1cc6c1ca0..8c56dd758 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -290,9 +290,20 @@ private:
void writeGetterFunction(QTextStream &s,
const AbstractMetaField *metaField,
const GeneratorContext &context);
+ void writeGetterFunction(QTextStream &s,
+ const QPropertySpec *property,
+ const GeneratorContext &context);
+ void writeSetterFunctionPreamble(QTextStream &s,
+ const QString &name,
+ const QString &funcName,
+ const AbstractMetaType *type,
+ const GeneratorContext &context);
void writeSetterFunction(QTextStream &s,
const AbstractMetaField *metaField,
const GeneratorContext &context);
+ void writeSetterFunction(QTextStream &s,
+ const QPropertySpec *property,
+ const GeneratorContext &context);
void writeRichCompareFunction(QTextStream &s, const GeneratorContext &context);
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 418d3f529..825965b92 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -31,6 +31,7 @@
#include <abstractmetalang.h>
#include <messages.h>
#include "overloaddata.h"
+#include "propertyspec.h"
#include <reporthandler.h>
#include <typedatabase.h>
#include <abstractmetabuilder.h>
@@ -452,14 +453,38 @@ QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass *
return cpythonBaseName(metaClass) + QLatin1String("_getattro");
}
+QString ShibokenGenerator::cpythonGetterFunctionName(const QString &name,
+ const AbstractMetaClass *enclosingClass)
+{
+ return cpythonBaseName(enclosingClass) + QStringLiteral("_get_") + name;
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const QString &name,
+ const AbstractMetaClass *enclosingClass)
+{
+ return cpythonBaseName(enclosingClass) + QStringLiteral("_set_") + name;
+}
+
QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField *metaField)
{
- return QStringLiteral("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
+ return cpythonGetterFunctionName(metaField->name(), metaField->enclosingClass());
}
QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField *metaField)
{
- return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
+ return cpythonSetterFunctionName(metaField->name(), metaField->enclosingClass());
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const QPropertySpec *property,
+ const AbstractMetaClass *metaClass)
+{
+ return cpythonGetterFunctionName(property->name(), metaClass);
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec *property,
+ const AbstractMetaClass *metaClass)
+{
+ return cpythonSetterFunctionName(property->name(), metaClass);
}
static QString cpythonEnumFlagsName(const QString &moduleName,
@@ -1590,8 +1615,7 @@ AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaCl
ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
{
ExtendedConverterData extConvs;
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList) {
+ for (const AbstractMetaClass *metaClass : classes()) {
// Use only the classes for the current module.
if (!shouldGenerate(metaClass))
continue;
@@ -2622,8 +2646,7 @@ bool ShibokenGenerator::doSetup()
const ContainerTypeEntryList &containerTypeList = containerTypes();
for (const ContainerTypeEntry *type : containerTypeList)
getCode(snips, type);
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList)
+ for (const AbstractMetaClass *metaClass : classes())
getCode(snips, metaClass->typeEntry());
const TypeSystemTypeEntry *moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index da0c16851..83e7cf5b9 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -53,6 +53,7 @@ extern const char *END_ALLOW_THREADS;
class DocParser;
class CodeSnip;
+class QPropertySpec;
class OverloadData;
struct GeneratorClassInfoCacheEntry;
@@ -308,9 +309,9 @@ protected:
static QString cpythonBaseName(const AbstractMetaClass *metaClass);
static QString cpythonBaseName(const TypeEntry *type);
- QString cpythonBaseName(const AbstractMetaType *type);
- QString cpythonTypeName(const AbstractMetaClass *metaClass);
- QString cpythonTypeName(const TypeEntry *type);
+ static QString cpythonBaseName(const AbstractMetaType *type);
+ static QString cpythonTypeName(const AbstractMetaClass *metaClass);
+ static QString cpythonTypeName(const TypeEntry *type);
QString cpythonTypeNameExt(const TypeEntry *type) const;
QString cpythonTypeNameExt(const AbstractMetaType *type) const;
QString cpythonCheckFunction(const TypeEntry *type, bool genericNumberType = false);
@@ -341,8 +342,12 @@ protected:
QString cpythonGettersSettersDefinitionName(const AbstractMetaClass *metaClass);
static QString cpythonGetattroFunctionName(const AbstractMetaClass *metaClass);
static QString cpythonSetattroFunctionName(const AbstractMetaClass *metaClass);
- QString cpythonGetterFunctionName(const AbstractMetaField *metaField);
- QString cpythonSetterFunctionName(const AbstractMetaField *metaField);
+ static QString cpythonGetterFunctionName(const AbstractMetaField *metaField);
+ static QString cpythonSetterFunctionName(const AbstractMetaField *metaField);
+ static QString cpythonGetterFunctionName(const QPropertySpec *property,
+ const AbstractMetaClass *metaClass);
+ static QString cpythonSetterFunctionName(const QPropertySpec *property,
+ const AbstractMetaClass *metaClass);
QString cpythonWrapperCPtr(const AbstractMetaClass *metaClass,
const QString &argName = QLatin1String("self")) const;
QString cpythonWrapperCPtr(const AbstractMetaType *metaType, const QString &argName) const;
@@ -461,6 +466,11 @@ protected:
static QStringList m_knownPythonTypes;
private:
+ static QString cpythonGetterFunctionName(const QString &name,
+ const AbstractMetaClass *enclosingClass);
+ static QString cpythonSetterFunctionName(const QString &name,
+ const AbstractMetaClass *enclosingClass);
+
static const GeneratorClassInfoCacheEntry &getGeneratorClassInfo(const AbstractMetaClass *scope);
static FunctionGroups getFunctionGroupsImpl(const AbstractMetaClass *scope);
static bool classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass);
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt
index 11765e637..a95a6358c 100644
--- a/sources/shiboken2/libshiboken/CMakeLists.txt
+++ b/sources/shiboken2/libshiboken/CMakeLists.txt
@@ -57,13 +57,18 @@ sbkstaticstrings.cpp
bindingmanager.cpp
threadstatesaver.cpp
shibokenbuffer.cpp
-signature.cpp
qapp_macro.cpp
pep384impl.cpp
voidptr.cpp
bufferprocs_py37.cpp
+
embed/signature_bootstrap_inc.h
embed/signature_inc.h
+
+signature/signature.cpp
+signature/signature_globals.cpp
+signature/signature_extend.cpp
+signature/signature_helper.cpp
)
get_numpy_location()
@@ -136,11 +141,14 @@ install(FILES
shibokenbuffer.h
sbkpython.h
pep384impl.h
- signature.h
qapp_macro.h
voidptr.h
bufferprocs_py37.h
"${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
+
+ signature.h
+ signature/signature_p.h
+
DESTINATION include/shiboken2${shiboken2_SUFFIX})
install(TARGETS libshiboken EXPORT Shiboken2Targets
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 9017d8f91..9dfd87208 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -1088,7 +1088,6 @@ introduceWrapperType(PyObject *enclosingObject,
const char *typeName,
const char *originalName,
PyType_Spec *typeSpec,
- const char *signatureStrings[],
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
@@ -1113,12 +1112,8 @@ introduceWrapperType(PyObject *enclosingObject,
BindingManager::instance().addClassInheritance(baseType, type);
}
}
- // PYSIDE-510: Here is the single change to support signatures.
- if (SbkSpecial_Type_Ready(enclosingObject, reinterpret_cast<PyTypeObject *>(type), signatureStrings) < 0) {
- std::cerr << "Warning: " << __FUNCTION__ << " returns nullptr for "
- << typeName << '/' << originalName << " due to SbkSpecial_Type_Ready() failing\n";
+ if (PyType_Ready(reinterpret_cast<PyTypeObject *>(type)) < 0)
return nullptr;
- }
initPrivateData(type);
auto sotp = PepType_SOTP(type);
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 1190f3187..31083522b 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -234,7 +234,6 @@ LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject,
const char *typeName,
const char *originalName,
PyType_Spec *typeSpec,
- const char *signatureStrings[],
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
deleted file mode 100644
index 242fe18c1..000000000
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ /dev/null
@@ -1,1264 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "basewrapper.h"
-#include "autodecref.h"
-#include "sbkstring.h"
-#include "sbkstaticstrings.h"
-#include "sbkstaticstrings_p.h"
-
-using namespace Shiboken;
-
-extern "C"
-{
-
-/*
- * The documentation is located in file signature_doc.rst
- */
-#include "signature.h"
-#include <structmember.h>
-
-// These constants were needed in former versions of the module:
-#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03030000)
-#define PYTHON_HAS_WEAKREF_PYCFUNCTION (PY_VERSION_HEX >= 0x030500A0)
-#define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000)
-#define PYTHON_HAS_KEYWORDONLY (PYTHON_IS_PYTHON3)
-#define PYTHON_USES_PERCENT_V_FORMAT (PYTHON_IS_PYTHON3)
-#define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000)
-#define PYTHON_HAS_DESCR_REDUCE (PY_VERSION_HEX >= 0x03040000)
-#define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE)
-#define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3)
-#define PYTHON_EXPOSES_METHODDESCR (PYTHON_IS_PYTHON3)
-#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3 || Py_LIMITED_API)
-#define PYTHON_HAS_INT_AND_LONG (!PYTHON_IS_PYTHON3)
-
-// These constants are still in use:
-#define PYTHON_USES_UNICODE (PY_VERSION_HEX >= 0x03000000)
-
-typedef struct safe_globals_struc {
- // init part 1: get arg_dict
- PyObject *helper_module;
- PyObject *arg_dict;
- PyObject *map_dict;
- PyObject *value_dict; // for writing signatures
- PyObject *feature_dict; // registry for PySide.support.__feature__
- // init part 2: run module
- PyObject *pyside_type_init_func;
- PyObject *create_signature_func;
- PyObject *seterror_argument_func;
- PyObject *make_helptext_func;
- PyObject *finish_import_func;
-} safe_globals_struc, *safe_globals;
-
-static safe_globals pyside_globals = nullptr;
-
-static PyObject *GetTypeKey(PyObject *ob);
-
-static PyObject *GetSignature_Function(PyObject *, PyObject *);
-static PyObject *GetSignature_TypeMod(PyObject *, PyObject *);
-static PyObject *GetSignature_Wrapper(PyObject *, PyObject *);
-static PyObject *get_signature(PyObject *self, PyObject *args);
-static PyObject *get_signature_intern(PyObject *ob, PyObject *modifier);
-
-static PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
-
-static void init_module_1(void);
-static void init_module_2(void);
-static PyObject *_init_pyside_extension(PyObject * /* self */, PyObject * /* args */);
-
-static PyObject *CreateSignature(PyObject *props, PyObject *key)
-{
- /*
- * Here is the new function to create all signatures. It simply calls
- * into Python and creates a signature object directly.
- * This is so much simpler than using all the attributes explicitly
- * to support '_signature_is_functionlike()'.
- */
- return PyObject_CallFunction(pyside_globals->create_signature_func,
- const_cast<char *>("(OO)"), props, key);
-}
-
-typedef PyObject *(*signaturefunc)(PyObject *, PyObject *);
-
-static PyObject *_get_written_signature(signaturefunc sf, PyObject *ob, PyObject *modifier)
-{
- /*
- * Be a writable Attribute, but have a computed value.
- *
- * If a signature has not been written, call the signature function.
- * If it has been written, return the written value.
- * After __del__ was called, the function value re-appears.
- *
- * Note: This serves also for the new version that does not allow any
- * assignment if we have a computed value. We only need to check if
- * a computed value exists and then forbid writing.
- * See pyside_set___signature
- */
- PyObject *ret = PyDict_GetItem(pyside_globals->value_dict, ob);
- if (ret == nullptr)
- return ob == nullptr ? nullptr : sf(ob, modifier);
- Py_INCREF(ret);
- return ret;
-}
-
-static PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier)
-{
- init_module_2();
- return _get_written_signature(GetSignature_Function, func, modifier);
-}
-
-static PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier)
-{
- init_module_2();
- AutoDecRef func(PyObject_GetAttr(sm, PyMagicName::func()));
- if (Py_TYPE(func) == PepFunction_TypePtr)
- return PyObject_GetAttr(func, PyMagicName::signature());
- return _get_written_signature(GetSignature_Function, func, modifier);
-}
-
-static PyObject *_get_class_of_cf(PyObject *ob_cf)
-{
- PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
- if (selftype == nullptr) {
- selftype = PyDict_GetItem(pyside_globals->map_dict, ob_cf);
- if (selftype == nullptr) {
- // This must be an overloaded function that we handled special.
- AutoDecRef special(Py_BuildValue("(OO)", ob_cf, PyName::overload()));
- selftype = PyDict_GetItem(pyside_globals->map_dict, special);
- if (selftype == nullptr) {
- // This is probably a module function. We will return type(None).
- selftype = Py_None;
- }
- }
- }
-
- PyObject *obtype_mod = (PyType_Check(selftype) || PyModule_Check(selftype))
- ? selftype
- : reinterpret_cast<PyObject *>(Py_TYPE(selftype));
- Py_INCREF(obtype_mod);
- return obtype_mod;
-}
-
-static PyObject *_get_class_of_sm(PyObject *ob_sm)
-{
- AutoDecRef func(PyObject_GetAttr(ob_sm, PyMagicName::func()));
- return _get_class_of_cf(func);
-}
-
-static PyObject *_get_class_of_descr(PyObject *ob)
-{
- return PyObject_GetAttr(ob, PyMagicName::objclass());
-}
-
-static PyObject *GetClassOrModOf(PyObject *ob)
-{
- /*
- * Return the type or module of a function or type.
- * The purpose is finally to use the name of the object.
- */
- if (PyType_Check(ob)) {
- // PySide-928: The type case must do refcounting like the others as well.
- Py_INCREF(ob);
- return ob;
- }
- if (PyType_IsSubtype(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 GetClassOrModOf");
- return nullptr;
-}
-
-static PyObject *get_funcname(PyObject *ob)
-{
- PyObject *func = ob;
- if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
- func = PyObject_GetAttr(ob, PyMagicName::func());
- else
- Py_INCREF(func);
- PyObject *func_name = PyObject_GetAttr(func, PyMagicName::name());
- Py_DECREF(func);
- if (func_name == nullptr)
- Py_FatalError("unexpected name problem in compute_name_key");
- return func_name;
-}
-
-static PyObject *compute_name_key(PyObject *ob)
-{
- if (PyType_Check(ob))
- return GetTypeKey(ob);
- AutoDecRef func_name(get_funcname(ob));
- AutoDecRef type_key(GetTypeKey(GetClassOrModOf(ob)));
- return Py_BuildValue("(OO)", type_key.object(), func_name.object());
-}
-
-static int build_name_key_to_func(PyObject *obtype)
-{
- auto *type = reinterpret_cast<PyTypeObject *>(obtype);
- PyMethodDef *meth = type->tp_methods;
-
- if (meth == nullptr)
- return 0;
-
- AutoDecRef type_key(GetTypeKey(obtype));
- for (; meth->ml_name != nullptr; meth++) {
- AutoDecRef func(PyCFunction_NewEx(meth, obtype, nullptr));
- AutoDecRef func_name(get_funcname(func));
- AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
- if (func.isNull() || name_key.isNull()
- || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
- return -1;
- }
- return 0;
-}
-
-static PyObject *name_key_to_func(PyObject *ob)
-{
- /*
- * 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.
- */
- 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 == nullptr) {
- // do a lazy initialization
- AutoDecRef type_key(GetTypeKey(GetClassOrModOf(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 nullptr;
- ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
- }
- Py_XINCREF(ret);
- return ret;
-}
-
-static PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier)
-{
- init_module_2();
- AutoDecRef func(name_key_to_func(ob_md));
- if (func.object() == Py_None)
- return Py_None;
- if (func.isNull())
- Py_FatalError("missing mapping in MethodDescriptor");
- return pyside_cf_get___signature__(func, modifier);
-}
-
-static PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier)
-{
- init_module_2();
- return _get_written_signature(GetSignature_Wrapper, ob, modifier);
-}
-
-static PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier)
-{
- init_module_2();
- return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier);
-}
-
-// forward
-static PyObject *GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier);
-
-// Helper for __qualname__ which might not always exist in Python 2 (type).
-static PyObject *_get_qualname(PyObject *ob)
-{
- // We support __qualname__ for types, only.
- assert(PyType_Check(ob));
- PyObject *name = PyObject_GetAttr(ob, PyMagicName::qualname());
- if (name == nullptr) {
- PyErr_Clear();
- name = PyObject_GetAttr(ob, PyMagicName::name());
- }
- return name;
-}
-
-static PyObject *GetTypeKey(PyObject *ob)
-{
- assert(PyType_Check(ob) || PyModule_Check(ob));
- /*
- * We obtain a unique key using the module name and the type name.
- *
- * The type 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.
- */
- // PYSIDE-1286: We use correct __module__ and __qualname__, now.
- AutoDecRef module_name(PyObject_GetAttr(ob, PyMagicName::module()));
- if (module_name.isNull()) {
- // We have no module_name because this is a module ;-)
- PyErr_Clear();
- module_name.reset(PyObject_GetAttr(ob, PyMagicName::name()));
- return Py_BuildValue("O", module_name.object());
- }
- AutoDecRef class_name(_get_qualname(ob));
- if (class_name.isNull()) {
- Py_FatalError("Signature: missing class name in GetTypeKey");
- return nullptr;
- }
- return Py_BuildValue("(OO)", module_name.object(), class_name.object());
-}
-
-static PyObject *empty_dict = nullptr;
-
-static PyObject *TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype)
-{
- PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
- if (dict == nullptr) {
- if (empty_dict == nullptr)
- empty_dict = PyDict_New();
- dict = empty_dict;
- }
- if (!PyDict_Check(dict))
- dict = PySide_BuildSignatureProps(type_key);
- return dict;
-}
-
-static PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
-{
- // make sure that we look into PyCFunction, only...
- if (Py_TYPE(obfunc) == PepFunction_TypePtr)
- Py_RETURN_NONE;
- 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, obtype_mod);
- 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;
-
- int flags = PyCFunction_GET_FLAGS(obfunc);
- PyObject *func_kind;
- if (PyModule_Check(obtype_mod))
- func_kind = PyName::function();
- else if (flags & METH_CLASS)
- func_kind = PyName::classmethod();
- else if (flags & METH_STATIC)
- func_kind = PyName::staticmethod();
- else
- func_kind = PyName::method();
- return GetSignature_Cached(props, func_kind, modifier);
-}
-
-static PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
-{
- AutoDecRef func_name(PyObject_GetAttr(ob, PyMagicName::name()));
- AutoDecRef objclass(PyObject_GetAttr(ob, PyMagicName::objclass()));
- AutoDecRef class_key(GetTypeKey(objclass));
- if (func_name.isNull() || objclass.isNull() || class_key.isNull())
- return nullptr;
- PyObject *dict = TypeKey_to_PropsDict(class_key, objclass);
- if (dict == nullptr)
- return nullptr;
- PyObject *props = PyDict_GetItem(dict, func_name);
- if (props == nullptr)
- Py_RETURN_NONE;
- return GetSignature_Cached(props, PyName::method(), modifier);
-}
-
-static 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);
- if (dict == nullptr)
- return nullptr;
- PyObject *props = PyDict_GetItem(dict, ob_name);
- if (props == nullptr)
- Py_RETURN_NONE;
- return GetSignature_Cached(props, PyName::method(), modifier);
-}
-
-static PyObject *GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier)
-{
- // Special case: We want to know the func_kind.
- if (modifier) {
-#if PYTHON_USES_UNICODE
- PyUnicode_InternInPlace(&modifier);
-#else
- PyString_InternInPlace(&modifier);
-#endif
- if (modifier == PyMagicName::func_kind())
- return Py_BuildValue("O", func_kind);
- }
-
- AutoDecRef key(modifier == nullptr ? Py_BuildValue("O", func_kind)
- : Py_BuildValue("(OO)", func_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)
- // this is an error
- return nullptr;
- }
- else {
- // key not found
- Py_RETURN_NONE;
- }
- }
- return Py_INCREF(value), value;
-}
-
-static const char *PySide_CompressedSignaturePackage[] = {
-#include "embed/signature_inc.h"
- };
-
-static const unsigned char PySide_SignatureLoader[] = {
-#include "embed/signature_bootstrap_inc.h"
- };
-
-// This function will be inserted into __builtins__.
-static PyMethodDef init_methods[] = {
- {"_init_pyside_extension", (PyCFunction)_init_pyside_extension, METH_NOARGS},
- {nullptr, nullptr}
-};
-
-static safe_globals_struc *init_phase_1(PyMethodDef *init_meth)
-{
- {
- auto *p = reinterpret_cast<safe_globals_struc *>
- (malloc(sizeof(safe_globals_struc)));
- if (p == nullptr)
- goto error;
- /*
- * Initializing module signature_bootstrap.
- * Since we now have an embedding script, we can do this without any
- * Python strings in the C code.
- */
-#ifdef Py_LIMITED_API
- // We must work for multiple versions, so use source code.
-#else
- AutoDecRef marshal_module(PyImport_Import(PyName::marshal()));
- if (marshal_module.isNull())
- goto error;
- AutoDecRef loads(PyObject_GetAttr(marshal_module, PyName::loads()));
- if (loads.isNull())
- goto error;
-#endif
- char *bytes_cast = reinterpret_cast<char *>(
- const_cast<unsigned char *>(PySide_SignatureLoader));
- AutoDecRef bytes(PyBytes_FromStringAndSize(bytes_cast, sizeof(PySide_SignatureLoader)));
- if (bytes.isNull())
- goto error;
-#ifdef Py_LIMITED_API
- PyObject *builtins = PyEval_GetBuiltins();
- PyObject *compile = PyDict_GetItem(builtins, PyName::compile());
- if (compile == nullptr)
- goto error;
- AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss",
- bytes.object(), "(builtin)", "exec"));
-#else
- AutoDecRef code_obj(PyObject_CallFunctionObjArgs(
- loads, bytes.object(), nullptr));
-#endif
- if (code_obj.isNull())
- goto error;
- p->helper_module = PyImport_ExecCodeModule(const_cast<char *>
- ("signature_bootstrap"), code_obj);
- if (p->helper_module == nullptr)
- goto error;
- // Initialize the module
- PyObject *mdict = PyModule_GetDict(p->helper_module);
- if (PyDict_SetItem(mdict, PyMagicName::builtins(), PyEval_GetBuiltins()) < 0)
- goto error;
- /*
- * Unpack an embedded ZIP file with more signature modules.
- * They will be loaded later with the zipimporter.
- * Due to MSVC's limitation to 64k strings, we need to assemble pieces.
- */
- const char **block_ptr = (const char **)PySide_CompressedSignaturePackage;
- int npieces = 0;
- PyObject *piece, *zipped_string_sequence = PyList_New(0);
- if (zipped_string_sequence == nullptr)
- return nullptr;
- for (; **block_ptr != 0; ++block_ptr) {
- npieces++;
- // we avoid the string/unicode dilemma by not using PyString_XXX:
- piece = Py_BuildValue("s", *block_ptr);
- if (piece == nullptr || PyList_Append(zipped_string_sequence, piece) < 0)
- goto error;
- }
- if (PyDict_SetItemString(mdict, "zipstring_sequence", zipped_string_sequence) < 0)
- goto error;
- Py_DECREF(zipped_string_sequence);
-
- // build a dict for diverse mappings
- p->map_dict = PyDict_New();
- if (p->map_dict == nullptr)
- goto error;
-
- // build a dict for the prepared arguments
- p->arg_dict = PyDict_New();
- if (p->arg_dict == nullptr
- || PyObject_SetAttrString(p->helper_module, "pyside_arg_dict", p->arg_dict) < 0)
- goto error;
-
- // build a dict for assigned signature values
- p->value_dict = PyDict_New();
- if (p->value_dict == nullptr)
- goto error;
-
- // PYSIDE-1019: build a __feature__ dict
- p->feature_dict = PyDict_New();
- if (p->feature_dict == nullptr
- || PyObject_SetAttrString(p->helper_module, "pyside_feature_dict", p->feature_dict) < 0)
- goto error;
-
- // This function will be disabled until phase 2 is done.
- p->finish_import_func = nullptr;
-
- // Initialize the explicit init function.
- AutoDecRef init(PyCFunction_NewEx(init_meth, nullptr, nullptr));
- if (init.isNull()
- || PyDict_SetItemString(PyEval_GetBuiltins(), init_meth->ml_name, init) != 0)
- goto error;
-
- return p;
- }
-error:
- PyErr_Print();
- Py_FatalError("could not initialize part 1");
- return nullptr;
-}
-
-static int init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
-{
- {
- PyMethodDef *ml;
-
- // The single function to be called, but maybe more to come.
- for (ml = methods; ml->ml_name != nullptr; ml++) {
- PyObject *v = PyCFunction_NewEx(ml, nullptr, nullptr);
- if (v == nullptr
- || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0)
- goto error;
- Py_DECREF(v);
- }
- PyObject *bootstrap_func = PyObject_GetAttrString(p->helper_module, "bootstrap");
- if (bootstrap_func == nullptr)
- goto error;
- // The return value of the bootstrap function is the loader module.
- PyObject *loader = PyObject_CallFunction(bootstrap_func, const_cast<char *>("()"));
- if (loader == nullptr)
- goto error;
- // now the loader should be initialized
- p->pyside_type_init_func = PyObject_GetAttrString(loader, "pyside_type_init");
- if (p->pyside_type_init_func == nullptr)
- goto error;
- p->create_signature_func = PyObject_GetAttrString(loader, "create_signature");
- if (p->create_signature_func == nullptr)
- goto error;
- p->seterror_argument_func = PyObject_GetAttrString(loader, "seterror_argument");
- if (p->seterror_argument_func == nullptr)
- goto error;
- p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext");
- if (p->make_helptext_func == nullptr)
- goto error;
- p->finish_import_func = PyObject_GetAttrString(loader, "finish_import");
- if (p->finish_import_func == nullptr)
- goto error;
- return 0;
- }
-error:
- PyErr_Print();
- Py_FatalError("could not initialize part 2");
- return -1;
-}
-
-static int _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp)
-{
- /*
- * This function pre-fills all fields of the new gsp. We then
- * insert the changed values.
- */
- PyGetSetDef *gsp = type->tp_getset;
- if (gsp != nullptr) {
- for (; gsp->name != nullptr; gsp++) {
- if (strcmp(gsp->name, name) == 0) {
- new_gsp->set = gsp->set;
- new_gsp->doc = gsp->doc;
- new_gsp->closure = gsp->closure;
- return 1; // success
- }
- }
- }
- PyMemberDef *md = type->tp_members;
- if (md != nullptr)
- for (; md->name != nullptr; md++)
- if (strcmp(md->name, name) == 0)
- return 1;
- // staticmethod has just a `__doc__` in the class
- assert(strcmp(type->tp_name, "staticmethod") == 0 && strcmp(name, "__doc__") == 0);
- return 0;
-}
-
-static int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr)
-{
- /*
- * This function is used to assign a new `__signature__` attribute,
- * and also to override a `__doc__` or `__name__` attribute.
- */
- assert(PyType_Check(type));
- PyType_Ready(type);
- PyObject *dict = type->tp_dict;
- for (; gsp->name != nullptr; gsp++) {
- PyObject *have_descr = PyDict_GetItemString(dict, gsp->name);
- if (have_descr != nullptr) {
- Py_INCREF(have_descr);
- if (strcmp(gsp->name, "__doc__") == 0)
- *doc_descr = have_descr;
- else
- assert(false);
- if (!_fixup_getset(type, gsp->name, gsp))
- continue;
- }
- AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
- if (descr.isNull())
- return -1;
- if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
- return -1;
- }
- PyType_Modified(type);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// Augmenting builtin types with a __signature__ attribute.
-//
-// This is a harmless change to Python, similar like __text_signature__.
-// We could avoid it, but then we would need to copy quite some module
-// initialization functions which are pretty version- and word size
-// dependent. I think this little patch is the lesser of the two evils.
-//
-// Please note that in fact we are modifying 'type', the metaclass of all
-// objects, because we add new functionality.
-//
-// Addendum 2019-01-12: We now also compute a docstring from the signature.
-//
-
-// keep the original __doc__ functions
-static PyObject *old_cf_doc_descr = nullptr;
-static PyObject *old_sm_doc_descr = nullptr;
-static PyObject *old_md_doc_descr = nullptr;
-static PyObject *old_tp_doc_descr = nullptr;
-static PyObject *old_wd_doc_descr = nullptr;
-
-static int handle_doc_in_progress = 0;
-
-static PyObject *handle_doc(PyObject *ob, PyObject *old_descr)
-{
- init_module_1();
- init_module_2();
- AutoDecRef ob_type_mod(GetClassOrModOf(ob));
- const char *name;
- if (PyModule_Check(ob_type_mod))
- name = PyModule_GetName(ob_type_mod);
- else
- name = reinterpret_cast<PyTypeObject *>(ob_type_mod.object())->tp_name;
- if (handle_doc_in_progress || name == nullptr
- || strncmp(name, "PySide2.", 8) != 0)
- return PyObject_CallMethodObjArgs(old_descr,
- PyMagicName::get(),
- ob, nullptr);
- handle_doc_in_progress++;
- PyObject *res = PyObject_CallFunction(
- pyside_globals->make_helptext_func,
- const_cast<char *>("(O)"), ob);
- handle_doc_in_progress--;
- if (res == nullptr) {
- PyErr_Print();
- Py_FatalError("handle_doc did not receive a result");
- }
- return res;
-}
-
-static PyObject *pyside_cf_get___doc__(PyObject *cf) {
- return handle_doc(cf, old_cf_doc_descr);
-}
-
-static PyObject *pyside_sm_get___doc__(PyObject *sm) {
- return handle_doc(sm, old_sm_doc_descr);
-}
-
-static PyObject *pyside_md_get___doc__(PyObject *md) {
- return handle_doc(md, old_md_doc_descr);
-}
-
-static PyObject *pyside_tp_get___doc__(PyObject *tp) {
- return handle_doc(tp, old_tp_doc_descr);
-}
-
-static PyObject *pyside_wd_get___doc__(PyObject *wd) {
- return handle_doc(wd, old_wd_doc_descr);
-}
-
-// the default setter for all objects
-static int pyside_set___signature__(PyObject *op, PyObject *value)
-{
- // By this additional check, this function refuses write access.
- // We consider both nullptr and Py_None as not been written.
- AutoDecRef has_val(get_signature_intern(op, nullptr));
- if (!(has_val.isNull() || has_val == Py_None)) {
- PyErr_Format(PyExc_AttributeError,
- "Attribute '__signature__' of '%.50s' object is not writable",
- Py_TYPE(op)->tp_name);
- return -1;
- }
- int ret = value == nullptr ? PyDict_DelItem(pyside_globals->value_dict, op)
- : PyDict_SetItem(pyside_globals->value_dict, op, value);
- Py_XINCREF(value);
- return ret;
-}
-
-static PyGetSetDef new_PyCFunction_getsets[] = {
- {const_cast<char *>("__doc__"), (getter)pyside_cf_get___doc__},
- {const_cast<char *>("__signature__"), (getter)pyside_cf_get___signature__,
- (setter)pyside_set___signature__},
- {nullptr}
-};
-
-static PyGetSetDef new_PyStaticMethod_getsets[] = {
- {const_cast<char *>("__doc__"), (getter)pyside_sm_get___doc__},
- {const_cast<char *>("__signature__"), (getter)pyside_sm_get___signature__,
- (setter)pyside_set___signature__},
- {nullptr}
-};
-
-static PyGetSetDef new_PyMethodDescr_getsets[] = {
- {const_cast<char *>("__doc__"), (getter)pyside_md_get___doc__},
- {const_cast<char *>("__signature__"), (getter)pyside_md_get___signature__,
- (setter)pyside_set___signature__},
- {nullptr}
-};
-
-static PyGetSetDef new_PyType_getsets[] = {
- {const_cast<char *>("__doc__"), (getter)pyside_tp_get___doc__},
- {const_cast<char *>("__signature__"), (getter)pyside_tp_get___signature__,
- (setter)pyside_set___signature__},
- {nullptr}
-};
-
-static PyGetSetDef new_PyWrapperDescr_getsets[] = {
- {const_cast<char *>("__doc__"), (getter)pyside_wd_get___doc__},
- {const_cast<char *>("__signature__"), (getter)pyside_wd_get___signature__,
- (setter)pyside_set___signature__},
- {nullptr}
-};
-
-////////////////////////////////////////////////////////////////////////////
-//
-// get_signature -- providing a superior interface
-//
-// Additionally to the interface via __signature__, we also provide
-// a general function, which allows for different signature layouts.
-// The "modifier" argument is a string that is passed in from 'loader.py'.
-// Configuration what the modifiers mean is completely in Python.
-//
-
-static PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
-{
- if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
- return pyside_cf_get___signature__(ob, modifier);
- if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
- return pyside_sm_get___signature__(ob, modifier);
- if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
- return pyside_md_get___signature__(ob, modifier);
- if (PyType_Check(ob))
- return pyside_tp_get___signature__(ob, modifier);
- if (Py_TYPE(ob) == &PyWrapperDescr_Type)
- return pyside_wd_get___signature__(ob, modifier);
- return nullptr;
-}
-
-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)
- Py_RETURN_NONE;
- PyObject *ret = get_signature_intern(ob, modifier);
- if (ret != nullptr)
- return ret;
- Py_RETURN_NONE;
-}
-
-static PyObject *_init_pyside_extension(PyObject * /* self */, PyObject * /* args */)
-{
- init_module_1();
- init_module_2();
- Py_RETURN_NONE;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// This special Type_Ready does certain initializations earlier with
-// our new version.
-//
-
-#ifndef _WIN32
-////////////////////////////////////////////////////////////////////////////
-// a stack trace for linux-like platforms
-#include <stdio.h>
-#if defined(__GLIBC__)
-# include <execinfo.h>
-#endif
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-void handler(int sig) {
-#if defined(__GLIBC__)
- void *array[30];
- size_t size;
-
- // get void *'s for all entries on the stack
- size = backtrace(array, 30);
-
- // print out all the frames to stderr
-#endif
- fprintf(stderr, "Error: signal %d:\n", sig);
-#if defined(__GLIBC__)
- backtrace_symbols_fd(array, size, STDERR_FILENO);
-#endif
- exit(1);
-}
-
-////////////////////////////////////////////////////////////////////////////
-#endif // _WIN32
-
-static int PySide_PatchTypes(void)
-{
- static int init_done = 0;
-
- if (!init_done) {
- AutoDecRef meth_descr(PyObject_GetAttrString(
- reinterpret_cast<PyObject *>(&PyString_Type), "split"));
- AutoDecRef wrap_descr(PyObject_GetAttrString(
- reinterpret_cast<PyObject *>(Py_TYPE(Py_True)), "__add__"));
- // abbreviations for readability
- auto md_gs = new_PyMethodDescr_getsets;
- auto md_doc = &old_md_doc_descr;
- auto cf_gs = new_PyCFunction_getsets;
- auto cf_doc = &old_cf_doc_descr;
- auto sm_gs = new_PyStaticMethod_getsets;
- auto sm_doc = &old_sm_doc_descr;
- auto tp_gs = new_PyType_getsets;
- auto tp_doc = &old_tp_doc_descr;
- auto wd_gs = new_PyWrapperDescr_getsets;
- auto wd_doc = &old_wd_doc_descr;
-
- if (meth_descr.isNull() || wrap_descr.isNull()
- || PyType_Ready(Py_TYPE(meth_descr)) < 0
- || add_more_getsets(PepMethodDescr_TypePtr, md_gs, md_doc) < 0
- || add_more_getsets(&PyCFunction_Type, cf_gs, cf_doc) < 0
- || add_more_getsets(PepStaticMethod_TypePtr, sm_gs, sm_doc) < 0
- || add_more_getsets(&PyType_Type, tp_gs, tp_doc) < 0
- || add_more_getsets(Py_TYPE(wrap_descr), wd_gs, wd_doc) < 0
- )
- return -1;
-#ifndef _WIN32
- // We enable the stack trace in CI, only.
- const char *testEnv = getenv("QTEST_ENVIRONMENT");
- if (testEnv && strstr(testEnv, "ci"))
- signal(SIGSEGV, handler); // install our handler
-#endif // _WIN32
- init_done = 1;
- }
- return 0;
-}
-
-static void init_module_1(void)
-{
- static int init_done = 0;
-
- if (!init_done) {
- pyside_globals = init_phase_1(init_methods);
- if (pyside_globals != nullptr)
- init_done = 1;
- }
-}
-
-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
- * 2**15 unicode characters (64 K memory).
- * Instead of one huge string, we take a ssize_t that is the
- * address of a string array. It will not be turned into a real
- * string list until really used by Python. This is quite optimal.
- */
- AutoDecRef numkey(Py_BuildValue("n", signatures));
- if (type_key.isNull() || numkey.isNull()
- || PyDict_SetItem(pyside_globals->arg_dict, type_key, numkey) < 0)
- return -1;
- /*
- * We record also a mapping from type key to type/module. This helps to
- * lazily initialize the Py_LIMITED_API in name_key_to_func().
- */
- return PyDict_SetItem(pyside_globals->map_dict, type_key, obtype_mod) == 0 ? 0 : -1;
-}
-
-static PyMethodDef signature_methods[] = {
- {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
- "get the __signature__, but pass an optional string parameter"},
- {nullptr, nullptr}
-};
-
-static void init_module_2(void)
-{
- static int init_done = 0;
-
- if (!init_done) {
- // Phase 2 will call __init__.py which touches a signature, itself.
- // Therefore we set init_done prior to init_phase_2().
- init_done = 1;
- init_phase_2(pyside_globals, signature_methods);
- }
-}
-
-static PyObject *_address_to_stringlist(PyObject *numkey)
-{
- ssize_t address = PyNumber_AsSsize_t(numkey, PyExc_ValueError);
- if (address == -1 && PyErr_Occurred())
- return nullptr;
- char **sig_strings = reinterpret_cast<char **>(address);
- PyObject *res_list = PyList_New(0);
- if (res_list == nullptr)
- return nullptr;
- for (; *sig_strings != nullptr; ++sig_strings) {
- char *sig_str = *sig_strings;
- AutoDecRef pystr(Py_BuildValue("s", sig_str));
- if (pystr.isNull() || PyList_Append(res_list, pystr) < 0)
- return nullptr;
- }
- return res_list;
-}
-
-static PyObject *PySide_BuildSignatureProps(PyObject *type_key)
-{
- /*
- * Here is the second part of the function.
- * This part will be called on-demand when needed by some attribute.
- * We simply pick up the arguments that we stored here and replace
- * them by the function result.
- */
- init_module_2();
- if (type_key == nullptr)
- return nullptr;
- PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key);
- AutoDecRef strings(_address_to_stringlist(numkey));
- if (strings.isNull())
- return nullptr;
- AutoDecRef arg_tup(Py_BuildValue("(OO)", type_key, strings.object()));
- if (arg_tup.isNull())
- return nullptr;
- PyObject *dict = PyObject_CallObject(pyside_globals->pyside_type_init_func, arg_tup);
- if (dict == nullptr) {
- if (PyErr_Occurred())
- return nullptr;
- // No error: return an empty dict.
- if (empty_dict == nullptr)
- empty_dict = PyDict_New();
- return empty_dict;
- }
- // We replace the arguments by the result dict.
- if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
- return nullptr;
- return dict;
-}
-
-static int _finish_nested_classes(PyObject *dict);
-static int _build_func_to_type(PyObject *obtype);
-
-static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
-{
- /*
- * Initialization of module functions and resolving of static methods.
- */
- const char *name = PyModule_GetName(module);
- if (name == nullptr)
- return -1;
-
- // we abuse the call for types, since they both have a __name__ attribute.
- if (PySide_BuildSignatureArgs(module, signatures) < 0)
- return -1;
-
- /*
- * Note: This function crashed when called from PySide_BuildSignatureArgs.
- * Probably this was too early.
- *
- * Pep384: We need to switch this always on since we have no access
- * to the PyCFunction attributes. Therefore I simplified things
- * and always use our own mapping.
- */
- PyObject *key, *func, *obdict = PyModule_GetDict(module);
- Py_ssize_t pos = 0;
-
- 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;
- // 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).
- if (pyside_globals->finish_import_func == nullptr) {
- assert(strncmp(name, "PySide2.", 8) != 0);
- return 0;
- }
- AutoDecRef ret(PyObject_CallFunction(
- pyside_globals->finish_import_func, const_cast<char *>("(O)"), module));
- return ret.isNull() ? -1 : 0;
-}
-
-static int _finish_nested_classes(PyObject *obdict)
-{
- PyObject *key, *value, *obtype;
- PyTypeObject *subtype;
- Py_ssize_t pos = 0;
-
- if (obdict == nullptr)
- 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 static method to this type in a dict.
- * We also check for hidden methods, see below.
- */
- auto *type = reinterpret_cast<PyTypeObject *>(obtype);
- PyObject *dict = type->tp_dict;
- PyMethodDef *meth = type->tp_methods;
-
- if (meth == nullptr)
- return 0;
-
- for (; meth->ml_name != nullptr; meth++) {
- /*
- * It is possible that a method is overwritten by another
- * attribute with the same name. This case was obviously provoked
- * explicitly in "testbinding.TestObject.staticMethodDouble",
- * where instead of the method a "PySide2.QtCore.Signal" object
- * was in the dict.
- * This overlap is also found in regular PySide under
- * "PySide2.QtCore.QProcess.error" where again a signal object is
- * returned. These hidden methods will be opened for the
- * signature module by adding them under the name
- * "{name}.overload".
- */
- PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
- PyObject *look_attr = meth->ml_flags & METH_STATIC ? PyMagicName::func()
- : PyMagicName::name();
- int check_name = meth->ml_flags & METH_STATIC ? 0 : 1;
- if (descr == nullptr)
- return -1;
-
- // We first check all methods if one is hidden by something else.
- AutoDecRef look(PyObject_GetAttr(descr, look_attr));
- AutoDecRef given(Py_BuildValue("s", meth->ml_name));
- if (look.isNull()
- || (check_name && PyObject_RichCompareBool(look, given, Py_EQ) != 1)) {
- PyErr_Clear();
- AutoDecRef cfunc(PyCFunction_NewEx(
- meth, reinterpret_cast<PyObject *>(type), nullptr));
- if (cfunc.isNull())
- return -1;
- if (meth->ml_flags & METH_STATIC)
- descr = PyStaticMethod_New(cfunc);
- else
- descr = PyDescr_NewMethod(type, meth);
- if (descr == nullptr)
- return -1;
- char mangled_name[200];
- strcpy(mangled_name, meth->ml_name);
- strcat(mangled_name, ".overload");
- if (PyDict_SetItemString(dict, mangled_name, descr) < 0)
- return -1;
- if (meth->ml_flags & METH_STATIC) {
- // This is the special case where a static method is hidden.
- AutoDecRef special(Py_BuildValue("(Os)", cfunc.object(), "overload"));
- if (PyDict_SetItem(pyside_globals->map_dict, special, obtype) < 0)
- return -1;
- }
- if (PyDict_SetItemString(pyside_globals->map_dict, mangled_name, obtype) < 0)
- return -1;
- continue;
- }
- // Then we insert the mapping for static methods.
- if (meth->ml_flags & METH_STATIC) {
- if (PyDict_SetItem(pyside_globals->map_dict, look, obtype) < 0)
- return -1;
- }
- }
- return 0;
-}
-
-int SbkSpecial_Type_Ready(PyObject * /* module */, PyTypeObject *type,
- const char *signatures[])
-{
- if (PyType_Ready(type) < 0)
- return -1;
- auto *ob_type = reinterpret_cast<PyObject *>(type);
- int ret = PySide_BuildSignatureArgs(ob_type, signatures);
- if (ret < 0) {
- PyErr_Print();
- PyErr_SetNone(PyExc_ImportError);
- }
- return ret;
-}
-
-void FinishSignatureInitialization(PyObject *module, const char *signatures[])
-{
- /*
- * This function is called at the very end of a module initialization.
- * We now patch certain types to support the __signature__ attribute,
- * initialize module functions and resolve static methods.
- *
- * 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
- || PySide_FinishSignatures(module, signatures) < 0) {
- PyErr_Print();
- PyErr_SetNone(PyExc_ImportError);
- }
-}
-
-void SetError_Argument(PyObject *args, const char *func_name)
-{
- /*
- * 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();
- AutoDecRef res(PyObject_CallFunction(pyside_globals->seterror_argument_func,
- const_cast<char *>("(Os)"), args, func_name));
- if (res.isNull()) {
- PyErr_Print();
- Py_FatalError("seterror_argument did not receive a result");
- }
- PyObject *err, *msg;
- if (!PyArg_UnpackTuple(res, func_name, 2, 2, &err, &msg)) {
- PyErr_Print();
- Py_FatalError("unexpected failure in seterror_argument");
- }
- PyErr_SetObject(err, msg);
-}
-
-/*
- * Support for the metatype SbkObjectType_Type's tp_getset.
- *
- * This was not necessary for __signature__, because PyType_Type inherited it.
- * But the __doc__ attribute existed already by inheritance, and calling
- * PyType_Modified() is not supported. So we added the getsets explicitly
- * to the metatype.
- */
-
-PyObject *Sbk_TypeGet___signature__(PyObject *ob, PyObject *modifier)
-{
- return pyside_tp_get___signature__(ob, modifier);
-}
-
-PyObject *Sbk_TypeGet___doc__(PyObject *ob)
-{
- return pyside_tp_get___doc__(ob);
-}
-
-PyObject *GetFeatureDict()
-{
- init_module_1();
- return pyside_globals->feature_dict;
-}
-
-} //extern "C"
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
index 2a69df9cf..b77cc0f4c 100644
--- a/sources/shiboken2/libshiboken/signature.h
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -40,12 +40,10 @@
#ifndef SIGNATURE_H
#define SIGNATURE_H
-#include "sbkpython.h"
-
extern "C"
{
-LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *[]);
+LIBSHIBOKEN_API int InitSignatureStrings(PyTypeObject *, const char *[]);
LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]);
LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *);
LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, PyObject *);
diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp
new file mode 100644
index 000000000..76a71b00b
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature/signature.cpp
@@ -0,0 +1,479 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature.cpp
+// -------------
+//
+// This is the main file of the signature module.
+// It contains the most important functions and avoids confusion
+// by moving many helper functions elsewhere.
+//
+// General documentation can be found in `signature_doc.rst`.
+//
+
+#include "basewrapper.h"
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+#include <structmember.h>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+static PyObject *CreateSignature(PyObject *props, PyObject *key)
+{
+ /*
+ * Here is the new function to create all signatures. It simply calls
+ * into Python and creates a signature object directly.
+ * This is so much simpler than using all the attributes explicitly
+ * to support '_signature_is_functionlike()'.
+ */
+ return PyObject_CallFunction(pyside_globals->create_signature_func,
+ const_cast<char *>("(OO)"), props, key);
+}
+
+PyObject *GetClassOrModOf(PyObject *ob)
+{
+ /*
+ * Return the type or module of a function or type.
+ * The purpose is finally to use the name of the object.
+ */
+ if (PyType_Check(ob)) {
+ // PySide-928: The type case must do refcounting like the others as well.
+ Py_INCREF(ob);
+ return ob;
+ }
+ if (PyType_IsSubtype(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 GetClassOrModOf");
+ return nullptr;
+}
+
+PyObject *GetTypeKey(PyObject *ob)
+{
+ assert(PyType_Check(ob) || PyModule_Check(ob));
+ /*
+ * Obtain a unique key using the module name and the type name.
+ *
+ * PYSIDE-1286: We use correct __module__ and __qualname__, now.
+ */
+ AutoDecRef module_name(PyObject_GetAttr(ob, PyMagicName::module()));
+ if (module_name.isNull()) {
+ // We have no module_name because this is a module ;-)
+ PyErr_Clear();
+ module_name.reset(PyObject_GetAttr(ob, PyMagicName::name()));
+ return Py_BuildValue("O", module_name.object());
+ }
+ AutoDecRef class_name(_get_qualname(ob));
+ if (class_name.isNull()) {
+ Py_FatalError("Signature: missing class name in GetTypeKey");
+ return nullptr;
+ }
+ return Py_BuildValue("(OO)", module_name.object(), class_name.object());
+}
+
+static PyObject *empty_dict = nullptr;
+
+PyObject *TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype)
+{
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ if (dict == nullptr) {
+ if (empty_dict == nullptr)
+ empty_dict = PyDict_New();
+ dict = empty_dict;
+ }
+ if (!PyDict_Check(dict))
+ dict = PySide_BuildSignatureProps(type_key);
+ return dict;
+}
+
+static PyObject *_GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier)
+{
+ // Special case: We want to know the func_kind.
+ if (modifier) {
+#if PY_VERSION_HEX >= 0x03000000
+ PyUnicode_InternInPlace(&modifier);
+#else
+ PyString_InternInPlace(&modifier);
+#endif
+ if (modifier == PyMagicName::func_kind())
+ return Py_BuildValue("O", func_kind);
+ }
+
+ AutoDecRef key(modifier == nullptr ? Py_BuildValue("O", func_kind)
+ : Py_BuildValue("(OO)", func_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)
+ // this is an error
+ return nullptr;
+ }
+ else {
+ // key not found
+ Py_RETURN_NONE;
+ }
+ }
+ return Py_INCREF(value), value;
+}
+
+PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
+{
+ // make sure that we look into PyCFunction, only...
+ if (Py_TYPE(obfunc) == PepFunction_TypePtr)
+ Py_RETURN_NONE;
+ 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, obtype_mod);
+ 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;
+
+ int flags = PyCFunction_GET_FLAGS(obfunc);
+ PyObject *func_kind;
+ if (PyModule_Check(obtype_mod))
+ func_kind = PyName::function();
+ else if (flags & METH_CLASS)
+ func_kind = PyName::classmethod();
+ else if (flags & METH_STATIC)
+ func_kind = PyName::staticmethod();
+ else
+ func_kind = PyName::method();
+ return _GetSignature_Cached(props, func_kind, modifier);
+}
+
+PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
+{
+ AutoDecRef func_name(PyObject_GetAttr(ob, PyMagicName::name()));
+ AutoDecRef objclass(PyObject_GetAttr(ob, PyMagicName::objclass()));
+ AutoDecRef class_key(GetTypeKey(objclass));
+ if (func_name.isNull() || objclass.isNull() || class_key.isNull())
+ return nullptr;
+ PyObject *dict = TypeKey_to_PropsDict(class_key, objclass);
+ if (dict == nullptr)
+ return nullptr;
+ PyObject *props = PyDict_GetItem(dict, func_name);
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+
+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);
+ if (dict == nullptr)
+ return nullptr;
+ PyObject *props = PyDict_GetItem(dict, ob_name);
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// get_signature -- providing a superior interface
+//
+// Additional to the interface via `__signature__`, we also provide
+// a general function, which allows for different signature layouts.
+// The `modifier` argument is a string that is passed in from `loader.py`.
+// Configuration what the modifiers mean is completely in Python.
+//
+
+PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
+{
+ if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
+ return pyside_cf_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return pyside_sm_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return pyside_md_get___signature__(ob, modifier);
+ if (PyType_Check(ob))
+ return pyside_tp_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ return nullptr;
+}
+
+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)
+ Py_RETURN_NONE;
+ PyObject *ret = get_signature_intern(ob, modifier);
+ if (ret != nullptr)
+ return ret;
+ Py_RETURN_NONE;
+}
+
+PyMethodDef signature_methods[] = {
+ {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
+ "get the __signature__, but pass an optional string parameter"},
+ {nullptr, nullptr}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Argument Handling
+// -----------------
+//
+// * PySide_BuildSignatureArgs
+//
+// Called during class or module initialization.
+// The signature strings from the C modules are stored in a dict for
+// later use.
+//
+// * PySide_BuildSignatureProps
+//
+// Called on demand during signature retieval. This function calls all the way
+// through `parser.py` and prepares all properties for the functions of the class.
+// The parsed properties can then be used to create signature objects.
+//
+
+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
+ * 2**15 unicode characters (64 K memory).
+ * Instead of one huge string, we take a ssize_t that is the
+ * address of a string array. It will not be turned into a real
+ * string list until really used by Python. This is quite optimal.
+ */
+ AutoDecRef numkey(Py_BuildValue("n", signatures));
+ if (type_key.isNull() || numkey.isNull()
+ || PyDict_SetItem(pyside_globals->arg_dict, type_key, numkey) < 0)
+ return -1;
+ /*
+ * We record also a mapping from type key to type/module. This helps to
+ * lazily initialize the Py_LIMITED_API in name_key_to_func().
+ */
+ return PyDict_SetItem(pyside_globals->map_dict, type_key, obtype_mod) == 0 ? 0 : -1;
+}
+
+PyObject *PySide_BuildSignatureProps(PyObject *type_key)
+{
+ /*
+ * Here is the second part of the function.
+ * This part will be called on-demand when needed by some attribute.
+ * We simply pick up the arguments that we stored here and replace
+ * them by the function result.
+ */
+ init_module_2();
+ if (type_key == nullptr)
+ return nullptr;
+ PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ AutoDecRef strings(_address_to_stringlist(numkey));
+ if (strings.isNull())
+ return nullptr;
+ AutoDecRef arg_tup(Py_BuildValue("(OO)", type_key, strings.object()));
+ if (arg_tup.isNull())
+ return nullptr;
+ PyObject *dict = PyObject_CallObject(pyside_globals->pyside_type_init_func, arg_tup);
+ if (dict == nullptr) {
+ if (PyErr_Occurred())
+ return nullptr;
+ // No error: return an empty dict.
+ if (empty_dict == nullptr)
+ empty_dict = PyDict_New();
+ return empty_dict;
+ }
+ // We replace the arguments by the result dict.
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
+ return nullptr;
+ return dict;
+}
+//
+////////////////////////////////////////////////////////////////////////////
+
+static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
+{
+ /*
+ * Initialization of module functions and resolving of static methods.
+ */
+ const char *name = PyModule_GetName(module);
+ if (name == nullptr)
+ return -1;
+
+ // we abuse the call for types, since they both have a __name__ attribute.
+ if (PySide_BuildSignatureArgs(module, signatures) < 0)
+ return -1;
+
+ /*
+ * Note: This function crashed when called from PySide_BuildSignatureArgs.
+ * Probably this was an import timing problem.
+ *
+ * Pep384: We need to switch this always on since we have no access
+ * to the PyCFunction attributes. Therefore I simplified things
+ * and always use our own mapping.
+ */
+ PyObject *key, *func, *obdict = PyModule_GetDict(module);
+ Py_ssize_t pos = 0;
+
+ 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;
+ // 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).
+ if (pyside_globals->finish_import_func == nullptr) {
+ assert(strncmp(name, "PySide2.", 8) != 0);
+ return 0;
+ }
+ AutoDecRef ret(PyObject_CallFunction(
+ pyside_globals->finish_import_func, const_cast<char *>("(O)"), module));
+ return ret.isNull() ? -1 : 0;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// External functions interface
+//
+// These are exactly the supported functions from `signature.h`.
+//
+
+int InitSignatureStrings(PyTypeObject *type, const char *signatures[])
+{
+ auto *ob_type = reinterpret_cast<PyObject *>(type);
+ int ret = PySide_BuildSignatureArgs(ob_type, signatures);
+ if (ret < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+ return ret;
+}
+
+void FinishSignatureInitialization(PyObject *module, const char *signatures[])
+{
+ /*
+ * This function is called at the very end of a module initialization.
+ * We now patch certain types to support the __signature__ attribute,
+ * initialize module functions and resolve static methods.
+ *
+ * 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
+ || PySide_FinishSignatures(module, signatures) < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+}
+
+void SetError_Argument(PyObject *args, const char *func_name)
+{
+ /*
+ * 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();
+ AutoDecRef res(PyObject_CallFunction(pyside_globals->seterror_argument_func,
+ const_cast<char *>("(Os)"), args, func_name));
+ if (res.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument did not receive a result");
+ }
+ PyObject *err, *msg;
+ if (!PyArg_UnpackTuple(res, func_name, 2, 2, &err, &msg)) {
+ PyErr_Print();
+ Py_FatalError("unexpected failure in seterror_argument");
+ }
+ PyErr_SetObject(err, msg);
+}
+
+/*
+ * Support for the metatype SbkObjectType_Type's tp_getset.
+ *
+ * This was not necessary for __signature__, because PyType_Type inherited it.
+ * But the __doc__ attribute existed already by inheritance, and calling
+ * PyType_Modified() is not supported. So we added the getsets explicitly
+ * to the metatype.
+ */
+
+PyObject *Sbk_TypeGet___signature__(PyObject *ob, PyObject *modifier)
+{
+ return pyside_tp_get___signature__(ob, modifier);
+}
+
+PyObject *Sbk_TypeGet___doc__(PyObject *ob)
+{
+ return pyside_tp_get___doc__(ob);
+}
+
+PyObject *GetFeatureDict()
+{
+ init_module_1();
+ return pyside_globals->feature_dict;
+}
+
+} //extern "C"
diff --git a/sources/shiboken2/libshiboken/signature_doc.rst b/sources/shiboken2/libshiboken/signature/signature_doc.rst
index cb9041d0c..f3dc652b6 100644
--- a/sources/shiboken2/libshiboken/signature_doc.rst
+++ b/sources/shiboken2/libshiboken/signature/signature_doc.rst
@@ -73,7 +73,7 @@ It calls ``GetSignature_Function`` which returns the signature if it is found.
Why this Code is Fast
---------------------
-It costs a little time (maybe 6 seconds) to run througs every single signature
+It costs a little time (maybe 6 seconds) to run through every single signature
object, since these are more than 25000 Python objects. But all the signature
objects will be rarely accessed but in special applications.
The normal case are only a few accesses, and these are working pretty fast.
diff --git a/sources/shiboken2/libshiboken/signature/signature_extend.cpp b/sources/shiboken2/libshiboken/signature/signature_extend.cpp
new file mode 100644
index 000000000..1490a6003
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature/signature_extend.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_extend.cpp
+// --------------------
+//
+// This file contains the additions and changes to the following
+// Python types:
+//
+// PyMethodDescr_Type
+// PyCFunction_Type
+// PyStaticMethod_Type
+// PyType_Type
+// PyWrapperDescr_Type
+//
+// Their `tp_getset` fields are modified so support the `__signature__`
+// attribute and additions to the `__doc__` attribute.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+typedef PyObject *(*signaturefunc)(PyObject *, PyObject *);
+
+static PyObject *_get_written_signature(signaturefunc sf, PyObject *ob, PyObject *modifier)
+{
+ /*
+ * Be a writable Attribute, but have a computed value.
+ *
+ * If a signature has not been written, call the signature function.
+ * If it has been written, return the written value.
+ * After __del__ was called, the function value re-appears.
+ *
+ * Note: This serves also for the new version that does not allow any
+ * assignment if we have a computed value. We only need to check if
+ * a computed value exists and then forbid writing.
+ * See pyside_set___signature
+ */
+ PyObject *ret = PyDict_GetItem(pyside_globals->value_dict, ob);
+ if (ret == nullptr)
+ return ob == nullptr ? nullptr : sf(ob, modifier);
+ Py_INCREF(ret);
+ return ret;
+}
+
+PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier)
+{
+ init_module_2();
+ return _get_written_signature(GetSignature_Function, func, modifier);
+}
+
+PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier)
+{
+ init_module_2();
+ AutoDecRef func(PyObject_GetAttr(sm, PyMagicName::func()));
+ if (Py_TYPE(func) == PepFunction_TypePtr)
+ return PyObject_GetAttr(func, PyMagicName::signature());
+ return _get_written_signature(GetSignature_Function, func, modifier);
+}
+
+PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier)
+{
+ init_module_2();
+ AutoDecRef func(name_key_to_func(ob_md));
+ if (func.object() == Py_None)
+ return Py_None;
+ if (func.isNull())
+ Py_FatalError("missing mapping in MethodDescriptor");
+ return pyside_cf_get___signature__(func, modifier);
+}
+
+PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier)
+{
+ init_module_2();
+ return _get_written_signature(GetSignature_Wrapper, ob, modifier);
+}
+
+PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier)
+{
+ init_module_2();
+ return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Augmenting builtin types with a __signature__ attribute.
+//
+// This is a harmless change to Python, similar like __text_signature__.
+// We could avoid it, but then we would need to copy quite some module
+// initialization functions which are pretty version- and word size
+// dependent. I think this little patch is the lesser of the two evils.
+//
+// Please note that in fact we are modifying 'type', the metaclass of all
+// objects, because we add new functionality.
+//
+// Addendum 2019-01-12: We now also compute a docstring from the signature.
+//
+
+// keep the original __doc__ functions
+static PyObject *old_cf_doc_descr = nullptr;
+static PyObject *old_sm_doc_descr = nullptr;
+static PyObject *old_md_doc_descr = nullptr;
+static PyObject *old_tp_doc_descr = nullptr;
+static PyObject *old_wd_doc_descr = nullptr;
+
+static int handle_doc_in_progress = 0;
+
+static PyObject *handle_doc(PyObject *ob, PyObject *old_descr)
+{
+ init_module_1();
+ init_module_2();
+ AutoDecRef ob_type_mod(GetClassOrModOf(ob));
+ const char *name;
+ if (PyModule_Check(ob_type_mod))
+ name = PyModule_GetName(ob_type_mod);
+ else
+ name = reinterpret_cast<PyTypeObject *>(ob_type_mod.object())->tp_name;
+ if (handle_doc_in_progress || name == nullptr
+ || strncmp(name, "PySide2.", 8) != 0)
+ return PyObject_CallMethodObjArgs(old_descr,
+ PyMagicName::get(),
+ ob, nullptr);
+ handle_doc_in_progress++;
+ PyObject *res = PyObject_CallFunction(
+ pyside_globals->make_helptext_func,
+ const_cast<char *>("(O)"), ob);
+ handle_doc_in_progress--;
+ if (res == nullptr) {
+ PyErr_Print();
+ Py_FatalError("handle_doc did not receive a result");
+ }
+ return res;
+}
+
+static PyObject *pyside_cf_get___doc__(PyObject *cf)
+{
+ return handle_doc(cf, old_cf_doc_descr);
+}
+
+static PyObject *pyside_sm_get___doc__(PyObject *sm)
+{
+ return handle_doc(sm, old_sm_doc_descr);
+}
+
+static PyObject *pyside_md_get___doc__(PyObject *md)
+{
+ return handle_doc(md, old_md_doc_descr);
+}
+
+PyObject *pyside_tp_get___doc__(PyObject *tp)
+{
+ return handle_doc(tp, old_tp_doc_descr);
+}
+
+static PyObject *pyside_wd_get___doc__(PyObject *wd)
+{
+ return handle_doc(wd, old_wd_doc_descr);
+}
+
+// the default setter for all objects
+static int pyside_set___signature__(PyObject *op, PyObject *value)
+{
+ // By this additional check, this function refuses write access.
+ // We consider both nullptr and Py_None as not been written.
+ AutoDecRef has_val(get_signature_intern(op, nullptr));
+ if (!(has_val.isNull() || has_val == Py_None)) {
+ PyErr_Format(PyExc_AttributeError,
+ "Attribute '__signature__' of '%.50s' object is not writable",
+ Py_TYPE(op)->tp_name);
+ return -1;
+ }
+ int ret = value == nullptr ? PyDict_DelItem(pyside_globals->value_dict, op)
+ : PyDict_SetItem(pyside_globals->value_dict, op, value);
+ Py_XINCREF(value);
+ return ret;
+}
+
+static PyGetSetDef new_PyCFunction_getsets[] = {
+ {const_cast<char *>("__doc__"), (getter)pyside_cf_get___doc__},
+ {const_cast<char *>("__signature__"), (getter)pyside_cf_get___signature__,
+ (setter)pyside_set___signature__},
+ {nullptr}
+};
+
+static PyGetSetDef new_PyStaticMethod_getsets[] = {
+ {const_cast<char *>("__doc__"), (getter)pyside_sm_get___doc__},
+ {const_cast<char *>("__signature__"), (getter)pyside_sm_get___signature__,
+ (setter)pyside_set___signature__},
+ {nullptr}
+};
+
+static PyGetSetDef new_PyMethodDescr_getsets[] = {
+ {const_cast<char *>("__doc__"), (getter)pyside_md_get___doc__},
+ {const_cast<char *>("__signature__"), (getter)pyside_md_get___signature__,
+ (setter)pyside_set___signature__},
+ {nullptr}
+};
+
+static PyGetSetDef new_PyType_getsets[] = {
+ {const_cast<char *>("__doc__"), (getter)pyside_tp_get___doc__},
+ {const_cast<char *>("__signature__"), (getter)pyside_tp_get___signature__,
+ (setter)pyside_set___signature__},
+ {nullptr}
+};
+
+static PyGetSetDef new_PyWrapperDescr_getsets[] = {
+ {const_cast<char *>("__doc__"), (getter)pyside_wd_get___doc__},
+ {const_cast<char *>("__signature__"), (getter)pyside_wd_get___signature__,
+ (setter)pyside_set___signature__},
+ {nullptr}
+};
+
+int PySide_PatchTypes(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ AutoDecRef meth_descr(PyObject_GetAttrString(
+ reinterpret_cast<PyObject *>(&PyString_Type), "split"));
+ AutoDecRef wrap_descr(PyObject_GetAttrString(
+ reinterpret_cast<PyObject *>(Py_TYPE(Py_True)), "__add__"));
+ // abbreviations for readability
+ auto md_gs = new_PyMethodDescr_getsets;
+ auto md_doc = &old_md_doc_descr;
+ auto cf_gs = new_PyCFunction_getsets;
+ auto cf_doc = &old_cf_doc_descr;
+ auto sm_gs = new_PyStaticMethod_getsets;
+ auto sm_doc = &old_sm_doc_descr;
+ auto tp_gs = new_PyType_getsets;
+ auto tp_doc = &old_tp_doc_descr;
+ auto wd_gs = new_PyWrapperDescr_getsets;
+ auto wd_doc = &old_wd_doc_descr;
+
+ if (meth_descr.isNull() || wrap_descr.isNull()
+ || PyType_Ready(Py_TYPE(meth_descr)) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, md_gs, md_doc) < 0
+ || add_more_getsets(&PyCFunction_Type, cf_gs, cf_doc) < 0
+ || add_more_getsets(PepStaticMethod_TypePtr, sm_gs, sm_doc) < 0
+ || add_more_getsets(&PyType_Type, tp_gs, tp_doc) < 0
+ || add_more_getsets(Py_TYPE(wrap_descr), wd_gs, wd_doc) < 0
+ )
+ return -1;
+ init_done = 1;
+ }
+ return 0;
+}
+
+} // extern "C"
diff --git a/sources/shiboken2/libshiboken/signature/signature_globals.cpp b/sources/shiboken2/libshiboken/signature/signature_globals.cpp
new file mode 100644
index 000000000..6af64682e
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature/signature_globals.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_global.cpp
+//
+// This file contains the global data structures and init code.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+static const char *PySide_CompressedSignaturePackage[] = {
+#include "embed/signature_inc.h"
+ };
+
+static const unsigned char PySide_SignatureLoader[] = {
+#include "embed/signature_bootstrap_inc.h"
+ };
+
+static PyObject *_init_pyside_extension(PyObject * /* self */, PyObject * /* args */)
+{
+ init_module_1();
+ init_module_2();
+ Py_RETURN_NONE;
+}
+
+// This function will be inserted into __builtins__.
+static PyMethodDef init_methods[] = {
+ {"_init_pyside_extension", (PyCFunction)_init_pyside_extension, METH_NOARGS},
+ {nullptr, nullptr}
+};
+
+static safe_globals_struc *init_phase_1(PyMethodDef *init_meth)
+{
+ {
+ auto *p = reinterpret_cast<safe_globals_struc *>
+ (malloc(sizeof(safe_globals_struc)));
+ if (p == nullptr)
+ goto error;
+ /*
+ * Initializing module signature_bootstrap.
+ * Since we now have an embedding script, we can do this without any
+ * Python strings in the C code.
+ */
+#ifdef Py_LIMITED_API
+ // We must work for multiple versions, so use source code.
+#else
+ AutoDecRef marshal_module(PyImport_Import(PyName::marshal()));
+ if (marshal_module.isNull())
+ goto error;
+ AutoDecRef loads(PyObject_GetAttr(marshal_module, PyName::loads()));
+ if (loads.isNull())
+ goto error;
+#endif
+ char *bytes_cast = reinterpret_cast<char *>(
+ const_cast<unsigned char *>(PySide_SignatureLoader));
+ AutoDecRef bytes(PyBytes_FromStringAndSize(bytes_cast, sizeof(PySide_SignatureLoader)));
+ if (bytes.isNull())
+ goto error;
+#ifdef Py_LIMITED_API
+ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *compile = PyDict_GetItem(builtins, PyName::compile());
+ if (compile == nullptr)
+ goto error;
+ AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss",
+ bytes.object(), "(builtin)", "exec"));
+#else
+ AutoDecRef code_obj(PyObject_CallFunctionObjArgs(
+ loads, bytes.object(), nullptr));
+#endif
+ if (code_obj.isNull())
+ goto error;
+ p->helper_module = PyImport_ExecCodeModule(const_cast<char *>
+ ("signature_bootstrap"), code_obj);
+ if (p->helper_module == nullptr)
+ goto error;
+ // Initialize the module
+ PyObject *mdict = PyModule_GetDict(p->helper_module);
+ if (PyDict_SetItem(mdict, PyMagicName::builtins(), PyEval_GetBuiltins()) < 0)
+ goto error;
+ /*
+ * Unpack an embedded ZIP file with more signature modules.
+ * They will be loaded later with the zipimporter.
+ * Due to MSVC's limitation to 64k strings, we need to assemble pieces.
+ */
+ const char **block_ptr = (const char **)PySide_CompressedSignaturePackage;
+ int npieces = 0;
+ PyObject *piece, *zipped_string_sequence = PyList_New(0);
+ if (zipped_string_sequence == nullptr)
+ return nullptr;
+ for (; **block_ptr != 0; ++block_ptr) {
+ npieces++;
+ // we avoid the string/unicode dilemma by not using PyString_XXX:
+ piece = Py_BuildValue("s", *block_ptr);
+ if (piece == nullptr || PyList_Append(zipped_string_sequence, piece) < 0)
+ goto error;
+ }
+ if (PyDict_SetItemString(mdict, "zipstring_sequence", zipped_string_sequence) < 0)
+ goto error;
+ Py_DECREF(zipped_string_sequence);
+
+ // build a dict for diverse mappings
+ p->map_dict = PyDict_New();
+ if (p->map_dict == nullptr)
+ goto error;
+
+ // build a dict for the prepared arguments
+ p->arg_dict = PyDict_New();
+ if (p->arg_dict == nullptr
+ || PyObject_SetAttrString(p->helper_module, "pyside_arg_dict", p->arg_dict) < 0)
+ goto error;
+
+ // build a dict for assigned signature values
+ p->value_dict = PyDict_New();
+ if (p->value_dict == nullptr)
+ goto error;
+
+ // PYSIDE-1019: build a __feature__ dict
+ p->feature_dict = PyDict_New();
+ if (p->feature_dict == nullptr
+ || PyObject_SetAttrString(p->helper_module, "pyside_feature_dict", p->feature_dict) < 0)
+ goto error;
+
+ // This function will be disabled until phase 2 is done.
+ p->finish_import_func = nullptr;
+
+ // Initialize the explicit init function.
+ AutoDecRef init(PyCFunction_NewEx(init_meth, nullptr, nullptr));
+ if (init.isNull()
+ || PyDict_SetItemString(PyEval_GetBuiltins(), init_meth->ml_name, init) != 0)
+ goto error;
+
+ return p;
+ }
+error:
+ PyErr_Print();
+ Py_FatalError("could not initialize part 1");
+ return nullptr;
+}
+
+static int init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
+{
+ {
+ PyMethodDef *ml;
+
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != nullptr; ml++) {
+ PyObject *v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr
+ || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0)
+ goto error;
+ Py_DECREF(v);
+ }
+ PyObject *bootstrap_func = PyObject_GetAttrString(p->helper_module, "bootstrap");
+ if (bootstrap_func == nullptr)
+ goto error;
+ // The return value of the bootstrap function is the loader module.
+ PyObject *loader = PyObject_CallFunction(bootstrap_func, const_cast<char *>("()"));
+ if (loader == nullptr)
+ goto error;
+ // now the loader should be initialized
+ p->pyside_type_init_func = PyObject_GetAttrString(loader, "pyside_type_init");
+ if (p->pyside_type_init_func == nullptr)
+ goto error;
+ p->create_signature_func = PyObject_GetAttrString(loader, "create_signature");
+ if (p->create_signature_func == nullptr)
+ goto error;
+ p->seterror_argument_func = PyObject_GetAttrString(loader, "seterror_argument");
+ if (p->seterror_argument_func == nullptr)
+ goto error;
+ p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext");
+ if (p->make_helptext_func == nullptr)
+ goto error;
+ p->finish_import_func = PyObject_GetAttrString(loader, "finish_import");
+ if (p->finish_import_func == nullptr)
+ goto error;
+ return 0;
+ }
+error:
+ PyErr_Print();
+ Py_FatalError("could not initialize part 2");
+ return -1;
+}
+
+#ifndef _WIN32
+////////////////////////////////////////////////////////////////////////////
+// a stack trace for linux-like platforms
+#include <stdio.h>
+#if defined(__GLIBC__)
+# include <execinfo.h>
+#endif
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void handler(int sig) {
+#if defined(__GLIBC__)
+ void *array[30];
+ size_t size;
+
+ // get void *'s for all entries on the stack
+ size = backtrace(array, 30);
+
+ // print out all the frames to stderr
+#endif
+ fprintf(stderr, "Error: signal %d:\n", sig);
+#if defined(__GLIBC__)
+ backtrace_symbols_fd(array, size, STDERR_FILENO);
+#endif
+ exit(1);
+}
+
+////////////////////////////////////////////////////////////////////////////
+#endif // _WIN32
+
+safe_globals pyside_globals = nullptr;
+
+void init_module_1(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1(init_methods);
+ if (pyside_globals != nullptr)
+ init_done = 1;
+
+#ifndef _WIN32
+ // We enable the stack trace in CI, only.
+ const char *testEnv = getenv("QTEST_ENVIRONMENT");
+ if (testEnv && strstr(testEnv, "ci"))
+ signal(SIGSEGV, handler); // install our handler
+#endif // _WIN32
+
+ }
+}
+
+void init_module_2(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ // Phase 2 will call __init__.py which touches a signature, itself.
+ // Therefore we set init_done prior to init_phase_2().
+ init_done = 1;
+ init_phase_2(pyside_globals, signature_methods);
+ }
+}
+
+} // extern "C"
diff --git a/sources/shiboken2/libshiboken/signature/signature_helper.cpp b/sources/shiboken2/libshiboken/signature/signature_helper.cpp
new file mode 100644
index 000000000..7e92a9861
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature/signature_helper.cpp
@@ -0,0 +1,364 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_helper.cpp
+// --------------------
+//
+// This file contains assoerted helper functions that are needed,
+// but it is not helpful to see them all the time.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+// Helper for __qualname__ which might not always exist in Python 2 (type).
+PyObject *_get_qualname(PyObject *ob)
+{
+ // We support __qualname__ for types, only.
+ assert(PyType_Check(ob));
+ PyObject *name = PyObject_GetAttr(ob, PyMagicName::qualname());
+ if (name == nullptr) {
+ PyErr_Clear();
+ name = PyObject_GetAttr(ob, PyMagicName::name());
+ }
+ return name;
+}
+
+static int _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp)
+{
+ /*
+ * This function pre-fills all fields of the new gsp. We then
+ * insert the changed values.
+ */
+ PyGetSetDef *gsp = type->tp_getset;
+ if (gsp != nullptr) {
+ for (; gsp->name != nullptr; gsp++) {
+ if (strcmp(gsp->name, name) == 0) {
+ new_gsp->set = gsp->set;
+ new_gsp->doc = gsp->doc;
+ new_gsp->closure = gsp->closure;
+ return 1; // success
+ }
+ }
+ }
+ PyMemberDef *md = type->tp_members;
+ if (md != nullptr)
+ for (; md->name != nullptr; md++)
+ if (strcmp(md->name, name) == 0)
+ return 1;
+ // staticmethod has just a `__doc__` in the class
+ assert(strcmp(type->tp_name, "staticmethod") == 0 && strcmp(name, "__doc__") == 0);
+ return 0;
+}
+
+int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr)
+{
+ /*
+ * This function is used to assign a new `__signature__` attribute,
+ * and also to override a `__doc__` or `__name__` attribute.
+ */
+ assert(PyType_Check(type));
+ PyType_Ready(type);
+ PyObject *dict = type->tp_dict;
+ for (; gsp->name != nullptr; gsp++) {
+ PyObject *have_descr = PyDict_GetItemString(dict, gsp->name);
+ if (have_descr != nullptr) {
+ Py_INCREF(have_descr);
+ if (strcmp(gsp->name, "__doc__") == 0)
+ *doc_descr = have_descr;
+ else
+ assert(false);
+ if (!_fixup_getset(type, gsp->name, gsp))
+ continue;
+ }
+ AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+ if (descr.isNull())
+ return -1;
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ return -1;
+ }
+ PyType_Modified(type);
+ return 0;
+}
+
+static PyObject *get_funcname(PyObject *ob)
+{
+ PyObject *func = ob;
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ func = PyObject_GetAttr(ob, PyMagicName::func());
+ else
+ Py_INCREF(func);
+ PyObject *func_name = PyObject_GetAttr(func, PyMagicName::name());
+ Py_DECREF(func);
+ if (func_name == nullptr)
+ Py_FatalError("unexpected name problem in compute_name_key");
+ return func_name;
+}
+
+static PyObject *compute_name_key(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return GetTypeKey(ob);
+ AutoDecRef func_name(get_funcname(ob));
+ AutoDecRef type_key(GetTypeKey(GetClassOrModOf(ob)));
+ return Py_BuildValue("(OO)", type_key.object(), func_name.object());
+}
+
+static int build_name_key_to_func(PyObject *obtype)
+{
+ auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == nullptr)
+ return 0;
+
+ AutoDecRef type_key(GetTypeKey(obtype));
+ for (; meth->ml_name != nullptr; meth++) {
+ AutoDecRef func(PyCFunction_NewEx(meth, obtype, nullptr));
+ AutoDecRef func_name(get_funcname(func));
+ AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+PyObject *name_key_to_func(PyObject *ob)
+{
+ /*
+ * 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.
+ */
+ 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 == nullptr) {
+ // do a lazy initialization
+ AutoDecRef type_key(GetTypeKey(GetClassOrModOf(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 nullptr;
+ ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ }
+ Py_XINCREF(ret);
+ return ret;
+}
+
+PyObject *_get_class_of_cf(PyObject *ob_cf)
+{
+ PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
+ if (selftype == nullptr) {
+ selftype = PyDict_GetItem(pyside_globals->map_dict, ob_cf);
+ if (selftype == nullptr) {
+ // This must be an overloaded function that we handled special.
+ AutoDecRef special(Py_BuildValue("(OO)", ob_cf, PyName::overload()));
+ selftype = PyDict_GetItem(pyside_globals->map_dict, special);
+ if (selftype == nullptr) {
+ // This is probably a module function. We will return type(None).
+ selftype = Py_None;
+ }
+ }
+ }
+
+ PyObject *obtype_mod = (PyType_Check(selftype) || PyModule_Check(selftype))
+ ? selftype
+ : reinterpret_cast<PyObject *>(Py_TYPE(selftype));
+ Py_INCREF(obtype_mod);
+ return obtype_mod;
+}
+
+PyObject *_get_class_of_sm(PyObject *ob_sm)
+{
+ AutoDecRef func(PyObject_GetAttr(ob_sm, PyMagicName::func()));
+ return _get_class_of_cf(func);
+}
+
+PyObject *_get_class_of_descr(PyObject *ob)
+{
+ return PyObject_GetAttr(ob, PyMagicName::objclass());
+}
+
+PyObject *_address_to_stringlist(PyObject *numkey)
+{
+ /*
+ * This is a tiny optimization that saves initialization time.
+ * Instead of creating all Python strings during the call to
+ * `PySide_BuildSignatureArgs`, we store the address of the stringlist.
+ * When needed in `PySide_BuildSignatureProps`, the strings are
+ * finally materialized.
+ */
+ ssize_t address = PyNumber_AsSsize_t(numkey, PyExc_ValueError);
+ if (address == -1 && PyErr_Occurred())
+ return nullptr;
+ char **sig_strings = reinterpret_cast<char **>(address);
+ PyObject *res_list = PyList_New(0);
+ if (res_list == nullptr)
+ return nullptr;
+ for (; *sig_strings != nullptr; ++sig_strings) {
+ char *sig_str = *sig_strings;
+ AutoDecRef pystr(Py_BuildValue("s", sig_str));
+ if (pystr.isNull() || PyList_Append(res_list, pystr) < 0)
+ return nullptr;
+ }
+ return res_list;
+}
+
+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 static method to this type in a dict.
+ * We also check for hidden methods, see below.
+ */
+ auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+ PyObject *dict = type->tp_dict;
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == nullptr)
+ return 0;
+
+ for (; meth->ml_name != nullptr; meth++) {
+ /*
+ * It is possible that a method is overwritten by another
+ * attribute with the same name. This case was obviously provoked
+ * explicitly in "testbinding.TestObject.staticMethodDouble",
+ * where instead of the method a "PySide2.QtCore.Signal" object
+ * was in the dict.
+ * This overlap is also found in regular PySide under
+ * "PySide2.QtCore.QProcess.error" where again a signal object is
+ * returned. These hidden methods will be opened for the
+ * signature module by adding them under the name
+ * "{name}.overload".
+ */
+ PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
+ PyObject *look_attr = meth->ml_flags & METH_STATIC ? PyMagicName::func()
+ : PyMagicName::name();
+ int check_name = meth->ml_flags & METH_STATIC ? 0 : 1;
+ if (descr == nullptr)
+ return -1;
+
+ // We first check all methods if one is hidden by something else.
+ AutoDecRef look(PyObject_GetAttr(descr, look_attr));
+ AutoDecRef given(Py_BuildValue("s", meth->ml_name));
+ if (look.isNull()
+ || (check_name && PyObject_RichCompareBool(look, given, Py_EQ) != 1)) {
+ PyErr_Clear();
+ AutoDecRef cfunc(PyCFunction_NewEx(
+ meth, reinterpret_cast<PyObject *>(type), nullptr));
+ if (cfunc.isNull())
+ return -1;
+ if (meth->ml_flags & METH_STATIC)
+ descr = PyStaticMethod_New(cfunc);
+ else
+ descr = PyDescr_NewMethod(type, meth);
+ if (descr == nullptr)
+ return -1;
+ char mangled_name[200];
+ strcpy(mangled_name, meth->ml_name);
+ strcat(mangled_name, ".overload");
+ if (PyDict_SetItemString(dict, mangled_name, descr) < 0)
+ return -1;
+ if (meth->ml_flags & METH_STATIC) {
+ // This is the special case where a static method is hidden.
+ AutoDecRef special(Py_BuildValue("(Os)", cfunc.object(), "overload"));
+ if (PyDict_SetItem(pyside_globals->map_dict, special, obtype) < 0)
+ return -1;
+ }
+ if (PyDict_SetItemString(pyside_globals->map_dict, mangled_name, obtype) < 0)
+ return -1;
+ continue;
+ }
+ // Then we insert the mapping for static methods.
+ if (meth->ml_flags & METH_STATIC) {
+ if (PyDict_SetItem(pyside_globals->map_dict, look, obtype) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int _finish_nested_classes(PyObject *obdict)
+{
+ PyObject *key, *value, *obtype;
+ PyTypeObject *subtype;
+ Py_ssize_t pos = 0;
+
+ if (obdict == nullptr)
+ 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;
+}
+
+} // extern "C"
diff --git a/sources/shiboken2/libshiboken/signature/signature_p.h b/sources/shiboken2/libshiboken/signature/signature_p.h
new file mode 100644
index 000000000..9444f3e9b
--- /dev/null
+++ b/sources/shiboken2/libshiboken/signature/signature_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef SIGNATURE_IMPL_H
+#define SIGNATURE_IMPL_H
+
+#include "signature.h"
+
+extern "C" {
+
+// signature_globals.cpp
+
+typedef struct safe_globals_struc {
+ // init part 1: get arg_dict
+ PyObject *helper_module;
+ PyObject *arg_dict;
+ PyObject *map_dict;
+ PyObject *value_dict; // for writing signatures
+ PyObject *feature_dict; // registry for PySide.support.__feature__
+ // init part 2: run module
+ PyObject *pyside_type_init_func;
+ PyObject *create_signature_func;
+ PyObject *seterror_argument_func;
+ PyObject *make_helptext_func;
+ PyObject *finish_import_func;
+} safe_globals_struc, *safe_globals;
+
+extern safe_globals pyside_globals;
+extern PyMethodDef signature_methods[];
+
+void init_module_1(void);
+void init_module_2(void);
+
+// signature.cpp
+
+PyObject *GetTypeKey(PyObject *ob);
+
+PyObject *GetSignature_Function(PyObject *, PyObject *);
+PyObject *GetSignature_TypeMod(PyObject *, PyObject *);
+PyObject *GetSignature_Wrapper(PyObject *, PyObject *);
+
+PyObject *get_signature_intern(PyObject *ob, PyObject *modifier);
+PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+PyObject *GetClassOrModOf(PyObject *ob);
+
+// signature_extend.cpp
+
+PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier);
+PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier);
+PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier);
+PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier);
+PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier);
+
+int PySide_PatchTypes(void);
+PyObject *pyside_tp_get___doc__(PyObject *tp);
+
+// signature_helper.cpp
+
+PyObject *_get_qualname(PyObject *ob);
+int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr);
+PyObject *name_key_to_func(PyObject *ob);
+PyObject *_get_class_of_cf(PyObject *ob_cf);
+PyObject *_get_class_of_sm(PyObject *ob_sm);
+PyObject *_get_class_of_descr(PyObject *ob);
+PyObject *_address_to_stringlist(PyObject *numkey);
+int _finish_nested_classes(PyObject *dict);
+
+} // extern "C"
+
+#endif // SIGNATURE_IMPL_H
diff --git a/sources/shiboken2/tests/libsample/pen.cpp b/sources/shiboken2/tests/libsample/pen.cpp
index b08721f79..1f39e7cbb 100644
--- a/sources/shiboken2/tests/libsample/pen.cpp
+++ b/sources/shiboken2/tests/libsample/pen.cpp
@@ -69,3 +69,13 @@ int Pen::ctorType()
void Pen::drawLine(int x1, int y1, int x2, int y2, RenderHints renderHints)
{
}
+
+Pen::RenderHints Pen::getRenderHints() const
+{
+ return m_renderHints;
+}
+
+void Pen::setRenderHints(RenderHints h)
+{
+ m_renderHints = h;
+}
diff --git a/sources/shiboken2/tests/libsample/pen.h b/sources/shiboken2/tests/libsample/pen.h
index 6b3bf9f1a..20977fdeb 100644
--- a/sources/shiboken2/tests/libsample/pen.h
+++ b/sources/shiboken2/tests/libsample/pen.h
@@ -60,8 +60,13 @@ public:
void drawLine(int x1, int y1, int x2, int y2, RenderHints renderHints = {});
int ctorType();
+
+ RenderHints getRenderHints() const;
+ void setRenderHints(RenderHints h);
+
private:
int m_ctor;
+ RenderHints m_renderHints = None;
};
#endif
diff --git a/sources/shiboken2/tests/libsample/removednamespaces.h b/sources/shiboken2/tests/libsample/removednamespaces.h
index 1de028d38..c9732f8a6 100644
--- a/sources/shiboken2/tests/libsample/removednamespaces.h
+++ b/sources/shiboken2/tests/libsample/removednamespaces.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of Qt for Python.
@@ -34,35 +34,29 @@
namespace RemovedNamespace1
{
-enum RemovedNamespace1_Enum {
- RemovedNamespace1_Enum_Value0
-};
+enum RemovedNamespace1_Enum { RemovedNamespace1_Enum_Value0 };
-enum {
- RemovedNamespace1_AnonymousEnum_Value0
-};
+enum { RemovedNamespace1_AnonymousEnum_Value0 };
-namespace RemovedNamespace2 {
- enum RemovedNamespace2_Enum {
- RemovedNamespace2_Enum_Value0
- };
-}
+namespace RemovedNamespace2
+{
+
+enum RemovedNamespace2_Enum { RemovedNamespace2_Enum_Value0 };
-}
+} // namespace RemovedNamespace2
+} // namespace RemovedNamespace1
namespace UnremovedNamespace
{
+
namespace RemovedNamespace3
{
- enum RemovedNamespace3_Enum {
- RemovedNamespace3_Enum_Value0
- };
+ enum RemovedNamespace3_Enum { RemovedNamespace3_Enum_Value0 };
+
+ enum { RemovedNamespace3_AnonymousEnum_Value0 };
- enum {
- RemovedNamespace3_AnonymousEnum_Value0
- };
-}
-}
+} // namespace RemovedNamespace3
+} // namespace UnremovedNamespace
#endif // REMOVEDNAMESPACE_H
diff --git a/sources/shiboken2/tests/samplebinding/pen_test.py b/sources/shiboken2/tests/samplebinding/pen_test.py
index 89abf4d54..ff6ee5e0e 100644
--- a/sources/shiboken2/tests/samplebinding/pen_test.py
+++ b/sources/shiboken2/tests/samplebinding/pen_test.py
@@ -65,7 +65,19 @@ class TestPen(unittest.TestCase):
self.assertEqual(pen.ctorType(), Pen.ColorCtor)
pen.drawLine(0, 0, 5, 5)
+ def testPenRenderHintsProperty(self):
+ """Exercise the generated property setter and getters, checking
+ against the C++ getter/setter functions."""
+ pen = Pen(1)
+ self.assertEqual(pen.getRenderHints(), Pen.RenderHints.None_)
+ self.assertEqual(pen.renderHints, Pen.RenderHints.None_)
+ pen.renderHints = Pen.RenderHints.TextAntialiasing
+ self.assertEqual(pen.getRenderHints(), Pen.RenderHints.TextAntialiasing)
+ self.assertEqual(pen.renderHints, Pen.RenderHints.TextAntialiasing)
+ pen.setRenderHints(Pen.RenderHints.Antialiasing)
+ self.assertEqual(pen.getRenderHints(), Pen.RenderHints.Antialiasing)
+ self.assertEqual(pen.renderHints, Pen.RenderHints.Antialiasing)
+
if __name__ == '__main__':
unittest.main()
-
diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
index 65738b85e..fdddb80f2 100644
--- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
@@ -601,16 +601,16 @@
</add-function>
</namespace-type>
- <namespace-type name="RemovedNamespace1" generate='no'>
+ <namespace-type name="RemovedNamespace1" visible='false'>
<enum-type name="RemovedNamespace1_Enum" />
- <namespace-type name="RemovedNamespace2" generate='no'>
+ <namespace-type name="RemovedNamespace2" visible='false'>
<enum-type name="RemovedNamespace2_Enum" />
</namespace-type>
<enum-type identified-by-value="RemovedNamespace1_AnonymousEnum_Value0" />
</namespace-type>
<namespace-type name="UnremovedNamespace">
- <namespace-type name="RemovedNamespace3" generate='no'>
+ <namespace-type name="RemovedNamespace3" visible='false'>
<enum-type name="RemovedNamespace3_Enum" />
<enum-type identified-by-value="RemovedNamespace3_AnonymousEnum_Value0" />
</namespace-type>
@@ -2320,6 +2320,7 @@
<value-type name="Pen">
<enum-type identified-by-value="EnumCtor"/>
<enum-type name="RenderHints"/>
+ <property type="RenderHints" name="renderHints" get="getRenderHints" set="setRenderHints"/>
</value-type>
<value-type name="CtorConvRule">