aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-03-01 08:19:26 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2019-03-01 08:19:26 +0100
commit639c5df6ad397ba98ca727c744278372087b2d46 (patch)
tree31e84eab330cb8a0a1f1236c85c8fad968918ceb /sources
parentb97ccab8c268d260f704e11b33d64fa31f74e258 (diff)
parent099f3f46ca9ec1362f211278df4b3e4949b0a339 (diff)
Merge remote-tracking branch 'origin/5.12' into dev
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside2/PySide2/QtPrintSupport/CMakeLists.txt6
-rw-r--r--sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml.in46
-rw-r--r--sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport_common.xml (renamed from sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml)7
-rw-r--r--sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml3
-rw-r--r--sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt4
-rw-r--r--sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml1
-rw-r--r--sources/pyside2/PySide2/glue/qtprintsupport.cpp43
-rw-r--r--sources/pyside2/PySide2/support/generate_pyi.py10
-rw-r--r--sources/pyside2/doc/index.rst12
-rw-r--r--sources/pyside2/tests/registry/init_platform.py6
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp41
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp124
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h13
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst19
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp130
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h3
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp21
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h4
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_p.h1
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp2
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp2
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp4
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt4
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/contextlib36.py472
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py4
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/loader.py4
-rw-r--r--sources/shiboken2/tests/libsmart/smart.cpp9
-rw-r--r--sources/shiboken2/tests/libsmart/smart.h1
-rw-r--r--sources/shiboken2/tests/smartbinding/smart_pointer_test.py19
-rw-r--r--sources/shiboken2/tests/smartbinding/typesystem_smart.xml30
30 files changed, 949 insertions, 96 deletions
diff --git a/sources/pyside2/PySide2/QtPrintSupport/CMakeLists.txt b/sources/pyside2/PySide2/QtPrintSupport/CMakeLists.txt
index 3482c68fe..74d3dfb88 100644
--- a/sources/pyside2/PySide2/QtPrintSupport/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtPrintSupport/CMakeLists.txt
@@ -13,6 +13,9 @@ ${QtPrintSupport_GEN_DIR}/qprintpreviewwidget_wrapper.cpp
${QtPrintSupport_GEN_DIR}/qtprintsupport_module_wrapper.cpp
)
+configure_file("${QtPrintSupport_SOURCE_DIR}/typesystem_printsupport.xml.in"
+ "${QtPrintSupport_BINARY_DIR}/typesystem_printsupport.xml" @ONLY)
+
set(QtPrintSupport_include_dirs ${QtPrintSupport_SOURCE_DIR}
${QtPrintSupport_BINARY_DIR}
${Qt5Core_INCLUDE_DIRS}
@@ -36,4 +39,5 @@ create_pyside_module(NAME QtPrintSupport
LIBRARIES QtPrintSupport_libraries
DEPS QtPrintSupport_deps
TYPESYSTEM_PATH QtPrintSupport_SOURCE_DIR
- SOURCES QtPrintSupport_SRC)
+ SOURCES QtPrintSupport_SRC
+ TYPESYSTEM_NAME ${QtPrintSupport_BINARY_DIR}/typesystem_printsupport.xml)
diff --git a/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml.in b/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml.in
new file mode 100644
index 000000000..7949b2daa
--- /dev/null
+++ b/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml.in
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+-->
+<typesystem package="PySide2.QtPrintSupport">
+ <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
+ <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
+ <load-typesystem name="QtPrintSupport/typesystem_printsupport_common.xml" generate="yes"/>
+</typesystem>
diff --git a/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml b/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport_common.xml
index f85aadc79..5026997c1 100644
--- a/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport.xml
+++ b/sources/pyside2/PySide2/QtPrintSupport/typesystem_printsupport_common.xml
@@ -40,7 +40,6 @@
****************************************************************************/
-->
<typesystem package="PySide2.QtPrintSupport">
- <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
<object-type name="QPageSetupDialog">
<modify-function signature="exec()" rename="exec_" allow-thread="yes"/>
@@ -105,6 +104,12 @@
<extra-includes>
<include file-name="QPrinterInfo" location="global"/>
</extra-includes>
+ <!-- fixme: Check if this is still required in Qt 6:
+ bool QPagedPaintDevice::setPageSize(QPageSize)
+ void QPagedPaintDevice::setPageSize(QPagedPaintDevice::PageSize) -->
+ <add-function signature="setPageSize(const QPageSize&amp;)" return-type="bool">
+ <inject-code file="../glue/qtprintsupport.cpp" snippet="setpagesize" />
+ </add-function>
</object-type>
<object-type name="QPrintPreviewDialog"/>
diff --git a/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml b/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml
index 8086da01e..2cbe490aa 100644
--- a/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml
+++ b/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml
@@ -90,18 +90,21 @@
<modify-function signature="createAction(QObject*,const QString&amp;)">
<modify-argument index="return">
<parent index="1" action="add"/>
+ <define-ownership class="target" owner="default"/>
</modify-argument>
</modify-function>
<modify-function signature="createActionGroup(QObject*,const QString&amp;)">
<modify-argument index="return">
<parent index="1" action="add"/>
+ <define-ownership class="target" owner="default"/>
</modify-argument>
</modify-function>
<modify-function signature="createLayout(const QString&amp;,QObject*,const QString&amp;)">
<modify-argument index="return">
<parent index="2" action="add"/>
+ <define-ownership class="target" owner="default"/>
</modify-argument>
</modify-function>
diff --git a/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt b/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt
index 555be9c41..214ebc56b 100644
--- a/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt
@@ -34,6 +34,7 @@ set(QtWebEngineWidgets_include_dirs
${QtNetwork_GEN_DIR}
${QtWebChannel_GEN_DIR}
${QtWebEngineCore_GEN_DIR}
+ ${QtPrintSupport_GEN_DIR}
)
set(QtWebEngineWidgets_libraries pyside2
${Qt5WebEngineWidgets_LIBRARIES}
@@ -42,8 +43,9 @@ set(QtWebEngineWidgets_libraries pyside2
${Qt5Widgets_LIBRARIES}
${Qt5Gui_LIBRARIES}
${Qt5Core_LIBRARIES}
+ ${Qt5PrintSupport_LIBRARIES}
)
-set(QtWebEngineWidgets_deps QtGui QtWidgets QtNetwork QtWebChannel)
+set(QtWebEngineWidgets_deps QtGui QtWidgets QtNetwork QtWebChannel QtPrintSupport)
create_pyside_module(NAME QtWebEngineWidgets
INCLUDE_DIRS QtWebEngineWidgets_include_dirs
LIBRARIES QtWebEngineWidgets_libraries
diff --git a/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml b/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml
index e51303c42..cd4cd8a91 100644
--- a/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml
+++ b/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml
@@ -46,6 +46,7 @@
<load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
<load-typesystem name="QtWebChannel/typesystem_webchannel.xml" generate="no"/>
<load-typesystem name="QtWebEngineCore/typesystem_webenginecore.xml" generate="no"/>
+ <load-typesystem name="QtPrintSupport/typesystem_printsupport.xml" generate="no"/>
<object-type name="QWebEngineCertificateError">
diff --git a/sources/pyside2/PySide2/glue/qtprintsupport.cpp b/sources/pyside2/PySide2/glue/qtprintsupport.cpp
new file mode 100644
index 000000000..300a498c0
--- /dev/null
+++ b/sources/pyside2/PySide2/glue/qtprintsupport.cpp
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+// @snippet setpagesize
+bool out = %CPPSELF.setPageSize(%1);
+%PYARG_0 = %CONVERTTOPYTHON[bool](out);
+// @snippet setpagesize
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py
index a92ee76f0..21ef841fe 100644
--- a/sources/pyside2/PySide2/support/generate_pyi.py
+++ b/sources/pyside2/PySide2/support/generate_pyi.py
@@ -53,6 +53,13 @@ import re
import subprocess
import argparse
import glob
+# PYSIDE-953: Use a newer contextlib for Python 3.5
+skip_creation = False
+if sys.version_info[:2] == (3, 5):
+ try:
+ import PySide2.support.signature # gets new contextlib
+ except:
+ skip_creation = True
from contextlib import contextmanager
from textwrap import dedent
@@ -272,6 +279,9 @@ def single_process(lockdir):
def generate_all_pyi(outpath, options):
+ if skip_creation:
+ logger.warn("Sorry, we cannot create .pyi files with Python 3.5 while PySide")
+ logger.warn(" is not installed. Please run it by hand!")
ps = os.pathsep
if options.sys_path:
# make sure to propagate the paths from sys_path to subprocesses
diff --git a/sources/pyside2/doc/index.rst b/sources/pyside2/doc/index.rst
index 474449a69..7f3b8e4a7 100644
--- a/sources/pyside2/doc/index.rst
+++ b/sources/pyside2/doc/index.rst
@@ -1,12 +1,12 @@
|project|
*************
-The |project| product enables the use of Qt5 APIs in Python applications. It
-lets Python developers utilize the full potential of Qt, using the |pymodname| module.
-The |pymodname| module provides access to the individual Qt modules such as QtCore,
-QtGui, and so on. |project| also comes with the :doc:`Shiboken2 <shiboken2:index>`
-CPython binding code generator, which can be used to generate Python bindings for
-your C or C++ code.
+|project| offers Python bindings for Qt, enabling the use of Qt5 APIs in Python
+applications. It lets Python developers utilize the full potential of Qt, using
+the |pymodname| module. The |pymodname| module provides access to the individual
+Qt modules such as QtCore, QtGui, and so on. |project| also comes with the
+:doc:`Shiboken2 <shiboken2:index>` CPython binding code generator, which can be
+used to generate Python bindings for your C or C++ code.
.. toctree::
:name: mastertoc
diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py
index a324c36a2..6031dd2ad 100644
--- a/sources/pyside2/tests/registry/init_platform.py
+++ b/sources/pyside2/tests/registry/init_platform.py
@@ -55,7 +55,8 @@ shiboken and pysidetest projects.
import sys
import os
import re
-from contextlib import contextmanager
+# PYSIDE-953: Use a newer contextlib for Python 3.5
+# from contextlib import contextmanager
from textwrap import dedent
script_dir = os.path.normpath(os.path.join(__file__, *".. .. .. .. ..".split()))
@@ -117,6 +118,9 @@ sys.path[:0] = [os.path.join(shiboken_build_dir, "shibokenmodule"),
pyside_build_dir]
import PySide2
+# PYSIDE-953: Use a newer contextlib for Python 3.5
+import PySide2.support.signature # new contextlib
+from contextlib import contextmanager
all_modules = list("PySide2." + x for x in PySide2.__all__)
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 15700e91e..37ff3b72c 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -1871,40 +1871,12 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func
return true;
}
-static bool generateExceptionHandling(const AbstractMetaFunction *func,
- ExceptionSpecification spec,
- TypeSystem::ExceptionHandling handling)
-{
- switch (func->functionType()) {
- case AbstractMetaFunction::CopyConstructorFunction:
- case AbstractMetaFunction::MoveConstructorFunction:
- case AbstractMetaFunction::AssignmentOperatorFunction:
- case AbstractMetaFunction::MoveAssignmentOperatorFunction:
- case AbstractMetaFunction::DestructorFunction:
- return false;
- default:
- break;
- }
- switch (handling) {
- case TypeSystem::ExceptionHandling::On:
- return true;
- case TypeSystem::ExceptionHandling::AutoDefaultToOn:
- return spec != ExceptionSpecification::NoExcept;
- case TypeSystem::ExceptionHandling::AutoDefaultToOff:
- return spec == ExceptionSpecification::Throws;
- default:
- break;
- }
- return false;
-}
-
AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem)
{
if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty())
return nullptr;
QString functionName = functionItem->name();
QString className;
- TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
if (m_currentClass) {
// Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT
// and overridden metaObject(), QGADGET helpers
@@ -1913,7 +1885,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
return nullptr;
}
className = m_currentClass->typeEntry()->qualifiedCppName();
- exceptionHandling = m_currentClass->typeEntry()->exceptionHandling();
if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject"))
return nullptr;
}
@@ -2085,16 +2056,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass);
for (const FunctionModification &mod : functionMods) {
- if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) {
- exceptionHandling = mod.exceptionHandling();
- break;
- }
+ if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified)
+ metaFunction->setExceptionHandlingModification(mod.exceptionHandling());
+ else if (mod.allowThread() != TypeSystem::AllowThread::Unspecified)
+ metaFunction->setAllowThreadModification(mod.allowThread());
}
- metaFunction->setGenerateExceptionHandling(generateExceptionHandling(metaFunction,
- functionItem->exceptionSpecification(),
- exceptionHandling));
-
// Find the correct default values
for (int i = 0, size = metaArguments.size(); i < size; ++i) {
const ArgumentModelItem &arg = arguments.at(i);
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 73f1bf621..a10a15b08 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -72,6 +72,26 @@ MetaClass *findByName(QVector<MetaClass *> haystack, QStringView needle)
return nullptr;
}
+// Helper for recursing the base classes of an AbstractMetaClass.
+// Returns the class for which the predicate is true.
+template <class Predicate>
+const AbstractMetaClass *recurseClassHierarchy(const AbstractMetaClass *klass,
+ Predicate pred)
+{
+ if (pred(klass))
+ return klass;
+ if (auto base = klass->baseClass()) {
+ if (auto r = recurseClassHierarchy(base, pred))
+ return r;
+ }
+ const auto interfaces = klass->interfaces();
+ for (auto i : interfaces) {
+ if (auto r = recurseClassHierarchy(i, pred))
+ return r;
+ }
+ return nullptr;
+}
+
/*******************************************************************************
* AbstractMetaVariable
*/
@@ -411,8 +431,7 @@ AbstractMetaFunction::AbstractMetaFunction()
m_userAdded(false),
m_explicit(false),
m_pointerOperator(false),
- m_isCallOperator(false),
- m_generateExceptionHandling(false)
+ m_isCallOperator(false)
{
}
@@ -531,7 +550,8 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const
cpy->setType(type()->copy());
cpy->setConstant(isConstant());
cpy->setExceptionSpecification(m_exceptionSpecification);
- cpy->setGenerateExceptionHandling(m_generateExceptionHandling);
+ cpy->setAllowThreadModification(m_allowThreadModification);
+ cpy->setExceptionHandlingModification(m_exceptionHandlingModification);
for (AbstractMetaArgument *arg : m_arguments)
cpy->addArgument(arg->copy());
@@ -754,28 +774,40 @@ bool AbstractMetaFunction::autoDetectAllowThread() const
return !maybeGetter;
}
-bool AbstractMetaFunction::allowThread() const
+static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClass *klass)
{
- using AllowThread = TypeSystem::AllowThread;
+ return klass->typeEntry()->allowThread();
+}
- if (m_cachedAllowThread < 0) {
- AllowThread allowThread = AllowThread::Auto;
- // Find a modification that specifies allowThread
- const FunctionModificationList &modifications = this->modifications(declaringClass());
- for (const FunctionModification &modification : modifications) {
- if (modification.allowThread() != AllowThread::Unspecified) {
- allowThread = modification.allowThread();
- break;
- }
- }
+static inline bool hasAllowThreadMod(const AbstractMetaClass *klass)
+{
+ return allowThreadMod(klass) != TypeSystem::AllowThread::Unspecified;
+}
- m_cachedAllowThread = allowThread == AllowThread::Allow
- || (allowThread == AllowThread::Auto && autoDetectAllowThread()) ? 1 : 0;
+bool AbstractMetaFunction::allowThread() const
+{
+ auto allowThreadModification = m_allowThreadModification;
+ // If there is no modification on the function, check for a base class.
+ if (m_class && allowThreadModification == TypeSystem::AllowThread::Unspecified) {
+ if (auto base = recurseClassHierarchy(m_class, hasAllowThreadMod))
+ allowThreadModification = allowThreadMod(base);
+ }
- if (m_cachedAllowThread == 0)
- qCDebug(lcShiboken).noquote() << msgDisallowThread(this);
+ bool result = true;
+ switch (allowThreadModification) {
+ case TypeSystem::AllowThread::Disallow:
+ result = false;
+ break;
+ case TypeSystem::AllowThread::Allow:
+ break;
+ case TypeSystem::AllowThread::Auto:
+ case TypeSystem::AllowThread::Unspecified:
+ result = autoDetectAllowThread();
+ break;
}
- return m_cachedAllowThread > 0;
+ if (!result)
+ qCDebug(lcShiboken).noquote() << msgDisallowThread(this);
+ return result;
}
TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
@@ -975,6 +1007,54 @@ void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e)
m_exceptionSpecification = e;
}
+static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClass *klass)
+{
+ return klass->typeEntry()->exceptionHandling();
+}
+
+static inline bool hasExceptionMod(const AbstractMetaClass *klass)
+{
+ return exceptionMod(klass) != TypeSystem::ExceptionHandling::Unspecified;
+}
+
+bool AbstractMetaFunction::generateExceptionHandling() const
+{
+ switch (m_functionType) {
+ case AbstractMetaFunction::CopyConstructorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ return false;
+ default:
+ break;
+ }
+
+ auto exceptionHandlingModification = m_exceptionHandlingModification;
+ // If there is no modification on the function, check for a base class.
+ if (m_class && exceptionHandlingModification == TypeSystem::ExceptionHandling::Unspecified) {
+ if (auto base = recurseClassHierarchy(m_class, hasExceptionMod))
+ exceptionHandlingModification = exceptionMod(base);
+ }
+
+ bool result = false;
+ switch (exceptionHandlingModification) {
+ case TypeSystem::ExceptionHandling::On:
+ result = true;
+ break;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOn:
+ result = m_exceptionSpecification != ExceptionSpecification::NoExcept;
+ break;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOff:
+ result = m_exceptionSpecification == ExceptionSpecification::Throws;
+ break;
+ case TypeSystem::ExceptionHandling::Unspecified:
+ case TypeSystem::ExceptionHandling::Off:
+ break;
+ }
+ return result;
+}
+
bool AbstractMetaFunction::isOperatorOverload(const QString& funcName)
{
if (isConversionOperator(funcName))
@@ -1159,8 +1239,8 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const
d << " throw(...)";
break;
}
- if (m_generateExceptionHandling)
- d << "[generate-exception-handling]";
+ if (m_exceptionHandlingModification != TypeSystem::ExceptionHandling::Unspecified)
+ d << " exeption-mod " << int(m_exceptionHandlingModification);
d << '(';
for (int i = 0, count = m_arguments.size(); i < count; ++i) {
if (i)
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index 1ab3049b2..074adbe00 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -851,8 +851,7 @@ public:
ExceptionSpecification exceptionSpecification() const;
void setExceptionSpecification(ExceptionSpecification e);
- bool generateExceptionHandling() const { return m_generateExceptionHandling; }
- void setGenerateExceptionHandling(bool g) { m_generateExceptionHandling = g; }
+ bool generateExceptionHandling() const;
bool isConversionOperator() const
{
@@ -1096,6 +1095,12 @@ public:
static AbstractMetaFunction *
find(const AbstractMetaFunctionList &haystack, const QString &needle);
+ // for the meta builder only
+ void setAllowThreadModification(TypeSystem::AllowThread am)
+ { m_allowThreadModification = am; }
+ void setExceptionHandlingModification(TypeSystem::ExceptionHandling em)
+ { m_exceptionHandlingModification = em; }
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebugVerbose(QDebug &d) const;
#endif
@@ -1123,9 +1128,9 @@ private:
uint m_explicit : 1;
uint m_pointerOperator : 1;
uint m_isCallOperator : 1;
- uint m_generateExceptionHandling: 1;
- mutable int m_cachedAllowThread = -1;
ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
+ TypeSystem::AllowThread m_allowThreadModification = TypeSystem::AllowThread::Unspecified;
+ TypeSystem::ExceptionHandling m_exceptionHandlingModification = TypeSystem::ExceptionHandling::Unspecified;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult)
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
index c3180ae88..ce66f77fe 100644
--- a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
@@ -11,7 +11,7 @@ typesystem
.. code-block:: xml
- <typesystem package="..." default-superclass="..." exception-handling="...">
+ <typesystem package="..." default-superclass="..." allow-thread="..." exception-handling="...">
</typesystem>
The **package** attribute is a string describing the package to be used,
@@ -19,8 +19,9 @@ typesystem
The *optional* **default-superclass** attribute is the canonical C++ base class
name of all objects, e.g., "object".
- The *optional* **exception-handling** attribute specifies the default exception
- handling mode of all objects (see :ref:`modify-function`).
+ The *optional* attributes **allow-thread** and **exception-handling**
+ specify the default handling for the corresponding function modification
+ (see :ref:`modify-function`).
load-typesystem
^^^^^^^^^^^^^^^
@@ -219,6 +220,7 @@ value-type
<typesystem>
<value-type name="..." since="..."
copyable="yes | no"
+ allow-thread="..."
exception-handling="..."
hash-function="..."
stream="yes | no"
@@ -247,8 +249,9 @@ value-type
The **revision** attribute can be used to specify a revision for each type, easing the
production of ABI compatible bindings.
- The *optional* **exception-handling** attribute specifies the default exception
- handling mode of all functions (see :ref:`modify-function`).
+ The *optional* attributes **allow-thread** and **exception-handling**
+ specify the default handling for the corresponding function modification
+ (see :ref:`modify-function`).
.. _object-type:
@@ -265,6 +268,7 @@ object-type
<object-type name="..."
since="..."
copyable="yes | no"
+ allow-thread="..."
exception-handling="..."
hash-function="..."
stream="yes | no"
@@ -286,8 +290,9 @@ object-type
The **revision** attribute can be used to specify a revision for each type, easing the
production of ABI compatible bindings.
- The *optional* **exception-handling** attribute specifies the default exception
- handling mode of all functions (see :ref:`modify-function`).
+ The *optional* attributes **allow-thread** and **exception-handling**
+ specify the default handling for the corresponding function modification
+ (see :ref:`modify-function`).
interface-type
^^^^^^^^^^^^^^
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
index af24689fe..922f1c23f 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
@@ -222,6 +222,8 @@ void TestModifyFunction::testWithApiVersion()
QVERIFY(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0) != TypeSystem::CppOwnership);
}
+// Modifications on class/typesystem level are tested below
+// in testScopedModifications().
void TestModifyFunction::testAllowThread()
{
const char cppCode[] =R"CPP(\
@@ -315,23 +317,130 @@ void TestModifyFunction::testGlobalFunctionModification()
QCOMPARE(arg->defaultValueExpression(), QLatin1String("A()"));
}
-void TestModifyFunction::testExceptionSpecification()
+// Tests modifications of exception handling and allow-thread
+// on various levels.
+void TestModifyFunction::testScopedModifications_data()
{
- const char cppCode[] = R"CPP(
-struct A {
+ QTest::addColumn<QByteArray>("cppCode");
+ QTest::addColumn<QByteArray>("xmlCode");
+ QTest::addColumn<bool>("expectedGenerateUnspecified");
+ QTest::addColumn<bool>("expectedGenerateNonThrowing");
+ QTest::addColumn<bool>("expectedGenerateThrowing");
+ QTest::addColumn<bool>("expectedAllowThread");
+
+ const QByteArray cppCode = R"CPP(
+struct Base {
+};
+
+struct A : public Base {
void unspecified();
void nonThrowing() noexcept;
void throwing() throw(int);
};
)CPP";
- const char xmlCode[] = R"XML(
-<typesystem package="Foo">
+
+ // Default: Off
+ QTest::newRow("none")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package= 'Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << false << false << false // exception
+ << true; // allowthread
+
+ // Modify one function
+ QTest::newRow("modify-function1")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
<primitive-type name='int'/>
+ <object-type name='Base'/>
<object-type name='A'>
<modify-function signature='throwing()' exception-handling='auto-on'/>
</object-type>
-</typesystem>)XML";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+</typesystem>)XML")
+ << false << false << true // exception
+ << true; // allowthread
+
+ // Flip defaults by modifying functions
+ QTest::newRow("modify-function2")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'>
+ <modify-function signature='unspecified()' exception-handling='auto-on'/>
+ <modify-function signature='throwing()' exception-handling='off'/>
+ </object-type>
+</typesystem>)XML")
+ << true << false << false // exception
+ << true; // allowthread
+
+ // Activate on type system level
+ QTest::newRow("typesystem-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo' exception-handling='auto-on' allow-thread='no'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Activate on class level
+ QTest::newRow("class-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A' exception-handling='auto-on' allow-thread='no'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Activate on base class level
+ QTest::newRow("baseclass-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base' exception-handling='auto-on' allow-thread='no'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Override value on class level
+ QTest::newRow("override-class-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A' exception-handling='auto-on'>
+ <modify-function signature='throwing()' exception-handling='no'/>
+ </object-type>
+</typesystem>)XML")
+ << true << false << false // exception
+ << true; // allowthread
+}
+
+void TestModifyFunction::testScopedModifications()
+{
+ QFETCH(QByteArray, cppCode);
+ QFETCH(QByteArray, xmlCode);
+ QFETCH(bool, expectedGenerateUnspecified);
+ QFETCH(bool, expectedGenerateNonThrowing);
+ QFETCH(bool, expectedGenerateThrowing);
+ QFETCH(bool, expectedAllowThread);
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode.constData(), xmlCode.constData(), false));
QVERIFY(!builder.isNull());
const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
@@ -340,17 +449,18 @@ struct A {
const AbstractMetaFunction *f = classA->findFunction(QStringLiteral("unspecified"));
QVERIFY(f);
QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown);
- QVERIFY(!f->generateExceptionHandling());
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateUnspecified);
+ QCOMPARE(f->allowThread(), expectedAllowThread);
f = classA->findFunction(QStringLiteral("nonThrowing"));
QVERIFY(f);
QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept);
- QVERIFY(!f->generateExceptionHandling());
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateNonThrowing);
f = classA->findFunction(QStringLiteral("throwing"));
QVERIFY(f);
QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws);
- QVERIFY(f->generateExceptionHandling());
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateThrowing);
}
QTEST_APPLESS_MAIN(TestModifyFunction)
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
index 494f31991..375111e03 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
@@ -42,7 +42,8 @@ class TestModifyFunction : public QObject
void testRenameArgument();
void invalidateAfterUse();
void testGlobalFunctionModification();
- void testExceptionSpecification();
+ void testScopedModifications_data();
+ void testScopedModifications();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index ff4f74d8c..204253777 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -1281,6 +1281,7 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
bool generate = true;
ctype->setCopyable(ComplexTypeEntry::Unknown);
auto exceptionHandling = m_exceptionHandling;
+ auto allowThread = m_allowThread;
QString package = m_defaultPackage;
for (int i = attributes->size() - 1; i >= 0; --i) {
@@ -1316,6 +1317,15 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
qCWarning(lcShiboken, "%s",
qPrintable(msgInvalidAttributeValue(attribute)));
}
+ } else if (name == allowThreadAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = allowThreadFromAttribute(attribute.value());
+ if (v != TypeSystem::AllowThread::Unspecified) {
+ allowThread = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
} else if (name == QLatin1String("held-type")) {
qCWarning(lcShiboken, "%s",
qPrintable(msgUnimplementedAttributeWarning(reader, name)));
@@ -1337,6 +1347,8 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
ctype->setExceptionHandling(exceptionHandling);
+ if (allowThread != TypeSystem::AllowThread::Unspecified)
+ ctype->setAllowThread(allowThread);
// The generator code relies on container's package being empty.
if (ctype->type() != TypeEntry::ContainerType)
@@ -1483,6 +1495,15 @@ TypeSystemTypeEntry *Handler::parseRootElement(const QXmlStreamReader &,
qCWarning(lcShiboken, "%s",
qPrintable(msgInvalidAttributeValue(attribute)));
}
+ } else if (name == allowThreadAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = allowThreadFromAttribute(attribute.value());
+ if (v != TypeSystem::AllowThread::Unspecified) {
+ m_allowThread = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
}
}
diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h
index b0144923a..36a75c599 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.h
+++ b/sources/shiboken2/ApiExtractor/typesystem.h
@@ -1395,6 +1395,9 @@ public:
TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; }
void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; }
+ TypeSystem::AllowThread allowThread() const { return m_allowThread; }
+ void setAllowThread(TypeSystem::AllowThread allowThread) { m_allowThread = allowThread; }
+
QString defaultConstructor() const;
void setDefaultConstructor(const QString& defaultConstructor);
bool hasDefaultConstructor() const;
@@ -1433,6 +1436,7 @@ private:
const ComplexTypeEntry* m_baseContainerType = nullptr;
// For class functions
TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified;
};
class TypedefEntry : public ComplexTypeEntry
diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h
index a617110d6..a119b2a97 100644
--- a/sources/shiboken2/ApiExtractor/typesystem_p.h
+++ b/sources/shiboken2/ApiExtractor/typesystem_p.h
@@ -246,6 +246,7 @@ private:
QString m_defaultPackage;
QString m_defaultSuperclass;
TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified;
QString m_error;
const TypeEntry::CodeGeneration m_generate;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 3ce07cf93..f2112e34f 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -5535,6 +5535,8 @@ bool CppGenerator::finishGeneration()
// cleanup staticMetaObject attribute
if (usePySideExtensions()) {
s << "void cleanTypesAttributes(void) {" << endl;
+ s << INDENT << "if (PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03060000)" << endl;
+ s << INDENT << " return; // testbinding crashes in Python 3.5 when hasattr touches types!" << endl;
s << INDENT << "for (int i = 0, imax = SBK_" << moduleName() << "_IDX_COUNT; i < imax; i++) {" << endl;
{
Indentation indentation(INDENT);
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index ca5dab54e..ec0d466f7 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -2683,7 +2683,7 @@ void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const
s << " = " << defaultCtor;
return;
}
- if (isCppPrimitive(type))
+ if (isCppPrimitive(type) || type->isSmartPointer())
return;
const auto ctor = minimalConstructor(type);
if (ctor.isValid()) {
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index d6c26ac79..61a097771 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -169,7 +169,7 @@ GetClassOfFunc(PyObject *ob)
{
if (PyType_Check(ob))
return ob;
- if (Py_TYPE(ob) == &PyCFunction_Type)
+ 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);
@@ -703,7 +703,7 @@ get_signature(PyObject *self, PyObject *args)
if (Py_TYPE(ob) == PepFunction_TypePtr)
Py_RETURN_NONE;
- if (Py_TYPE(ob) == &PyCFunction_Type)
+ 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);
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index b37d0c941..952d31994 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -70,6 +70,10 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py"
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.py" COPYONLY)
if (PYTHON_VERSION_MAJOR EQUAL 3)
+ if (PYTHON_VERSION_MINOR EQUAL 5)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/contextlib36.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/contextlib36.py" COPYONLY)
+ endif()
else()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/backport_inspect.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/backport_inspect.py" COPYONLY)
diff --git a/sources/shiboken2/shibokenmodule/support/signature/contextlib36.py b/sources/shiboken2/shibokenmodule/support/signature/contextlib36.py
new file mode 100644
index 000000000..d416eef27
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/contextlib36.py
@@ -0,0 +1,472 @@
+# This Python file uses the following encoding: utf-8
+# It has been edited by fix-complaints.py .
+
+#############################################################################
+##
+## Copyright (C) 2019 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$
+##
+#############################################################################
+
+"""
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
+"""
+
+"""Utilities for with-statement contexts. See PEP 343."""
+import abc
+import sys
+import _collections_abc
+from collections import deque
+from functools import wraps
+
+__all__ = ["contextmanager", "closing", "AbstractContextManager",
+ "ContextDecorator", "ExitStack", "redirect_stdout",
+ "redirect_stderr", "suppress"]
+
+
+class AbstractContextManager(abc.ABC):
+
+ """An abstract base class for context managers."""
+
+ def __enter__(self):
+ """Return `self` upon entering the runtime context."""
+ return self
+
+ @abc.abstractmethod
+ def __exit__(self, exc_type, exc_value, traceback):
+ """Raise any exception triggered within the runtime context."""
+ return None
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is AbstractContextManager:
+ return _collections_abc._check_methods(C, "__enter__", "__exit__")
+ return NotImplemented
+
+
+class ContextDecorator(object):
+ "A base class or mixin that enables context managers to work as decorators."
+
+ def _recreate_cm(self):
+ """Return a recreated instance of self.
+
+ Allows an otherwise one-shot context manager like
+ _GeneratorContextManager to support use as
+ a decorator via implicit recreation.
+
+ This is a private interface just for _GeneratorContextManager.
+ See issue #11647 for details.
+ """
+ return self
+
+ def __call__(self, func):
+ @wraps(func)
+ def inner(*args, **kwds):
+ with self._recreate_cm():
+ return func(*args, **kwds)
+ return inner
+
+
+class _GeneratorContextManager(ContextDecorator, AbstractContextManager):
+ """Helper for @contextmanager decorator."""
+
+ def __init__(self, func, args, kwds):
+ self.gen = func(*args, **kwds)
+ self.func, self.args, self.kwds = func, args, kwds
+ # Issue 19330: ensure context manager instances have good docstrings
+ doc = getattr(func, "__doc__", None)
+ if doc is None:
+ doc = type(self).__doc__
+ self.__doc__ = doc
+ # Unfortunately, this still doesn't provide good help output when
+ # inspecting the created context manager instances, since pydoc
+ # currently bypasses the instance docstring and shows the docstring
+ # for the class instead.
+ # See http://bugs.python.org/issue19404 for more details.
+
+ def _recreate_cm(self):
+ # _GCM instances are one-shot context managers, so the
+ # CM must be recreated each time a decorated function is
+ # called
+ return self.__class__(self.func, self.args, self.kwds)
+
+ def __enter__(self):
+ try:
+ return next(self.gen)
+ except StopIteration:
+ raise RuntimeError("generator didn't yield") from None
+
+ def __exit__(self, type, value, traceback):
+ if type is None:
+ try:
+ next(self.gen)
+ except StopIteration:
+ return False
+ else:
+ raise RuntimeError("generator didn't stop")
+ else:
+ if value is None:
+ # Need to force instantiation so we can reliably
+ # tell if we get the same exception back
+ value = type()
+ try:
+ self.gen.throw(type, value, traceback)
+ except StopIteration as exc:
+ # Suppress StopIteration *unless* it's the same exception that
+ # was passed to throw(). This prevents a StopIteration
+ # raised inside the "with" statement from being suppressed.
+ return exc is not value
+ except RuntimeError as exc:
+ # Don't re-raise the passed in exception. (issue27122)
+ if exc is value:
+ return False
+ # Likewise, avoid suppressing if a StopIteration exception
+ # was passed to throw() and later wrapped into a RuntimeError
+ # (see PEP 479).
+ if type is StopIteration and exc.__cause__ is value:
+ return False
+ raise
+ except:
+ # only re-raise if it's *not* the exception that was
+ # passed to throw(), because __exit__() must not raise
+ # an exception unless __exit__() itself failed. But throw()
+ # has to raise the exception to signal propagation, so this
+ # fixes the impedance mismatch between the throw() protocol
+ # and the __exit__() protocol.
+ #
+ if sys.exc_info()[1] is value:
+ return False
+ raise
+ raise RuntimeError("generator didn't stop after throw()")
+
+
+def contextmanager(func):
+ """@contextmanager decorator.
+
+ Typical usage:
+
+ @contextmanager
+ def some_generator(<arguments>):
+ <setup>
+ try:
+ yield <value>
+ finally:
+ <cleanup>
+
+ This makes this:
+
+ with some_generator(<arguments>) as <variable>:
+ <body>
+
+ equivalent to this:
+
+ <setup>
+ try:
+ <variable> = <value>
+ <body>
+ finally:
+ <cleanup>
+
+ """
+ @wraps(func)
+ def helper(*args, **kwds):
+ return _GeneratorContextManager(func, args, kwds)
+ return helper
+
+
+class closing(AbstractContextManager):
+ """Context to automatically close something at the end of a block.
+
+ Code like this:
+
+ with closing(<module>.open(<arguments>)) as f:
+ <block>
+
+ is equivalent to this:
+
+ f = <module>.open(<arguments>)
+ try:
+ <block>
+ finally:
+ f.close()
+
+ """
+ def __init__(self, thing):
+ self.thing = thing
+ def __enter__(self):
+ return self.thing
+ def __exit__(self, *exc_info):
+ self.thing.close()
+
+
+class _RedirectStream(AbstractContextManager):
+
+ _stream = None
+
+ def __init__(self, new_target):
+ self._new_target = new_target
+ # We use a list of old targets to make this CM re-entrant
+ self._old_targets = []
+
+ def __enter__(self):
+ self._old_targets.append(getattr(sys, self._stream))
+ setattr(sys, self._stream, self._new_target)
+ return self._new_target
+
+ def __exit__(self, exctype, excinst, exctb):
+ setattr(sys, self._stream, self._old_targets.pop())
+
+
+class redirect_stdout(_RedirectStream):
+ """Context manager for temporarily redirecting stdout to another file.
+
+ # How to send help() to stderr
+ with redirect_stdout(sys.stderr):
+ help(dir)
+
+ # How to write help() to a file
+ with open('help.txt', 'w') as f:
+ with redirect_stdout(f):
+ help(pow)
+ """
+
+ _stream = "stdout"
+
+
+class redirect_stderr(_RedirectStream):
+ """Context manager for temporarily redirecting stderr to another file."""
+
+ _stream = "stderr"
+
+
+class suppress(AbstractContextManager):
+ """Context manager to suppress specified exceptions
+
+ After the exception is suppressed, execution proceeds with the next
+ statement following the with statement.
+
+ with suppress(FileNotFoundError):
+ os.remove(somefile)
+ # Execution still resumes here if the file was already removed
+ """
+
+ def __init__(self, *exceptions):
+ self._exceptions = exceptions
+
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exctype, excinst, exctb):
+ # Unlike isinstance and issubclass, CPython exception handling
+ # currently only looks at the concrete type hierarchy (ignoring
+ # the instance and subclass checking hooks). While Guido considers
+ # that a bug rather than a feature, it's a fairly hard one to fix
+ # due to various internal implementation details. suppress provides
+ # the simpler issubclass based semantics, rather than trying to
+ # exactly reproduce the limitations of the CPython interpreter.
+ #
+ # See http://bugs.python.org/issue12029 for more details
+ return exctype is not None and issubclass(exctype, self._exceptions)
+
+
+# Inspired by discussions on http://bugs.python.org/issue13585
+class ExitStack(AbstractContextManager):
+ """Context manager for dynamic management of a stack of exit callbacks
+
+ For example:
+
+ with ExitStack() as stack:
+ files = [stack.enter_context(open(fname)) for fname in filenames]
+ # All opened files will automatically be closed at the end of
+ # the with statement, even if attempts to open files later
+ # in the list raise an exception
+
+ """
+ def __init__(self):
+ self._exit_callbacks = deque()
+
+ def pop_all(self):
+ """Preserve the context stack by transferring it to a new instance"""
+ new_stack = type(self)()
+ new_stack._exit_callbacks = self._exit_callbacks
+ self._exit_callbacks = deque()
+ return new_stack
+
+ def _push_cm_exit(self, cm, cm_exit):
+ """Helper to correctly register callbacks to __exit__ methods"""
+ def _exit_wrapper(*exc_details):
+ return cm_exit(cm, *exc_details)
+ _exit_wrapper.__self__ = cm
+ self.push(_exit_wrapper)
+
+ def push(self, exit):
+ """Registers a callback with the standard __exit__ method signature
+
+ Can suppress exceptions the same way __exit__ methods can.
+
+ Also accepts any object with an __exit__ method (registering a call
+ to the method instead of the object itself)
+ """
+ # We use an unbound method rather than a bound method to follow
+ # the standard lookup behavior for special methods
+ _cb_type = type(exit)
+ try:
+ exit_method = _cb_type.__exit__
+ except AttributeError:
+ # Not a context manager, so assume its a callable
+ self._exit_callbacks.append(exit)
+ else:
+ self._push_cm_exit(exit, exit_method)
+ return exit # Allow use as a decorator
+
+ def callback(self, callback, *args, **kwds):
+ """Registers an arbitrary callback and arguments.
+
+ Cannot suppress exceptions.
+ """
+ def _exit_wrapper(exc_type, exc, tb):
+ callback(*args, **kwds)
+ # We changed the signature, so using @wraps is not appropriate, but
+ # setting __wrapped__ may still help with introspection
+ _exit_wrapper.__wrapped__ = callback
+ self.push(_exit_wrapper)
+ return callback # Allow use as a decorator
+
+ def enter_context(self, cm):
+ """Enters the supplied context manager
+
+ If successful, also pushes its __exit__ method as a callback and
+ returns the result of the __enter__ method.
+ """
+ # We look up the special methods on the type to match the with statement
+ _cm_type = type(cm)
+ _exit = _cm_type.__exit__
+ result = _cm_type.__enter__(cm)
+ self._push_cm_exit(cm, _exit)
+ return result
+
+ def close(self):
+ """Immediately unwind the context stack"""
+ self.__exit__(None, None, None)
+
+ def __exit__(self, *exc_details):
+ received_exc = exc_details[0] is not None
+
+ # We manipulate the exception state so it behaves as though
+ # we were actually nesting multiple with statements
+ frame_exc = sys.exc_info()[1]
+ def _fix_exception_context(new_exc, old_exc):
+ # Context may not be correct, so find the end of the chain
+ while 1:
+ exc_context = new_exc.__context__
+ if exc_context is old_exc:
+ # Context is already set correctly (see issue 20317)
+ return
+ if exc_context is None or exc_context is frame_exc:
+ break
+ new_exc = exc_context
+ # Change the end of the chain to point to the exception
+ # we expect it to reference
+ new_exc.__context__ = old_exc
+
+ # Callbacks are invoked in LIFO order to match the behavior of
+ # nested context managers
+ suppressed_exc = False
+ pending_raise = False
+ while self._exit_callbacks:
+ cb = self._exit_callbacks.pop()
+ try:
+ if cb(*exc_details):
+ suppressed_exc = True
+ pending_raise = False
+ exc_details = (None, None, None)
+ except:
+ new_exc_details = sys.exc_info()
+ # simulate the stack of exceptions by setting the context
+ _fix_exception_context(new_exc_details[1], exc_details[1])
+ pending_raise = True
+ exc_details = new_exc_details
+ if pending_raise:
+ try:
+ # bare "raise exc_details[1]" replaces our carefully
+ # set-up context
+ fixed_ctx = exc_details[1].__context__
+ raise exc_details[1]
+ except BaseException:
+ exc_details[1].__context__ = fixed_ctx
+ raise
+ return received_exc and suppressed_exc
diff --git a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py b/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py
index e078ef1ab..ef18beb67 100644
--- a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py
+++ b/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2018 The Qt Company Ltd.
+## Copyright (C) 2019 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -49,7 +49,7 @@ you are changing messages (what I did, of course :-) .
import os
-patched_modules = "backport_inspect typing27"
+patched_modules = "backport_inspect typing27 contextlib36"
offending_words = {
"behavio""ur": "behavior",
diff --git a/sources/shiboken2/shibokenmodule/support/signature/loader.py b/sources/shiboken2/shibokenmodule/support/signature/loader.py
index 458759845..749229c3b 100644
--- a/sources/shiboken2/shibokenmodule/support/signature/loader.py
+++ b/sources/shiboken2/shibokenmodule/support/signature/loader.py
@@ -158,6 +158,10 @@ with ensure_import_support():
import typing
import inspect
inspect.formatannotation = formatannotation
+ if sys.version_info[:2] == (3, 5):
+ # PYSIDE-953: Use a newer contextlib.
+ from support.signature import contextlib36 as contextlib
+ sys.modules["contextlib"] = contextlib
else:
import inspect
namespace = inspect.__dict__
diff --git a/sources/shiboken2/tests/libsmart/smart.cpp b/sources/shiboken2/tests/libsmart/smart.cpp
index 4132c2fc8..8d85d67a1 100644
--- a/sources/shiboken2/tests/libsmart/smart.cpp
+++ b/sources/shiboken2/tests/libsmart/smart.cpp
@@ -62,6 +62,15 @@ SharedPtr<Obj> Obj::giveSharedPtrToObj()
return o;
}
+std::vector<SharedPtr<Obj> > Obj::giveSharedPtrToObjList(int size)
+{
+ std::vector<SharedPtr<Obj> > r;
+ for (int i=0; i < size; i++)
+ r.push_back(giveSharedPtrToObj());
+ return r;
+}
+
+
SharedPtr<Integer> Obj::giveSharedPtrToInteger()
{
SharedPtr<Integer> o(new Integer);
diff --git a/sources/shiboken2/tests/libsmart/smart.h b/sources/shiboken2/tests/libsmart/smart.h
index 502187a11..2e3c96406 100644
--- a/sources/shiboken2/tests/libsmart/smart.h
+++ b/sources/shiboken2/tests/libsmart/smart.h
@@ -207,6 +207,7 @@ public:
void printObj();
Integer takeInteger(Integer val);
SharedPtr<Obj> giveSharedPtrToObj();
+ std::vector<SharedPtr<Obj> > giveSharedPtrToObjList(int size);
SharedPtr<Integer> giveSharedPtrToInteger();
SharedPtr<Smart::Integer2> giveSharedPtrToInteger2();
int takeSharedPtrToObj(SharedPtr<Obj> pObj);
diff --git a/sources/shiboken2/tests/smartbinding/smart_pointer_test.py b/sources/shiboken2/tests/smartbinding/smart_pointer_test.py
index 62bfc0500..e07856e61 100644
--- a/sources/shiboken2/tests/smartbinding/smart_pointer_test.py
+++ b/sources/shiboken2/tests/smartbinding/smart_pointer_test.py
@@ -156,5 +156,24 @@ class SmartPointerTests(unittest.TestCase):
integer = ptrToInteger.data()
self.assertTrue(integer)
+ def testListOfSmartPointers(self):
+ # Create the main object
+ o = Obj()
+
+ # Create a list of shared objects
+ ptrToObjList = o.giveSharedPtrToObjList(10)
+ self.assertEqual(len(ptrToObjList), 10)
+ self.assertEqual(objCount(), 11)
+
+ # Remove one from the list
+ ptrToObjList.pop()
+ self.assertEqual(len(ptrToObjList), 9)
+ self.assertEqual(objCount(), 10)
+
+ # clear and delete all objects in the list
+ ptrToObjList.clear()
+ self.assertEqual(len(ptrToObjList), 0)
+ self.assertEqual(objCount(), 1)
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken2/tests/smartbinding/typesystem_smart.xml b/sources/shiboken2/tests/smartbinding/typesystem_smart.xml
index b2deb18cb..aea1c2f73 100644
--- a/sources/shiboken2/tests/smartbinding/typesystem_smart.xml
+++ b/sources/shiboken2/tests/smartbinding/typesystem_smart.xml
@@ -5,6 +5,36 @@
<primitive-type name="float" />
<primitive-type name="bool" />
+ <template name="cpplist_to_pylist_convertion">
+ PyObject *%out = PyList_New(int(%in.size()));
+ int idx = 0;
+ for (const auto &amp;cppItem : %in)
+ PyList_SET_ITEM(%out, idx++, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+ return %out;
+ </template>
+ <template name="pyseq_to_cpplist_convertion">
+ Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0));
+ for (int i = 0, size = PySequence_Fast_GET_SIZE(seq.object()); i &lt; size; ++i) {
+ PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i);
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ %out.push_back(cppItem);
+ }
+ </template>
+ <container-type name="std::vector" type="list">
+ <include file-name="list" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name="cpplist_to_pylist_convertion"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="pyseq_to_cpplist_convertion"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
+
+
<!-- Used in tests to check what C++ objects are allocated. -->
<object-type name="Registry" />