Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside-tools/pyside_tool.py27
-rw-r--r--sources/pyside-tools/requirements-android.txt1
-rw-r--r--sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp99
-rw-r--r--sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h10
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml10
-rw-r--r--sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml5
-rw-r--r--sources/pyside6/PySide6/QtXml/typesystem_xml.xml4
-rw-r--r--sources/pyside6/PySide6/glue/qtcore.cpp57
-rw-r--r--sources/pyside6/libpyside/CMakeLists.txt2
-rw-r--r--sources/pyside6/libpyside/pysidemetafunction.cpp8
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp25
-rw-r--r--sources/pyside6/libpyside/pysidevariantutils.cpp212
-rw-r--r--sources/pyside6/libpyside/pysidevariantutils.h37
-rw-r--r--sources/pyside6/libpyside/signalmanager.cpp71
-rw-r--r--sources/pyside6/libpyside/signalmanager.h8
-rw-r--r--sources/pyside6/tests/QtCore/deepcopy_test.py6
-rw-r--r--sources/pyside6/tests/QtCore/qobject_property_test.py34
-rw-r--r--sources/pyside6/tests/QtCore/repr_test.py6
-rw-r--r--sources/pyside6/tests/QtWidgets/bug_433.py2
-rw-r--r--sources/pyside6/tests/QtWidgets/bug_919.py9
-rw-r--r--sources/pyside6/tests/QtWidgets/qapp_issue_585.py10
-rw-r--r--sources/pyside6/tests/QtWidgets/qmenu_test.py18
-rw-r--r--sources/pyside6/tests/QtXml/qdomdocument_test.py23
-rw-r--r--sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py2
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp20
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractor.cpp1
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp20
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp63
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.h8
-rw-r--r--sources/shiboken6/ApiExtractor/customconversion.cpp3
-rw-r--r--sources/shiboken6/ApiExtractor/parser/typeinfo.cpp38
-rw-r--r--sources/shiboken6/ApiExtractor/parser/typeinfo.h5
-rw-r--r--sources/shiboken6/ApiExtractor/smartpointertypeentry.h5
-rw-r--r--sources/shiboken6/ApiExtractor/typesystem.cpp19
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemparser.cpp8
-rw-r--r--sources/shiboken6/cmake/ShibokenHelpers.cmake25
-rw-r--r--sources/shiboken6/doc/typesystem_conversionrule.rst15
-rw-r--r--sources/shiboken6/doc/typesystem_converters.rst36
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst6
-rw-r--r--sources/shiboken6/doc/typesystem_variables.rst2
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp44
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.h8
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp11
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.cpp6
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp76
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.h5
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp15
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.cpp13
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py10
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py1
-rw-r--r--sources/shiboken6/tests/libsample/bucket.cpp14
-rw-r--r--sources/shiboken6/tests/libsample/bucket.h6
-rw-r--r--sources/shiboken6/tests/libsample/samplenamespace.cpp9
-rw-r--r--sources/shiboken6/tests/libsample/samplenamespace.h4
-rw-r--r--sources/shiboken6/tests/samplebinding/sample_test.py7
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml19
57 files changed, 832 insertions, 380 deletions
diff --git a/sources/pyside-tools/pyside_tool.py b/sources/pyside-tools/pyside_tool.py
index 887f2bdda..5c009859d 100644
--- a/sources/pyside-tools/pyside_tool.py
+++ b/sources/pyside-tools/pyside_tool.py
@@ -198,6 +198,18 @@ def metaobjectdump():
pyside_script_wrapper("metaobjectdump.py")
+def _check_requirements(requirements_file):
+ """Check if all required packages are installed."""
+ missing_packages = []
+ with open(requirements_file, 'r', encoding='UTF-8') as file:
+ for line in file:
+ # versions
+ package = line.strip().split('==')[0]
+ if not importlib.util.find_spec(package):
+ missing_packages.append(line.strip())
+ return missing_packages
+
+
def project():
pyside_script_wrapper("project.py")
@@ -220,12 +232,15 @@ def android_deploy():
file=sys.stderr)
else:
android_requirements_file = Path(__file__).parent / "requirements-android.txt"
- with open(android_requirements_file, 'r', encoding='UTF-8') as file:
- while line := file.readline():
- dependent_package = line.rstrip()
- if not bool(importlib.util.find_spec(dependent_package)):
- command = [sys.executable, "-m", "pip", "install", dependent_package]
- subprocess.run(command)
+ if android_requirements_file.exists():
+ missing_packages = _check_requirements(android_requirements_file)
+ if missing_packages:
+ print("The following packages are required but not installed:")
+ for package in missing_packages:
+ print(f" - {package}")
+ print("Please install them using:")
+ print(f" pip install -r {android_requirements_file}")
+ sys.exit(1)
pyside_script_wrapper("android_deploy.py")
diff --git a/sources/pyside-tools/requirements-android.txt b/sources/pyside-tools/requirements-android.txt
index 9ed5d8427..1a247f6c1 100644
--- a/sources/pyside-tools/requirements-android.txt
+++ b/sources/pyside-tools/requirements-android.txt
@@ -1,3 +1,4 @@
jinja2
pkginfo
tqdm
+packaging==24.1
diff --git a/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp b/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
index e58d54998..9b2b40e82 100644
--- a/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
+++ b/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
@@ -19,105 +19,6 @@
#include <QtCore/QObject>
#include <QtCore/QRegularExpression>
#include <QtCore/QStack>
-#include <QtCore/QVariant>
-
-// Helpers for QVariant conversion
-
-QMetaType QVariant_resolveMetaType(PyTypeObject *type)
-{
- if (!PyObject_TypeCheck(type, SbkObjectType_TypeF()))
- return {};
- const char *typeName = Shiboken::ObjectType::getOriginalName(type);
- if (!typeName)
- return {};
- const bool valueType = '*' != typeName[qstrlen(typeName) - 1];
- // Do not convert user type of value
- if (valueType && Shiboken::ObjectType::isUserType(type))
- return {};
- QMetaType metaType = QMetaType::fromName(typeName);
- if (metaType.isValid())
- return metaType;
- // Do not resolve types to value type
- if (valueType)
- return {};
- // Find in base types. First check tp_bases, and only after check tp_base, because
- // tp_base does not always point to the first base class, but rather to the first
- // that has added any python fields or slots to its object layout.
- // See https://mail.python.org/pipermail/python-list/2009-January/520733.html
- if (type->tp_bases) {
- const auto size = PyTuple_Size(type->tp_bases);
- Py_ssize_t i = 0;
- // PYSIDE-1887, PYSIDE-86: Skip QObject base class of QGraphicsObject;
- // it needs to use always QGraphicsItem as a QVariant type for
- // QGraphicsItem::itemChange() to work.
- if (qstrcmp(typeName, "QGraphicsObject*") == 0)
- ++i;
- for ( ; i < size; ++i) {
- auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, i));
- const QMetaType derived = QVariant_resolveMetaType(baseType);
- if (derived.isValid())
- return derived;
- }
- } else if (type->tp_base) {
- return QVariant_resolveMetaType(type->tp_base);
- }
- return {};
-}
-
-QVariant QVariant_convertToValueList(PyObject *list)
-{
- if (PySequence_Size(list) < 0) {
- // clear the error if < 0 which means no length at all
- PyErr_Clear();
- return {};
- }
-
- Shiboken::AutoDecRef element(PySequence_GetItem(list, 0));
-
- auto *type = reinterpret_cast<PyTypeObject *>(element.object());
- QMetaType metaType = QVariant_resolveMetaType(type);
- if (!metaType.isValid())
- return {};
-
- const QByteArray listTypeName = QByteArrayLiteral("QList<") + metaType.name() + '>';
- metaType = QMetaType::fromName(listTypeName);
- if (!metaType.isValid())
- return {};
-
- Shiboken::Conversions::SpecificConverter converter(listTypeName);
- if (!converter) {
- qWarning("Type converter for: %s not registered.", listTypeName.constData());
- return {};
- }
-
- QVariant var(metaType);
- converter.toCpp(list, &var);
- return var;
-}
-
-bool QVariant_isStringList(PyObject *list)
-{
- if (!PySequence_Check(list)) {
- // If it is not a list or a derived list class
- // we assume that will not be a String list neither.
- return false;
- }
-
- if (PySequence_Size(list) < 0) {
- // clear the error if < 0 which means no length at all
- PyErr_Clear();
- return false;
- }
-
- Shiboken::AutoDecRef fast(PySequence_Fast(list, "Failed to convert QVariantList"));
- const Py_ssize_t size = PySequence_Size(fast.object());
- for (Py_ssize_t i = 0; i < size; ++i) {
- Shiboken::AutoDecRef item(PySequence_GetItem(fast.object(), i));
- if (PyUnicode_Check(item) == 0)
- return false;
- }
- return true;
-}
// Helpers for qAddPostRoutine
diff --git a/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h b/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
index 11e84b291..4c1867a1a 100644
--- a/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
+++ b/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
@@ -14,10 +14,8 @@
QT_FORWARD_DECLARE_CLASS(QGenericArgument)
QT_FORWARD_DECLARE_CLASS(QGenericReturnArgument)
-QT_FORWARD_DECLARE_CLASS(QMetaType)
QT_FORWARD_DECLARE_CLASS(QObject)
QT_FORWARD_DECLARE_CLASS(QRegularExpression)
-QT_FORWARD_DECLARE_CLASS(QVariant);
QT_BEGIN_NAMESPACE
namespace QtCoreHelper {
@@ -26,14 +24,6 @@ class QGenericReturnArgumentHolder;
}
QT_END_NAMESPACE
-// Helpers for QVariant conversion
-
-QMetaType QVariant_resolveMetaType(PyTypeObject *type);
-
-QVariant QVariant_convertToValueList(PyObject *list);
-
-bool QVariant_isStringList(PyObject *list);
-
// Helpers for qAddPostRoutine
namespace PySide {
void globalPostRoutineCallback();
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index 207844c56..c3130ccb2 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -16,6 +16,7 @@
<extra-includes>
<include file-name="pysidemetatype.h" location="global"/>
<include file-name="pysideutils.h" location="global"/> <!-- QString conversion -->
+ <include file-name="pysidevariantutils.h" location="global"/> <!-- QVariant conversion -->
<include file-name="signalmanager.h" location="global"/>
<include file-name="sbkerrors.h" location="global"/>
<!-- QtCoreHelper::QGenericReturnArgumentHolder -->
@@ -320,6 +321,7 @@
<extra-includes>
<include file-name="optional" location="global"/>
<include file-name="pysideqenum.h" location="global"/>
+ <include file-name="pysidevariantutils.h" location="global"/>
</extra-includes>
<conversion-rule>
<native-to-target file="../glue/qtcore.cpp" snippet="return-qvariant"/>
@@ -391,6 +393,9 @@
</object-type>
<primitive-type name="QJsonObject">
+ <extra-includes>
+ <include file-name="pysidevariantutils.h" location="global"/>
+ </extra-includes>
<conversion-rule>
<native-to-target file="../glue/qtcore.cpp" snippet="return-qjsonobject"/>
<target-to-native>
@@ -934,9 +939,12 @@
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-2"/>
</add-function>
<!-- PYSIDE-1735: Qt::TimeSpec is no more compatible with int -->
- <add-function signature="QDateTime(int@year@,int@month@,int@day@,int@h@,int@m@,int@s@,int@ms@,Qt::TimeSpec@spec@=Qt::LocalTime)">
+ <add-function signature="QDateTime(int@year@,int@month@,int@day@,int@h@,int@m@,int@s@,int@ms@,Qt::TimeSpec@spec@)">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-3"/>
</add-function>
+ <add-function signature="QDateTime(int@year@,int@month@,int@day@,int@h@,int@m@,int@s@,int@ms@,QTimeZone@spec@=QTimeZone::LocalTime)" since="6.5">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-4"/>
+ </add-function>
<add-function signature="__repr__" return-type="str">
<inject-code class="target" position="beginning">
<insert-template name="repr_code">
diff --git a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
index a15527c03..c6e93cfd7 100644
--- a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
@@ -1489,6 +1489,7 @@
<enum-type name="InputMode"/>
<modify-function signature="getInt(QWidget*,const QString&amp;,const QString&amp;,int,int,int,int,bool*,QFlags&lt;Qt::WindowType&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[int, bool]"/>
<modify-argument index="8">
<remove-default-expression/>
@@ -1500,6 +1501,7 @@
</modify-function>
<modify-function signature="getItem(QWidget*,const QString&amp;,const QString&amp;,const QStringList&amp;,int,bool,bool*,QFlags&lt;Qt::WindowType&gt;,QFlags&lt;Qt::InputMethodHint&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[str, bool]"/>
<modify-argument index="7">
<remove-default-expression/>
@@ -1511,6 +1513,7 @@
</modify-function>
<modify-function signature="getMultiLineText(QWidget*,const QString&amp;,const QString&amp;,const QString&amp;,bool*,QFlags&lt;Qt::WindowType&gt;,QFlags&lt;Qt::InputMethodHint&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[str, bool]"/>
<modify-argument index="5">
<remove-default-expression/>
@@ -1522,6 +1525,7 @@
</modify-function>
<modify-function signature="getText(QWidget*,const QString&amp;,const QString&amp;,QLineEdit::EchoMode,const QString&amp;,bool*,QFlags&lt;Qt::WindowType&gt;,QFlags&lt;Qt::InputMethodHint&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[str, bool]"/>
<modify-argument index="6">
<remove-default-expression/>
@@ -1533,6 +1537,7 @@
</modify-function>
<modify-function signature="getDouble(QWidget*,const QString&amp;,const QString&amp;,double,double,double,int,bool*,QFlags&lt;Qt::WindowType&gt;,double)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[float, bool]"/>
<modify-argument index="8">
<remove-default-expression/>
diff --git a/sources/pyside6/PySide6/QtXml/typesystem_xml.xml b/sources/pyside6/PySide6/QtXml/typesystem_xml.xml
index 089978b6d..93d3c1f56 100644
--- a/sources/pyside6/PySide6/QtXml/typesystem_xml.xml
+++ b/sources/pyside6/PySide6/QtXml/typesystem_xml.xml
@@ -20,7 +20,7 @@
<enum-type name="ParseOption" flags="ParseOptions" since="6.5"/>
<!-- will be replaced in inject code -->
- <value-type name="ParseResult"/>
+ <value-type name="ParseResult" operator-bool="yes"/>
<modify-function signature="setContent(const QByteArray&amp;,bool,QString*,int*,int*)">
<modify-argument index="3">
@@ -130,6 +130,8 @@
</modify-argument>
<inject-code class="target" position="beginning" file="../glue/qtxml.cpp" snippet="qdomdocument-setcontent" />
</modify-function>
+ <declare-function signature="setContent(const QByteArray&amp;@data@, QDomDocument::ParseOptions@options@=QDomDocument::ParseOption::Default)"
+ return-type="QDomDocument::ParseResult" since="6.8" />
</value-type>
<value-type name="QDomDocumentFragment"/>
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
index 78a25f0a1..cd1462676 100644
--- a/sources/pyside6/PySide6/glue/qtcore.cpp
+++ b/sources/pyside6/PySide6/glue/qtcore.cpp
@@ -225,49 +225,6 @@ return %out;
// @snippet conversion-qmetatype-pytypeobject
// @snippet qvariant-conversion
-static QVariant QVariant_convertToVariantMap(PyObject *map)
-{
- Py_ssize_t pos = 0;
- Shiboken::AutoDecRef keys(PyDict_Keys(map));
- if (!QVariant_isStringList(keys))
- return {};
- PyObject *key{};
- PyObject *value{};
- QMap<QString,QVariant> ret;
- while (PyDict_Next(map, &pos, &key, &value)) {
- QString cppKey = %CONVERTTOCPP[QString](key);
- QVariant cppValue = %CONVERTTOCPP[QVariant](value);
- ret.insert(cppKey, cppValue);
- }
- return QVariant(ret);
-}
-static QVariant QVariant_convertToVariantList(PyObject *list)
-{
- if (QVariant_isStringList(list)) {
- QList<QString > lst = %CONVERTTOCPP[QList<QString>](list);
- return QVariant(QStringList(lst));
- }
- QVariant valueList = QVariant_convertToValueList(list);
- if (valueList.isValid())
- return valueList;
-
- if (PySequence_Size(list) < 0) {
- // clear the error if < 0 which means no length at all
- PyErr_Clear();
- return {};
- }
-
- QList<QVariant> lst;
- Shiboken::AutoDecRef fast(PySequence_Fast(list, "Failed to convert QVariantList"));
- const Py_ssize_t size = PySequence_Size(fast.object());
- for (Py_ssize_t i = 0; i < size; ++i) {
- Shiboken::AutoDecRef pyItem(PySequence_GetItem(fast.object(), i));
- QVariant item = %CONVERTTOCPP[QVariant](pyItem);
- lst.append(item);
- }
- return QVariant(lst);
-}
-
using SpecificConverter = Shiboken::Conversions::SpecificConverter;
static std::optional<SpecificConverter> converterForQtType(const char *typeNameC)
@@ -535,6 +492,12 @@ QTime time(%4, %5, %6, %7);
Shiboken::Warnings::warnDeprecated("QDateTime", "QDateTime(..., Qt::TimeSpec spec)");
// @snippet qdatetime-3
+// @snippet qdatetime-4
+QDate date(%1, %2, %3);
+QTime time(%4, %5, %6, %7);
+%0 = new %TYPE(date, time, QTimeZone(%8));
+// @snippet qdatetime-4
+
// @snippet qdatetime-topython
QDate date = %CPPSELF.date();
QTime time = %CPPSELF.time();
@@ -1538,7 +1501,7 @@ if (Shiboken::Enum::check(%in)) {
metaType = QMetaType::fromName(typeName);
}
if (!metaType.isValid())
- metaType = QVariant_resolveMetaType(Py_TYPE(%in));
+ metaType = PySide::Variant::resolveMetaType(Py_TYPE(%in));
bool ok = false;
if (metaType.isValid()) {
@@ -1560,12 +1523,12 @@ if (!ok)
// @snippet conversion-sbkobject
// @snippet conversion-pydict
-QVariant ret = QVariant_convertToVariantMap(%in);
+QVariant ret = PySide::Variant::convertToVariantMap(%in);
%out = ret.isValid() ? ret : QVariant::fromValue(PySide::PyObjectWrapper(%in));
// @snippet conversion-pydict
// @snippet conversion-pylist
-QVariant ret = QVariant_convertToVariantList(%in);
+QVariant ret = PySide::Variant::convertToVariantList(%in);
%out = ret.isValid() ? ret : QVariant::fromValue(PySide::PyObjectWrapper(%in));
// @snippet conversion-pylist
@@ -1575,7 +1538,7 @@ QVariant ret = QVariant_convertToVariantList(%in);
// @snippet conversion-pyobject
// @snippet conversion-qjsonobject-pydict
-QVariant dict = QVariant_convertToVariantMap(%in);
+QVariant dict = PySide::Variant::convertToVariantMap(%in);
QJsonValue val = QJsonValue::fromVariant(dict);
%out = val.toObject();
// @snippet conversion-qjsonobject-pydict
diff --git a/sources/pyside6/libpyside/CMakeLists.txt b/sources/pyside6/libpyside/CMakeLists.txt
index 539f1f329..15ab47494 100644
--- a/sources/pyside6/libpyside/CMakeLists.txt
+++ b/sources/pyside6/libpyside/CMakeLists.txt
@@ -40,6 +40,7 @@ set(libpyside_HEADERS # installed below
pysideslot_p.h
pysidestaticstrings.h
pysideutils.h
+ pysidevariantutils.h
pysideweakref.h
qobjectconnect.h
signalmanager.h
@@ -59,6 +60,7 @@ set(libpyside_SRC
pysidesignal.cpp
pysideslot.cpp
pysideproperty.cpp
+ pysidevariantutils.cpp
pysideweakref.cpp
pyside.cpp
pyside_numpy.cpp
diff --git a/sources/pyside6/libpyside/pysidemetafunction.cpp b/sources/pyside6/libpyside/pysidemetafunction.cpp
index 48aba3c7b..7a496c4b7 100644
--- a/sources/pyside6/libpyside/pysidemetafunction.cpp
+++ b/sources/pyside6/libpyside/pysidemetafunction.cpp
@@ -4,6 +4,8 @@
#include "pysidemetafunction.h"
#include "pysidemetafunction_p.h"
+#include <signalmanager.h>
+
#include <autodecref.h>
#include <basewrapper.h>
#include <sbkconverter.h>
@@ -12,6 +14,8 @@
#include <QtCore/qmetaobject.h>
+using namespace Qt::StringLiterals;
+
extern "C"
{
@@ -164,6 +168,10 @@ bool call(QObject *self, int methodIndex, PyObject *args, PyObject **retVal)
QString tmp;
converter.toCpp(obj, &tmp);
methValues[i] = tmp;
+ } else if (metaType.id() == PyObjectWrapper::metaTypeId()) {
+ // Manual conversion, see PyObjectWrapper converter registration
+ methValues[i] = QVariant::fromValue(PyObjectWrapper(obj.object()));
+ methArgs[i] = methValues[i].data();
} else {
converter.toCpp(obj, methArgs[i]);
}
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp
index e8ea2fa03..69d347043 100644
--- a/sources/pyside6/libpyside/pysideproperty.cpp
+++ b/sources/pyside6/libpyside/pysideproperty.cpp
@@ -6,6 +6,7 @@
#include "pysideproperty_p.h"
#include "pysidesignal.h"
#include "pysidesignal_p.h"
+#include "signalmanager.h"
#include <autodecref.h>
#include <pep384ext.h>
@@ -17,6 +18,8 @@
using namespace Shiboken;
+using namespace Qt::StringLiterals;
+
extern "C"
{
@@ -148,16 +151,20 @@ void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, v
switch (call) {
case QMetaObject::ReadProperty: {
AutoDecRef value(getValue(source));
- auto *obValue = value.object();
- if (obValue) {
- Conversions::SpecificConverter converter(typeName);
- if (converter) {
- converter.toCpp(obValue, args[0]);
- } else {
- // PYSIDE-2160: Report an unknown type name to the caller `qtPropertyMetacall`.
- PyErr_SetObject(PyExc_StopIteration, obValue);
- }
+ if (value.isNull())
+ return;
+ if (typeName == "PyObject"_ba) {
+ // Manual conversion, see PyObjectWrapper converter registration
+ auto *pw = reinterpret_cast<PySide::PyObjectWrapper *>(args[0]);
+ pw->reset(value.object());
+ return;
+ }
+ if (Conversions::SpecificConverter converter(typeName); converter) {
+ converter.toCpp(value.object(), args[0]);
+ return;
}
+ // PYSIDE-2160: Report an unknown type name to the caller `qtPropertyMetacall`.
+ PyErr_SetObject(PyExc_StopIteration, value.object());
}
break;
diff --git a/sources/pyside6/libpyside/pysidevariantutils.cpp b/sources/pyside6/libpyside/pysidevariantutils.cpp
new file mode 100644
index 000000000..7dbfb3afc
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidevariantutils.cpp
@@ -0,0 +1,212 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysidevariantutils.h"
+#include "pysideutils.h"
+
+#include <QtCore/qvariantmap.h>
+
+#include <autodecref.h>
+#include <sbkconverter.h>
+#include <basewrapper.h>
+
+using namespace Qt::StringLiterals;
+
+static const char qVariantTypeName[] = "QVariant";
+
+static void warnConverter(const char *name)
+{
+ qWarning("Type converter for: %s not registered.", name);
+}
+
+// Helper converting each item of a non-empty list using the "QVariant" converter
+static std::optional<QVariantList> pyListToVariantListHelper(PyObject *list, Py_ssize_t size)
+{
+ Q_ASSERT(size > 0);
+ QVariantList result;
+ result.reserve(size);
+ Shiboken::Conversions::SpecificConverter converter(qVariantTypeName);
+ if (!converter) {
+ warnConverter(qVariantTypeName);
+ return std::nullopt;
+ }
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ Shiboken::AutoDecRef pyItem(PySequence_GetItem(list, i));
+ QVariant item;
+ converter.toCpp(pyItem.object(), &item);
+ result.append(item);
+ }
+ return result;
+}
+
+// Helper checking for a sequence of Unicode objects
+static bool isStringList(PyObject *list)
+{
+ const Py_ssize_t size = PySequence_Size(list);
+ if (size == 0)
+ return false;
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ Shiboken::AutoDecRef item(PySequence_GetItem(list, i));
+ if (PyUnicode_Check(item) == 0)
+ return false;
+ }
+ return true;
+}
+
+// Helper to convert to a QStringList
+static std::optional<QStringList> listToStringList(PyObject *list)
+{
+ static const char listType[] = "QList<QString>";
+ Shiboken::Conversions::SpecificConverter converter(listType);
+ if (!converter) {
+ warnConverter(listType);
+ return std::nullopt;
+ }
+ QStringList result;
+ converter.toCpp(list, &result);
+ return result;
+}
+
+// Helper to convert a non-empty, homogenous list using the converter of the first item
+static QVariant convertToValueList(PyObject *list)
+{
+ Q_ASSERT(PySequence_Size(list) >= 0);
+
+ Shiboken::AutoDecRef element(PySequence_GetItem(list, 0));
+
+ auto *type = reinterpret_cast<PyTypeObject *>(element.object());
+ QMetaType metaType = PySide::Variant::resolveMetaType(type);
+ if (!metaType.isValid())
+ return {};
+
+ const QByteArray listTypeName = QByteArrayLiteral("QList<") + metaType.name() + '>';
+ metaType = QMetaType::fromName(listTypeName);
+ if (!metaType.isValid())
+ return {};
+
+ Shiboken::Conversions::SpecificConverter converter(listTypeName);
+ if (!converter) {
+ warnConverter(listTypeName.constData());
+ return {};
+ }
+
+ QVariant var(metaType);
+ converter.toCpp(list, &var);
+ return var;
+}
+
+namespace PySide::Variant
+{
+
+QMetaType resolveMetaType(PyTypeObject *type)
+{
+ if (!PyObject_TypeCheck(type, SbkObjectType_TypeF()))
+ return {};
+ const char *typeName = Shiboken::ObjectType::getOriginalName(type);
+ if (!typeName)
+ return {};
+ const bool valueType = '*' != typeName[qstrlen(typeName) - 1];
+ // Do not convert user type of value
+ if (valueType && Shiboken::ObjectType::isUserType(type))
+ return {};
+ QMetaType metaType = QMetaType::fromName(typeName);
+ if (metaType.isValid())
+ return metaType;
+ // Do not resolve types to value type
+ if (valueType)
+ return {};
+ // Find in base types. First check tp_bases, and only after check tp_base, because
+ // tp_base does not always point to the first base class, but rather to the first
+ // that has added any python fields or slots to its object layout.
+ // See https://mail.python.org/pipermail/python-list/2009-January/520733.html
+ if (type->tp_bases) {
+ const auto size = PyTuple_Size(type->tp_bases);
+ Py_ssize_t i = 0;
+ // PYSIDE-1887, PYSIDE-86: Skip QObject base class of QGraphicsObject;
+ // it needs to use always QGraphicsItem as a QVariant type for
+ // QGraphicsItem::itemChange() to work.
+ if (qstrcmp(typeName, "QGraphicsObject*") == 0)
+ ++i;
+ for ( ; i < size; ++i) {
+ auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, i));
+ const QMetaType derived = resolveMetaType(baseType);
+ if (derived.isValid())
+ return derived;
+ }
+ return {};
+ }
+ if (type->tp_base != nullptr)
+ return resolveMetaType(type->tp_base);
+ return {};
+}
+
+std::optional<QVariantList> pyListToVariantList(PyObject *list)
+{
+ if (list == nullptr || PySequence_Check(list) == 0)
+ return std::nullopt;
+ const auto size = PySequence_Size(list);
+ if (size < 0) { // Some infinite (I/O read) thing? - bail out
+ PyErr_Clear();
+ return std::nullopt;
+ }
+ if (size == 0)
+ return QVariantList{};
+ return pyListToVariantListHelper(list, size);
+}
+
+QVariant convertToVariantList(PyObject *list)
+{
+ const auto size = PySequence_Size(list);
+ if (size < 0) { // Some infinite (I/O read) thing? - bail out
+ PyErr_Clear();
+ return {};
+ }
+ if (size == 0)
+ return QVariantList{};
+
+ if (isStringList(list)) {
+ auto stringListO = listToStringList(list);
+ if (stringListO.has_value())
+ return {stringListO.value()};
+ }
+
+ if (QVariant valueList = convertToValueList(list); valueList.isValid())
+ return valueList;
+
+ if (auto vlO = pyListToVariantListHelper(list, size); vlO.has_value())
+ return vlO.value();
+
+ return {};
+}
+
+QVariant convertToVariantMap(PyObject *map)
+{
+ if (map == nullptr || PyDict_Check(map) == 0)
+ return {};
+
+ QVariantMap result;
+ if (PyDict_Size(map) == 0)
+ return result;
+
+ Py_ssize_t pos = 0;
+ Shiboken::AutoDecRef keys(PyDict_Keys(map));
+ if (!isStringList(keys))
+ return {};
+
+ Shiboken::Conversions::SpecificConverter converter(qVariantTypeName);
+ if (!converter) {
+ warnConverter(qVariantTypeName);
+ return {};
+ }
+
+ PyObject *key{};
+ PyObject *value{};
+ while (PyDict_Next(map, &pos, &key, &value)) {
+ QVariant cppValue;
+ converter.toCpp(value, &cppValue);
+ result.insert(PySide::pyUnicodeToQString(key), cppValue);
+ }
+ return result;
+}
+
+} // namespace PySide::Variant
diff --git a/sources/pyside6/libpyside/pysidevariantutils.h b/sources/pyside6/libpyside/pysidevariantutils.h
new file mode 100644
index 000000000..b53f7ce82
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidevariantutils.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEVARIANTUTILS_H
+#define PYSIDEVARIANTUTILS_H
+
+#include <sbkpython.h>
+
+#include <pysidemacros.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qvariantlist.h>
+
+#include <optional>
+
+namespace PySide::Variant
+{
+
+/// Return a QMetaType for a PyTypeObject for purposes of
+/// converting to a QVariant.
+PYSIDE_API QMetaType resolveMetaType(PyTypeObject *type);
+
+/// Convert a heterogenous Python list to a QVariantList by converting each
+/// item using the QVariant converter.
+PYSIDE_API std::optional<QVariantList> pyListToVariantList(PyObject *list);
+
+/// Converts a list to a QVariant following the PySide semantics:
+/// - A list of strings is returned as QVariant<QStringList>
+/// - A list of convertible values is returned as QVariant<QList<Value>>
+/// - Remaining types are returned as QVariant(QVariantList)
+PYSIDE_API QVariant convertToVariantList(PyObject *list);
+
+/// Converts a map to a QVariantMap (string keys and QVariant values)
+PYSIDE_API QVariant convertToVariantMap(PyObject *map);
+} // namespace PySide::Variant
+
+#endif // PYSIDEVARIANTUTILS_H
diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp
index 933edd318..305d2f5c3 100644
--- a/sources/pyside6/libpyside/signalmanager.cpp
+++ b/sources/pyside6/libpyside/signalmanager.cpp
@@ -24,9 +24,12 @@
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
+#include <QtCore/qmetatype.h>
#include <QtCore/qscopedpointer.h>
+#include <climits>
#include <memory>
+#include <utility>
using namespace Qt::StringLiterals;
@@ -36,6 +39,8 @@ using namespace Qt::StringLiterals;
static PyObject *metaObjectAttr = nullptr;
+static int pyObjectWrapperMetaTypeId = QMetaType::UnknownType;
+
static void destroyMetaObject(PyObject *obj)
{
void *ptr = PyCapsule_GetPointer(obj, nullptr);
@@ -125,6 +130,17 @@ PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other)
Py_XINCREF(m_me);
}
+PyObjectWrapper::PyObjectWrapper(PyObjectWrapper &&other) noexcept
+ : m_me{std::exchange(other.m_me, nullptr)}
+{
+}
+
+PyObjectWrapper &PyObjectWrapper::operator=(PyObjectWrapper &&other) noexcept
+{
+ m_me = std::exchange(other.m_me, nullptr);
+ return *this;
+}
+
PyObjectWrapper::~PyObjectWrapper()
{
// Check that Python is still initialized as sometimes this is called by a static destructor
@@ -156,6 +172,10 @@ PyObjectWrapper::operator PyObject *() const
return m_me;
}
+int PyObjectWrapper::metaTypeId()
+{
+ return pyObjectWrapperMetaTypeId;
+}
int PyObjectWrapper::toInt() const
{
@@ -221,7 +241,29 @@ QDataStream &operator>>(QDataStream &in, PyObjectWrapper &myObj)
return in;
}
-};
+PYSIDE_API QDebug operator<<(QDebug debug, const PyObjectWrapper &myObj)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ // Do not repeat the type name as it is typically called from the QVariant debug
+ // operator, which outputs the type.
+ debug << '<';
+ if (PyObject *ob = myObj) {
+ const auto refs = Py_REFCNT(ob);
+ debug << Py_TYPE(ob)->tp_name << " at " << ob;
+ if (refs == UINT_MAX) // _Py_IMMORTAL_REFCNT
+ debug << ", immortal";
+ else
+ debug << ", refs=" << refs;
+ } else {
+ debug << '0';
+ }
+ debug << '>';
+ return debug;
+}
+
+} // namespace PySide
using namespace PySide;
@@ -238,19 +280,11 @@ struct SignalManagerPrivate
SignalManager::QmlMetaCallErrorHandler
SignalManagerPrivate::m_qmlMetaCallErrorHandler = nullptr;
-static void PyObject_PythonToCpp_PyObject_PTR(PyObject *pyIn, void *cppOut)
-{
- *reinterpret_cast<PyObject **>(cppOut) = pyIn;
-}
-static PythonToCppFunc is_PyObject_PythonToCpp_PyObject_PTR_Convertible(PyObject * /* pyIn */)
-{
- return PyObject_PythonToCpp_PyObject_PTR;
-}
-static PyObject *PyObject_PTR_CppToPython_PyObject(const void *cppIn)
+static PyObject *CopyCppToPythonPyObject(const void *cppIn)
{
- auto *pyOut = reinterpret_cast<PyObject *>(const_cast<void *>(cppIn));
- if (pyOut)
- Py_INCREF(pyOut);
+ const auto *wrapper = reinterpret_cast<const PyObjectWrapper *>(cppIn);
+ PyObject *pyOut = *wrapper;
+ Py_XINCREF(pyOut);
return pyOut;
}
@@ -260,13 +294,16 @@ void SignalManager::init()
using namespace Shiboken;
// Register PyObject type to use in queued signal and slot connections
- qRegisterMetaType<PyObjectWrapper>("PyObject");
+ pyObjectWrapperMetaTypeId = qRegisterMetaType<PyObjectWrapper>("PyObject");
// Register QVariant(enum) conversion to QVariant(int)
QMetaType::registerConverter<PyObjectWrapper, int>(&PyObjectWrapper::toInt);
- SbkConverter *converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type, nullptr);
- Shiboken::Conversions::setCppPointerToPythonFunction(converter, PyObject_PTR_CppToPython_PyObject);
- Shiboken::Conversions::setPythonToCppPointerFunctions(converter, PyObject_PythonToCpp_PyObject_PTR, is_PyObject_PythonToCpp_PyObject_PTR_Convertible);
+ // Register a shiboken converter for PyObjectWrapper->Python (value conversion).
+ // Python->PyObjectWrapper is not registered since the converters do not work for
+ // non-SbkObject types (falling back to plain pointer pass through).
+ // This conversion needs to be done manually via QVariant.
+ SbkConverter *converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type,
+ CopyCppToPythonPyObject);
Shiboken::Conversions::registerConverterName(converter, "PyObject");
Shiboken::Conversions::registerConverterName(converter, "object");
Shiboken::Conversions::registerConverterName(converter, "PyObjectWrapper");
diff --git a/sources/pyside6/libpyside/signalmanager.h b/sources/pyside6/libpyside/signalmanager.h
index d5c007dbe..9fe56efc2 100644
--- a/sources/pyside6/libpyside/signalmanager.h
+++ b/sources/pyside6/libpyside/signalmanager.h
@@ -14,6 +14,7 @@
#include <optional>
QT_FORWARD_DECLARE_CLASS(QDataStream)
+QT_FORWARD_DECLARE_CLASS(QDebug)
namespace PySide
{
@@ -22,13 +23,13 @@ namespace PySide
class PYSIDE_API PyObjectWrapper
{
public:
- PyObjectWrapper(PyObjectWrapper&&) = delete;
- PyObjectWrapper& operator=(PyObjectWrapper &&) = delete;
PyObjectWrapper();
explicit PyObjectWrapper(PyObject* me);
PyObjectWrapper(const PyObjectWrapper &other);
PyObjectWrapper& operator=(const PyObjectWrapper &other);
+ PyObjectWrapper(PyObjectWrapper&&) noexcept;
+ PyObjectWrapper &operator=(PyObjectWrapper &&) noexcept;
void reset(PyObject *o);
@@ -43,12 +44,15 @@ public:
// The proper fix would be to associate PyObjectWrapper to the corresponding C++ Enum.
int toInt() const;
+ static int metaTypeId();
+
private:
PyObject* m_me;
};
PYSIDE_API QDataStream &operator<<(QDataStream& out, const PyObjectWrapper& myObj);
PYSIDE_API QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj);
+PYSIDE_API QDebug operator<<(QDebug debug, const PyObjectWrapper &myObj);
class PYSIDE_API SignalManager
{
diff --git a/sources/pyside6/tests/QtCore/deepcopy_test.py b/sources/pyside6/tests/QtCore/deepcopy_test.py
index 8b211a979..64b001e6d 100644
--- a/sources/pyside6/tests/QtCore/deepcopy_test.py
+++ b/sources/pyside6/tests/QtCore/deepcopy_test.py
@@ -12,8 +12,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from init_paths import init_test_paths
init_test_paths(False)
-from PySide6.QtCore import QByteArray, QDate, QDateTime, QTime, QLine, QLineF
-from PySide6.QtCore import Qt, QSize, QSizeF, QRect, QRectF, QDir, QPoint, QPointF
+from PySide6.QtCore import QByteArray, QDate, QDateTime, QTime, QLine, QLineF, QTimeZone
+from PySide6.QtCore import QSize, QSizeF, QRect, QRectF, QDir, QPoint, QPointF
try:
from PySide6.QtCore import QUuid
HAVE_Q = True
@@ -45,7 +45,7 @@ class QTimeDeepCopy(DeepCopyHelper, unittest.TestCase):
class QDateTimeDeepCopy(DeepCopyHelper, unittest.TestCase):
def setUp(self):
- self.original = QDateTime(2010, 5, 18, 10, 24, 45, 223, Qt.TimeSpec.LocalTime)
+ self.original = QDateTime(2010, 5, 18, 10, 24, 45, 223, QTimeZone(QTimeZone.LocalTime))
class QSizeDeepCopy(DeepCopyHelper, unittest.TestCase):
diff --git a/sources/pyside6/tests/QtCore/qobject_property_test.py b/sources/pyside6/tests/QtCore/qobject_property_test.py
index 37936205e..80387ec77 100644
--- a/sources/pyside6/tests/QtCore/qobject_property_test.py
+++ b/sources/pyside6/tests/QtCore/qobject_property_test.py
@@ -32,6 +32,26 @@ class MyObjectWithNotifyProperty(QObject):
myProperty = Property(int, readP, fset=writeP, notify=notifyP)
+class OtherClass:
+ """Helper for QObjectWithOtherClassPropertyTest."""
+ pass
+
+
+class MyObjectWithOtherClassProperty(QObject):
+ """Helper for QObjectWithOtherClassPropertyTest."""
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._otherclass = None
+
+ def _get_otherclass(self):
+ return self._otherclass
+
+ def _set_otherclass(self, o):
+ self._otherclass = o
+
+ otherclass = Property(OtherClass, fget=_get_otherclass, fset=_set_otherclass)
+
+
class PropertyWithNotify(unittest.TestCase):
def called(self):
self.called_ = True
@@ -50,5 +70,19 @@ class PropertyWithNotify(unittest.TestCase):
self.assertEqual(o.property("myProperty"), 10)
+class QObjectWithOtherClassPropertyTest(unittest.TestCase):
+ """PYSIDE-2193: For properties of custom classes not wrapped by shiboken,
+ QVariant<PyObjectWrapper> is used, which had refcount issues causing crashes.
+ Exercise the QVariant conversion by setting and retrieving via the
+ QVariant-based property()/setProperty() API."""
+ def testNotify(self):
+ obj = MyObjectWithOtherClassProperty()
+ obj.setProperty("otherclass", OtherClass())
+ for i in range(10):
+ pv = obj.property("otherclass")
+ print(pv) # Exercise repr
+ self.assertTrue(type(pv) is OtherClass)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside6/tests/QtCore/repr_test.py b/sources/pyside6/tests/QtCore/repr_test.py
index 084b69f87..52a426d31 100644
--- a/sources/pyside6/tests/QtCore/repr_test.py
+++ b/sources/pyside6/tests/QtCore/repr_test.py
@@ -13,8 +13,8 @@ init_test_paths(False)
# for 'self.original'
import PySide6 # noqa
-from PySide6.QtCore import QByteArray, QDate, QDateTime, QTime, QLine, QLineF
-from PySide6.QtCore import Qt, QSize, QSizeF, QRect, QRectF, QPoint, QPointF
+from PySide6.QtCore import QByteArray, QDate, QDateTime, QTime, QLine, QLineF, QTimeZone
+from PySide6.QtCore import QSize, QSizeF, QRect, QRectF, QPoint, QPointF
try:
from PySide6.QtCore import QUuid
HAVE_Q = True
@@ -46,7 +46,7 @@ class QTimeReprCopy(ReprCopyHelper, unittest.TestCase):
class QDateTimeReprCopy(ReprCopyHelper, unittest.TestCase):
def setUp(self):
- self.original = QDateTime(2010, 5, 18, 10, 24, 45, 223, Qt.TimeSpec.LocalTime)
+ self.original = QDateTime(2010, 5, 18, 10, 24, 45, 223, QTimeZone(QTimeZone.LocalTime))
class QSizeReprCopy(ReprCopyHelper, unittest.TestCase):
diff --git a/sources/pyside6/tests/QtWidgets/bug_433.py b/sources/pyside6/tests/QtWidgets/bug_433.py
index 5adcacccc..6d5c4333a 100644
--- a/sources/pyside6/tests/QtWidgets/bug_433.py
+++ b/sources/pyside6/tests/QtWidgets/bug_433.py
@@ -26,4 +26,4 @@ a = QApplication(sys.argv)
t = Test()
t.show()
QTimer.singleShot(0, t.close)
-sys.exit(a.exec_())
+sys.exit(a.exec())
diff --git a/sources/pyside6/tests/QtWidgets/bug_919.py b/sources/pyside6/tests/QtWidgets/bug_919.py
index 6f2fc128d..a95d3aa37 100644
--- a/sources/pyside6/tests/QtWidgets/bug_919.py
+++ b/sources/pyside6/tests/QtWidgets/bug_919.py
@@ -26,10 +26,11 @@ class MyWidget(QPushButton):
self.paintReceived.emit()
def paintEvent(self, e):
- p = QPainter(self)
- style = QApplication.style()
- option = QStyleOptionButton()
- style.drawControl(QStyle.ControlElement.CE_PushButton, option, p)
+ with QPainter(self) as p:
+ style = QApplication.style()
+ option = QStyleOptionButton()
+ self.initStyleOption(option)
+ style.drawControl(QStyle.ControlElement.CE_PushButton, option, p)
self._painted = True
QTimer.singleShot(0, self._emitPainted)
diff --git a/sources/pyside6/tests/QtWidgets/qapp_issue_585.py b/sources/pyside6/tests/QtWidgets/qapp_issue_585.py
index ec8a47569..1300ea4aa 100644
--- a/sources/pyside6/tests/QtWidgets/qapp_issue_585.py
+++ b/sources/pyside6/tests/QtWidgets/qapp_issue_585.py
@@ -40,15 +40,15 @@ import sys
from pathlib import Path
sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util"))
-from init_paths import init_test_paths
+from init_paths import init_test_paths # noqa: E402
init_test_paths()
-from PySide6.QtCore import QTimer
-from PySide6.QtWidgets import QApplication
+from PySide6.QtCore import QTimer # noqa: E402
+from PySide6.QtWidgets import QApplication # noqa: E402
app_instance = QApplication([])
# If the following line is commented, application doesn't crash on exit anymore.
app_instance2 = app_instance
-QTimer.singleShot(0, qApp.quit)
-app_instance.exec_()
+QTimer.singleShot(0, qApp.quit) # noqa: F821
+app_instance.exec()
diff --git a/sources/pyside6/tests/QtWidgets/qmenu_test.py b/sources/pyside6/tests/QtWidgets/qmenu_test.py
index 7d1d262e4..8bd5d1624 100644
--- a/sources/pyside6/tests/QtWidgets/qmenu_test.py
+++ b/sources/pyside6/tests/QtWidgets/qmenu_test.py
@@ -33,16 +33,16 @@ class QMenuAddAction(UsesQApplication):
def testAddActionWithoutKeySequenceCallable(self):
# bug #280
- action = self.menu.addAction(self.app.tr('aaa'), lambda: 1)
+ action = self.menu.addAction(self.app.tr('aaa'), lambda: 1) # noqa: F841
def testAddActionKeySequenceCallable(self):
# bug #228
- action = self.menu.addAction(self.app.tr('aaa'), lambda: 1,
+ action = self.menu.addAction(self.app.tr('aaa'), lambda: 1, # noqa: F841
QKeySequence(self.app.tr('Ctrl+O')))
def testAddActionKeySequenceSlot(self):
- action = self.menu.addAction('Quit', self.app, SLOT('quit()'),
- QKeySequence('Ctrl+O'))
+ action = self.menu.addAction('Quit', QKeySequence('Ctrl+O'), # noqa: F841
+ self.app, SLOT('quit()'))
class QMenuAddActionWithIcon(UsesQApplication):
@@ -61,16 +61,16 @@ class QMenuAddActionWithIcon(UsesQApplication):
def testAddActionWithoutKeySequenceCallable(self):
# bug #280
- action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1)
+ action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1) # noqa: F841
def testAddActionKeySequenceCallable(self):
# bug #228
- action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1,
- QKeySequence(self.app.tr('Ctrl+O')))
+ action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1, # noqa: F841
+ QKeySequence(self.app.tr('Ctrl+O'))) # noqa: F841
def testAddActionKeySequenceSlot(self):
- action = self.menu.addAction(self.icon, 'Quit', self.app, SLOT('quit()'),
- QKeySequence('Ctrl+O'))
+ action = self.menu.addAction(self.icon, 'Quit', QKeySequence('Ctrl+O'), # noqa: F841
+ self.app, SLOT('quit()')) # noqa: F841
if __name__ == '__main__':
diff --git a/sources/pyside6/tests/QtXml/qdomdocument_test.py b/sources/pyside6/tests/QtXml/qdomdocument_test.py
index 8fe4f6e17..b321b1bdf 100644
--- a/sources/pyside6/tests/QtXml/qdomdocument_test.py
+++ b/sources/pyside6/tests/QtXml/qdomdocument_test.py
@@ -44,18 +44,20 @@ class QDomDocumentTest(unittest.TestCase):
def testQDomDocumentSetContentWithBadXmlData(self):
'''Sets invalid xml as the QDomDocument contents.'''
- ok, errorStr, errorLine, errorColumn = self.dom.setContent(self.badXmlData, True)
- self.assertFalse(ok)
- self.assertEqual(errorStr, 'Opening and ending tag mismatch.')
- self.assertEqual(errorLine, 4)
+ parseResult = self.dom.setContent(self.badXmlData,
+ QDomDocument.ParseOption.UseNamespaceProcessing)
+ self.assertFalse(parseResult)
+ self.assertEqual(parseResult.errorMessage, 'Opening and ending tag mismatch.')
+ self.assertEqual(parseResult.errorLine, 4)
def testQDomDocumentSetContentWithGoodXmlData(self):
'''Sets valid xml as the QDomDocument contents.'''
- ok, errorStr, errorLine, errorColumn = self.dom.setContent(self.goodXmlData, True)
- self.assertTrue(ok)
- self.assertEqual(errorStr, '')
- self.assertEqual(errorLine, 0)
- self.assertEqual(errorColumn, 0)
+ parseResult = self.dom.setContent(self.goodXmlData,
+ QDomDocument.ParseOption.UseNamespaceProcessing)
+ self.assertTrue(parseResult)
+ self.assertEqual(parseResult.errorMessage, '')
+ self.assertEqual(parseResult.errorLine, 0)
+ self.assertEqual(parseResult.errorColumn, 0)
def testQDomDocumentData(self):
'''Checks the QDomDocument elements for the valid xml contents.'''
@@ -66,7 +68,8 @@ class QDomDocumentTest(unittest.TestCase):
self.assertTrue(element.hasAttribute(attribute))
self.assertEqual(element.attribute(attribute), value)
- ok, errorStr, errorLine, errorColumn = self.dom.setContent(self.goodXmlData, True)
+ parseResult = self.dom.setContent(self.goodXmlData, # noqa F:841
+ QDomDocument.ParseOption.UseNamespaceProcessing)
root = self.dom.documentElement()
self.assertEqual(root.tagName(), 'typesystem')
checkAttribute(root, 'package', 'PySide6.QtXml')
diff --git a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
index 120c54af3..14330726a 100644
--- a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
+++ b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
@@ -36,7 +36,7 @@ class DeployTestBase(unittest.TestCase):
android_requirements_file = pyside_tools / "requirements-android.txt"
with open(android_requirements_file, 'r', encoding='UTF-8') as file:
while line := file.readline():
- dependent_package = line.rstrip()
+ dependent_package = line.rstrip().split('==')[0]
if not bool(importlib.util.find_spec(dependent_package)):
command = [sys.executable, "-m", "pip", "install", dependent_package]
subprocess.run(command)
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index 27570ec4f..fb5399baa 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -2664,7 +2664,7 @@ std::optional<AbstractMetaType>
qsizetype i = d ? d->m_scopes.size() - 1 : -1;
while (i >= 0) {
typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--));
- if (typeInfo.qualifiedName().join(u"::"_s) != _typei.qualifiedName().join(u"::"_s))
+ if (typeInfo.qualifiedName() != _typei.qualifiedName())
break;
}
@@ -2757,12 +2757,22 @@ std::optional<AbstractMetaType>
// 4. Special case QFlags (include instantiation in name)
if (qualifiedName == u"QFlags") {
- qualifiedName = typeInfo.toString();
+ qualifiedName = typeInfo.qualifiedInstantationName();
typeInfo.clearInstantiations();
}
TypeEntryCList types = findTypeEntries(qualifiedName, name, flags,
currentClass, d, errorMessageIn);
+ if (types.isEmpty() && !typeInfo.instantiations().isEmpty()) {
+ // Allow for specifying template specializations as primitive types
+ // with converters ('std::optional<int>' or similar).
+ auto pt = TypeDatabase::instance()->findPrimitiveType(typeInfo.qualifiedInstantationName());
+ if (pt) {
+ types.append(pt);
+ typeInfo.clearInstantiations();
+ }
+ }
+
if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) {
// Avoid clashes between QByteArray and enum value QMetaType::QByteArray
// unless we are looking for template arguments.
@@ -2796,7 +2806,7 @@ std::optional<AbstractMetaType>
// For non-type template parameters, create a dummy type entry on the fly
// as is done for classes.
if (!targType.has_value()) {
- const QString value = ti.qualifiedName().join(u"::"_s);
+ const QString value = ti.qualifiedNameString();
if (isNumber(value)) {
auto module = typeSystemTypeEntry(type);
TypeDatabase::instance()->addConstantValueTypeEntry(value, module);
@@ -3082,7 +3092,7 @@ AbstractMetaClassPtr
QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(u"::"_s) + u"::"_s : QString();
QString completeName = prefix + name;
const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage);
- QString qualifiedName = parsed.qualifiedName().join(u"::"_s);
+ QString qualifiedName = parsed.qualifiedNameString();
if (qualifiedName.isEmpty()) {
qWarning().noquote().nospace() << "Unable to parse type \"" << completeName
<< "\" while looking for template \"" << name << "\": " << errorMessage;
@@ -3196,7 +3206,7 @@ static std::optional<AbstractMetaType>
const AbstractMetaClassCPtr &templateClass,
const TypeInfo &info, QString *errorMessage)
{
- QString typeName = info.qualifiedName().join("::"_L1);
+ QString typeName = info.qualifiedNameString();
TypeDatabase *typeDb = TypeDatabase::instance();
TypeEntryPtr t;
// Check for a non-type template integer parameter, that is, for a base
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp
index 90f4f5dd9..38dedfd14 100644
--- a/sources/shiboken6/ApiExtractor/apiextractor.cpp
+++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp
@@ -370,6 +370,7 @@ bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags)
bool addCompilerSupportArguments = true;
if (clangOptionsSize > 0) {
+ clang::setTargetTriple(m_clangOptions);
qsizetype i = 0;
if (m_clangOptions.at(i) == u"-") {
++i;
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
index 54a1a2c8b..747937ede 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
@@ -275,6 +275,24 @@ static CXTranslationUnit createTranslationUnit(CXIndex index,
return tu;
}
+static void setupTarget(CXTranslationUnit translationUnit)
+{
+ const CXTargetInfo targetInfo = clang_getTranslationUnitTargetInfo(translationUnit);
+ const auto tripleCS = clang_TargetInfo_getTriple(targetInfo);
+ clang::setPointerSize(clang_TargetInfo_getPointerWidth(targetInfo));
+ clang::setTargetTriple(QString::fromUtf8(clang_getCString(tripleCS)));
+ clang_disposeString(tripleCS);
+
+ QString message;
+ {
+ QTextStream str(&message);
+ str << "CLANG v" << CINDEX_VERSION_MAJOR << '.' << CINDEX_VERSION_MINOR
+ << " targeting \"" << targetTriple() << "\", " << pointerSize() << "bit.";
+ }
+ qCInfo(lcShiboken, "%s", qPrintable(message));
+ ReportHandler::addGeneralMessage(message + u'\n');
+}
+
/* clangFlags are flags to clang_parseTranslationUnit2() such as
* CXTranslationUnit_KeepGoing (from CINDEX_VERSION_MAJOR/CINDEX_VERSION_MINOR 0.35)
*/
@@ -295,6 +313,8 @@ bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments,
if (!translationUnit)
return false;
+ setupTarget(translationUnit);
+
CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit);
clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast<CXClientData>(&bv));
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
index ed8057b62..4d93a084f 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
+++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
@@ -59,6 +59,9 @@ bool setCompiler(const QString &name)
QString _compilerPath; // Pre-defined compiler path (from command line)
+static unsigned _pointerSize = QT_POINTER_SIZE * 8;
+static QString _targetTriple;
+
const QString &compilerPath()
{
return _compilerPath;
@@ -153,14 +156,15 @@ static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths)
if (homebrewPrefix.isEmpty())
return;
- qCInfo(lcShiboken) << "Found HOMEBREW_OPT with value:" << homebrewPrefix
- << "Assuming homebrew build environment.";
+ ReportHandler::addGeneralMessage("Found HOMEBREW_OPT with value:"_L1
+ + QString::fromUtf8(homebrewPrefix)
+ + "\nAssuming homebrew build environment."_L1);
HeaderPaths::iterator it = headerPaths.begin();
while (it != headerPaths.end()) {
if (it->path.startsWith(homebrewPrefix)) {
- qCInfo(lcShiboken) << "Filtering out homebrew include path: "
- << it->path;
+ ReportHandler::addGeneralMessage("Filtering out homebrew include path: "_L1
+ + QString::fromUtf8(it->path));
it = headerPaths.erase(it);
} else {
++it;
@@ -186,12 +190,6 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler)
const QByteArrayList stdErrLines = stdErr.split('\n');
bool isIncludeDir = false;
- if (ReportHandler::isDebug(ReportHandler::MediumDebug))
- qCInfo(lcShiboken()).noquote().nospace()
- << "gppInternalIncludePaths:\n compiler: " << compiler
- << "\n stdOut: " << stdOut
- << "\n stdErr: " << stdErr;
-
for (const QByteArray &line : stdErrLines) {
if (isIncludeDir) {
if (line.startsWith(QByteArrayLiteral("End of search list"))) {
@@ -212,6 +210,17 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler)
if (platform() == Platform::macOS)
filterHomebrewHeaderPaths(result);
+ QString message;
+ {
+ QTextStream str(&message);
+ str << "gppInternalIncludePaths:\n compiler: " << compiler << '\n';
+ for (const auto &h : result)
+ str << " " << h.path << '\n';
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug))
+ str << " stdOut: " << stdOut << "\n stdErr: " << stdErr;
+ }
+ ReportHandler::addGeneralMessage(message);
+
return result;
}
@@ -365,11 +374,10 @@ static void appendClangBuiltinIncludes(HeaderPaths *p)
"(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR "
" nor running llvm-config). This may lead to parse errors.");
} else {
- qCInfo(lcShiboken, "CLANG v%d.%d, builtins includes directory: %s",
- CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR,
- qPrintable(clangBuiltinIncludesDir));
p->append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir),
HeaderType::System});
+ ReportHandler::addGeneralMessage("CLANG builtins includes directory: "_L1
+ + clangBuiltinIncludesDir);
}
}
@@ -451,4 +459,33 @@ LanguageLevel languageLevelFromOption(const char *o)
return LanguageLevel::Default;
}
+unsigned pointerSize()
+{
+ return _pointerSize;
+}
+
+void setPointerSize(unsigned ps)
+{
+ _pointerSize = ps;
+}
+
+QString targetTriple()
+{
+ return _targetTriple;
+
+}
+void setTargetTriple(const QString &t)
+{
+ _targetTriple = t;
+}
+
+void setTargetTriple(const QStringList &clangOptions)
+{
+ static constexpr auto targetOption = "--target="_L1;
+ auto targetOptionPred = [](const QString &o) { return o.startsWith(targetOption); };
+ const auto it = std::find_if(clangOptions.cbegin(), clangOptions.cend(), targetOptionPred);
+ if (it != clangOptions.cend())
+ _targetTriple = it->sliced(targetOption.size());
+}
+
} // namespace clang
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
index 1fa980998..0e12ca137 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
+++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
@@ -51,6 +51,14 @@ void setCompilerPath(const QString &name);
Platform platform();
bool setPlatform(const QString &name);
+
+unsigned pointerSize(); // (bit)
+void setPointerSize(unsigned ps); // Set by parser
+
+QString targetTriple();
+void setTargetTriple(const QStringList &clangOptions); // Set from cmd line before parsing
+void setTargetTriple(const QString &t); // Updated by clang parser while parsing
+
} // namespace clang
#endif // COMPILERSUPPORT_H
diff --git a/sources/shiboken6/ApiExtractor/customconversion.cpp b/sources/shiboken6/ApiExtractor/customconversion.cpp
index 4cfd1b974..7b65bcf3a 100644
--- a/sources/shiboken6/ApiExtractor/customconversion.cpp
+++ b/sources/shiboken6/ApiExtractor/customconversion.cpp
@@ -5,6 +5,7 @@
#include "containertypeentry.h"
#include "customtypenentry.h"
#include "primitivetypeentry.h"
+#include "smartpointertypeentry.h"
#include "valuetypeentry.h"
#include <QtCore/qdebug.h>
@@ -139,6 +140,8 @@ CustomConversionPtr CustomConversion::getCustomConversion(const TypeEntryCPtr &t
return std::static_pointer_cast<const ContainerTypeEntry>(type)->customConversion();
if (type->isValue())
return std::static_pointer_cast<const ValueTypeEntry>(type)->customConversion();
+ if (type->isSmartPointer())
+ return std::static_pointer_cast<const SmartPointerTypeEntry>(type)->customConversion();
return {};
}
diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
index 845a0f916..93627e6d5 100644
--- a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
+++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
@@ -110,6 +110,28 @@ QStringList TypeInfo::qualifiedName() const
return d->m_qualifiedName;
}
+QString TypeInfo::qualifiedNameString() const
+{
+ return d->m_qualifiedName.join("::"_L1);
+}
+
+QString TypeInfo::qualifiedInstantationName() const
+{
+ QString result = qualifiedNameString();
+ if (const auto instantiationCount = d->m_instantiations.size()) {
+ result += u'<';
+ for (qsizetype i = 0; i < instantiationCount; ++i) {
+ if (i)
+ result += ", "_L1;
+ result += d->m_instantiations.at(i).toString();
+ }
+ if (result.endsWith(u'>'))
+ result += u' ';
+ result += u'>';
+ }
+ return result;
+}
+
void TypeInfo::setQualifiedName(const QStringList &qualified_name)
{
if (d->m_qualifiedName != qualified_name)
@@ -300,7 +322,7 @@ TypeInfo TypeInfo::resolveType(const CodeModelItem &__item, TypeInfo const &__ty
// typedef struct xcb_connection_t xcb_connection_t;
if (nextItem.get() ==__item.get()) {
std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__
- << "() on " << qPrintable(__type.qualifiedName().join(u"::"_s))
+ << "() on " << qPrintable(__type.qualifiedNameString())
<< '\n';
return otherType;
}
@@ -385,19 +407,7 @@ QString TypeInfo::toString() const
if (isVolatile())
tmp += u"volatile "_s;
- tmp += d->m_qualifiedName.join(u"::"_s);
-
- if (const auto instantiationCount = d->m_instantiations.size()) {
- tmp += u'<';
- for (qsizetype i = 0; i < instantiationCount; ++i) {
- if (i)
- tmp += u", "_s;
- tmp += d->m_instantiations.at(i).toString();
- }
- if (tmp.endsWith(u'>'))
- tmp += u' ';
- tmp += u'>';
- }
+ tmp += qualifiedInstantationName();
for (Indirection i : d->m_indirections)
tmp.append(indirectionKeyword(i));
diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h
index 9cd746e85..6f75b5737 100644
--- a/sources/shiboken6/ApiExtractor/parser/typeinfo.h
+++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h
@@ -39,6 +39,11 @@ public:
QStringList qualifiedName() const;
void setQualifiedName(const QStringList &qualified_name);
+ // Returns "std::list"
+ QString qualifiedNameString() const;
+ // Returns qualifiedName() with instantions ("std::list<int>")
+ QString qualifiedInstantationName() const;
+
void addName(const QString &);
bool isVoid() const;
diff --git a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h
index d704210f7..7b67647b9 100644
--- a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h
+++ b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h
@@ -5,6 +5,7 @@
#define SMARTPOINTERTYPEENTRY_H
#include "complextypeentry.h"
+#include "customconversion_typedefs.h"
class SmartPointerTypeEntryPrivate;
@@ -51,6 +52,10 @@ public:
QString getTargetName(const AbstractMetaType &metaType) const;
+ bool hasCustomConversion() const;
+ void setCustomConversion(const CustomConversionPtr &customConversion);
+ CustomConversionPtr customConversion() const;
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const override;
#endif
diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp
index 0820150f8..46e88291d 100644
--- a/sources/shiboken6/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken6/ApiExtractor/typesystem.cpp
@@ -2154,6 +2154,7 @@ public:
QString m_resetMethod;
SmartPointerTypeEntry::Instantiations m_instantiations;
TypeEntryCList m_excludedInstantiations;
+ CustomConversionPtr m_customConversion;
TypeSystem::SmartPointerType m_smartPointerType;
};
@@ -2306,6 +2307,24 @@ QString SmartPointerTypeEntry::getTargetName(const AbstractMetaType &metaType) c
return fixSmartPointerName(name);
}
+bool SmartPointerTypeEntry::hasCustomConversion() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return bool(d->m_customConversion);
+}
+
+void SmartPointerTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion)
+{
+ S_D(SmartPointerTypeEntry);
+ d->m_customConversion = customConversion;
+}
+
+CustomConversionPtr SmartPointerTypeEntry::customConversion() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_customConversion;
+}
+
// ----------------- NamespaceTypeEntry
class NamespaceTypeEntryPrivate : public ComplexTypeEntryPrivate
{
diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp
index 8b2ad08de..7ae25e48c 100644
--- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp
+++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp
@@ -2348,9 +2348,10 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &,
if (topElement != StackElement::ModifyArgument
&& topElement != StackElement::ValueTypeEntry
&& topElement != StackElement::PrimitiveTypeEntry
- && topElement != StackElement::ContainerTypeEntry) {
+ && topElement != StackElement::ContainerTypeEntry
+ && topElement != StackElement::SmartPointerTypeEntry) {
m_error = u"Conversion rules can only be specified for argument modification, "
- "value-type, primitive-type or container-type conversion."_s;
+ "value-type, primitive-type, or container-type or smartpointer-type conversion."_s;
return false;
}
@@ -2415,6 +2416,9 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &,
std::static_pointer_cast<ContainerTypeEntry>(top->entry)->setCustomConversion(customConversion);
else if (top->entry->isValue())
std::static_pointer_cast<ValueTypeEntry>(top->entry)->setCustomConversion(customConversion);
+ else if (top->entry->isSmartPointer())
+ std::static_pointer_cast<SmartPointerTypeEntry>(top->entry)->setCustomConversion(customConversion);
+
customConversionsForReview.append(customConversion);
return true;
}
diff --git a/sources/shiboken6/cmake/ShibokenHelpers.cmake b/sources/shiboken6/cmake/ShibokenHelpers.cmake
index bcaf31e89..c6414b2ca 100644
--- a/sources/shiboken6/cmake/ShibokenHelpers.cmake
+++ b/sources/shiboken6/cmake/ShibokenHelpers.cmake
@@ -869,28 +869,9 @@ endfunction()
# Get path to libclang.dll/libclang.so depending on the platform
macro(find_libclang)
- if(CMAKE_HOST_WIN32)
- set(libclang_directory_suffix "bin")
- set(libclang_suffix ".dll")
- else()
- set(libclang_directory_suffix "lib")
- if(CMAKE_HOST_APPLE)
- set(libclang_suffix ".dylib")
- else()
- set(libclang_suffix ".so")
- endif()
- endif()
-
- set(libclang_lib_dir "")
- if(DEFINED ENV{LLVM_INSTALL_DIR})
- set(libclang_lib_dir "$ENV{LLVM_INSTALL_DIR}/${libclang_directory_suffix}")
- elseif(DEFINED ENV{CLANG_INSTALL_DIR})
- set(libclang_lib_dir "$ENV{CLANG_INSTALL_DIR}/${libclang_directory_suffix}")
- else()
- message(WARNING
- "Couldn't find libclang${libclang_suffix} "
- "You will likely need to add it manually to PATH to ensure the build succeeds.")
- endif()
+ find_package(Clang CONFIG REQUIRED)
+ get_target_property(libclang_location libclang LOCATION)
+ get_filename_component(libclang_lib_dir "${libclang_location}" DIRECTORY)
endmacro()
# Allow setting a shiboken debug level from the the build system or from the environment
diff --git a/sources/shiboken6/doc/typesystem_conversionrule.rst b/sources/shiboken6/doc/typesystem_conversionrule.rst
index cee45bfb3..f6ce18345 100644
--- a/sources/shiboken6/doc/typesystem_conversionrule.rst
+++ b/sources/shiboken6/doc/typesystem_conversionrule.rst
@@ -12,9 +12,13 @@ The **conversion-rule** tag specifies how a **primitive-type**, a **container-ty
or a **value-type** may be converted to and from the native C++ language types to the
target language types (see also :ref:`user-defined-type-conversion`).
-It is a child of the :ref:`container-type`, :ref:`primitive-type` or
-:ref:`value-type` and may contain :ref:`native-to-target` or
-:ref:`native-to-target` child nodes.
+It may be a child of the :ref:`container-type` and :ref:`primitive-type` nodes,
+where conversions have to be provided for both directions using the
+:ref:`native-to-target` and :ref:`target-to-native` child nodes.
+
+It may also appear as a child of :ref:`value-type` or :ref:`smart-pointer-type`
+where additional conversions from other target language types can be provided
+using the :ref:`target-to-native` child node.
.. code-block:: xml
@@ -70,8 +74,9 @@ an input value an does what's needed to convert it to the output value.
</conversion-rule>
Use the replace node to modify the template code.
-Notice that the generator must provide type system variables for the input
-and output values and types, namely **%in**, **%out**, **%INTYPE** and
+Notice that the generator provides type system variables for the input
+and output values and types (see :ref:`converter_variables_and_functions`).
+The most important ones are **%in**, **%out**, **%INTYPE** and
**%OUTTYPE**. In the case of container types, **%INTYPE** refers to the
full container type (e.g. **"list<int>"**) and **%INTYPE_0**, **%INTYPE_1**,
**%INTYPE_#**, should be replaced by the types used in the container template
diff --git a/sources/shiboken6/doc/typesystem_converters.rst b/sources/shiboken6/doc/typesystem_converters.rst
index ab6fba930..f34f5b829 100644
--- a/sources/shiboken6/doc/typesystem_converters.rst
+++ b/sources/shiboken6/doc/typesystem_converters.rst
@@ -16,7 +16,8 @@ C++ and vice-versa.
// C++ class
struct Complex {
- Complex(double real, double imag);
+ explicit Complex(double real, double imag);
+
double real() const;
double imag() const;
};
@@ -82,8 +83,9 @@ Here's how to do it:
<!-- Code injection at module level. -->
<inject-code class="native" position="beginning">
- static bool Check2TupleOfNumbers(PyObject* pyIn) {
- if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2))
+ static bool Check2TupleOfNumbers(PyObject *pyIn)
+ {
+ if (PySequence_Check(pyIn) == 0 || PySequence_Size(pyIn) != 2)
return false;
Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0));
if (!PyNumber_Check(pyReal))
@@ -134,7 +136,8 @@ Container Conversions
Converters for :ref:`container-type <container-type>` are pretty much the same as for other type,
except that they make use of the type system variables
-:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>`.
+:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>` denoting the
+template parameters.
|project| combines the conversion code for containers with the conversion
defined (or automatically generated) for the containers.
@@ -147,13 +150,12 @@ defined (or automatically generated) for the containers.
<native-to-target>
PyObject* %out = PyDict_New();
- %INTYPE::const_iterator it = %in.begin();
- for (; it != %in.end(); ++it) {
- %INTYPE_0 key = it->first;
- %INTYPE_1 value = it->second;
- PyDict_SetItem(%out,
+ for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
+ const auto &amp;key = it->first;
+ const auto &amp;value = it->second;
+ PyDict_SetItem(%out,
%CONVERTTOPYTHON[%INTYPE_0](key),
- %CONVERTTOPYTHON[%INTYPE_1](value));
+ %CONVERTTOPYTHON[%INTYPE_1](value));
}
return %out;
</native-to-target>
@@ -161,8 +163,8 @@ defined (or automatically generated) for the containers.
<target-to-native>
<add-conversion type="PyDict">
- PyObject* key;
- PyObject* value;
+ PyObject *key{};
+ PyObject *value{};
Py_ssize_t pos = 0;
while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
%OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
@@ -183,10 +185,10 @@ defined (or automatically generated) for the containers.
For this case, a number of pre-defined conversion templates
are provided (see :ref:`predefined_templates`).
-.. _variables_and_functions:
+.. _converter_variables_and_functions:
-Variables & Functions
-=====================
+Converter Variables & Functions
+===============================
.. _in:
@@ -212,7 +214,7 @@ Variables & Functions
.. _intype_n:
**%INTYPE_#**
- Replaced by the name of the #th type used in a container.
+ Replaced by the name of the #th template parameter type used in a container.
.. _outtype:
@@ -225,7 +227,7 @@ Variables & Functions
.. _outtype_n:
**%OUTTYPE_#**
- Replaced by the name of the #th type used in a container.
+ Replaced by the name of the #th template parameter type used in a container.
.. _checktype:
diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
index c03d203b9..798ef5719 100644
--- a/sources/shiboken6/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
@@ -208,6 +208,9 @@ can be generated for them. Instead, an instance of the viewed class should
be instantiated and passed to functions using the view class
for argument types.
+It is also possible to specify template specializations
+like "std::optional<int>" as primitive types with converters.
+
See :ref:`predefined_templates` for built-in templates for standard type
conversion rules.
@@ -726,7 +729,8 @@ The ``smart pointer`` type node indicates that the given class is a smart pointe
and requires inserting calls to **getter** to access the pointeee.
Currently, the usage is limited to function return values.
**ref-count-method** specifies the name of the method used to do reference counting.
-It is a child of the :ref:`typesystem_details` node or other type nodes.
+It is a child of the :ref:`typesystem_details` node or other type nodes
+and may contain :ref:`conversion-rule` nodes.
The *optional* attribute **instantiations** specifies for which instantiations
of the smart pointer wrappers will be generated (comma-separated list).
diff --git a/sources/shiboken6/doc/typesystem_variables.rst b/sources/shiboken6/doc/typesystem_variables.rst
index 5eb5d5abe..6dfd1f801 100644
--- a/sources/shiboken6/doc/typesystem_variables.rst
+++ b/sources/shiboken6/doc/typesystem_variables.rst
@@ -16,6 +16,8 @@ implementation specifics.
Variables
=========
+In addition to the below listed variables, there are some variables specific to type
+conversion code (see :ref:`converter_variables_and_functions`).
.. _cpp_return_argument:
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 21e167b53..9092768a3 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -997,7 +997,7 @@ void CppGenerator::writeCacheResetNative(TextStream &s, const GeneratorContext &
{
s << "void " << classContext.wrapperName()
<< "::resetPyMethodCache()\n{\n" << indent
- << "std::fill_n(m_PyMethodCache, sizeof(m_PyMethodCache) / sizeof(m_PyMethodCache[0]), false);\n"
+ << "std::fill(m_PyMethodCache.begin(), m_PyMethodCache.end(), nullptr);\n"
<< outdent << "}\n\n";
}
@@ -2120,6 +2120,24 @@ void CppGenerator::writeCustomConverterRegister(TextStream &s,
}
}
+void CppGenerator::writeTemplateCustomConverterRegister(TextStream &s,
+ const AbstractMetaType &type,
+ QString converter)
+{
+ auto customConversion = CustomConversion::getCustomConversion(type.typeEntry());
+ if (!customConversion || customConversion->targetToNativeConversions().isEmpty())
+ return;
+ if (converter.isEmpty())
+ converter = converterVar;
+ const QString typeName = fixedCppTypeName(type);
+ for (const auto &conv : customConversion->targetToNativeConversions()) {
+ const QString &sourceTypeName = conv.sourceTypeName();
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName);
+ writeAddPythonToCppConversion(s, converter, toCpp, isConv);
+ }
+}
+
void CppGenerator::writeContainerConverterFunctions(TextStream &s,
const AbstractMetaType &containerType) const
{
@@ -3600,13 +3618,15 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
}
-void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const
+void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
+ const AbstractMetaType &templateType) const
{
- Q_ASSERT(containerType.typeEntry()->isContainer());
- const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
- const auto customConversion = cte->customConversion();
- for (const auto &conv : customConversion->targetToNativeConversions())
- writePythonToCppConversionFunction(s, containerType, conv);
+ const auto customConversion = CustomConversion::getCustomConversion(templateType.typeEntry());
+ if (customConversion) {
+ const auto &conversions = customConversion->targetToNativeConversions();
+ for (const auto &conv : conversions)
+ writePythonToCppConversionFunction(s, templateType, conv);
+ }
}
void CppGenerator::writePythonToCppConversionFunction(TextStream &s,
@@ -4438,8 +4458,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
s << '&' << targetTypeName << "_Type";
}
- const QString typeName = fixedCppTypeName(type);
- s << ", " << cppToPythonFunctionName(typeName, targetTypeName) << ");\n";
+ s << ", " << cppToPythonFunctionName(fixedCppTypeName(type), targetTypeName) << ");\n";
s << registerConverterName(cppSignature, converter);
if (usePySideExtensions() && cppSignature.startsWith("const "_L1)
@@ -4448,12 +4467,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
s << registerConverterName(underlyingType, converter);
}
- for (const auto &conv : typeEntry->customConversion()->targetToNativeConversions()) {
- const QString &sourceTypeName = conv.sourceTypeName();
- QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName);
- QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName);
- writeAddPythonToCppConversion(s, converter, toCpp, isConv);
- }
+ writeTemplateCustomConverterRegister(s, type, converter);
auto typedefItPair = api.typedefTargetToName().equal_range(type.cppSignature());
if (typedefItPair.first != typedefItPair.second) {
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h
index 0cf204234..441a9f781 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.h
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.h
@@ -114,6 +114,9 @@ private:
static void writeCustomConverterRegister(TextStream &s,
const CustomConversionPtr &customConversion,
const QString &converterVar);
+ static void writeTemplateCustomConverterRegister(TextStream &s,
+ const AbstractMetaType &type,
+ QString converter = {});
void writeContainerConverterFunctions(TextStream &s,
const AbstractMetaType &containerType) const;
@@ -361,9 +364,10 @@ private:
const TargetToNativeConversion &toNative,
const TypeEntryCPtr &targetType) const;
- /// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
+ /// Writes a pair of Python to C++ conversion and check functions for instantiated
+ /// template (smart pointer/container types).
void writePythonToCppConversionFunctions(TextStream &s,
- const AbstractMetaType &containerType) const;
+ const AbstractMetaType &templateType) const;
void writePythonToCppConversionFunction(TextStream &s,
const AbstractMetaType &containerType,
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
index 48c4ed5d2..1d3280e36 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
@@ -232,13 +232,16 @@ void CppGenerator::generateSmartPointerClass(TextStream &s,
void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s,
const AbstractMetaType &smartPointerType) const
{
+ auto smartPointerTypeEntry =
+ std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry());
+
+ if (smartPointerTypeEntry->hasCustomConversion())
+ writePythonToCppConversionFunctions(s, smartPointerType);
+
const auto baseClasses = findSmartPointeeBaseClasses(api(), smartPointerType);
if (baseClasses.isEmpty())
return;
- auto smartPointerTypeEntry =
- std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry());
-
// TODO: Missing conversion to smart pointer pointer type:
s << "// Register smartpointer conversion for all derived classes\n";
@@ -290,6 +293,8 @@ void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s,
writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv);
};
+ writeTemplateCustomConverterRegister(s, type);
+
const auto classes = findSmartPointeeBaseClasses(api(), type);
if (classes.isEmpty())
return;
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp
index 965d80dad..7616fa5c3 100644
--- a/sources/shiboken6/generator/shiboken/headergenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp
@@ -185,6 +185,7 @@ void HeaderGenerator::writeWrapperClass(TextStream &s,
for( const auto &includeGroup : includeGroups)
s << includeGroup;
}
+ s << "#include <sbkpython.h>\n\n#include <array>\n";
s << "namespace Shiboken { class AutoDecRef; class GilState; }\n\n";
@@ -288,9 +289,10 @@ void *qt_metacast(const char *_clname) override;
}
if (needsMethodCache) {
- s << "mutable bool m_PyMethodCache[" << maxOverrides << "] = {false";
+ s << "mutable std::array<PyObject *, " << maxOverrides
+ << "> m_PyMethodCache = {nullptr";
for (int i = 1; i < maxOverrides; ++i)
- s << ", false";
+ s << ", nullptr";
s << "};\n";
}
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
index 3e26b4605..039cd3085 100644
--- a/sources/shiboken6/libshiboken/basewrapper.cpp
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -21,6 +21,7 @@
#include "voidptr.h"
#include <algorithm>
+#include <cctype>
#include <cstddef>
#include <cstring>
#include <iostream>
@@ -786,32 +787,57 @@ static PyObject *overrideMethodName(PyObject *pySelf, const char *methodName,
// The virtual function call
PyObject *Sbk_GetPyOverride(const void *voidThis, PyTypeObject *typeObject,
Shiboken::GilState &gil, const char *funcName,
- bool &resultCache, PyObject **nameCache)
-{
- PyObject *pyOverride{};
- if (!resultCache) {
- gil.acquire();
- auto &bindingManager = Shiboken::BindingManager::instance();
- SbkObject *wrapper = bindingManager.retrieveWrapper(voidThis, typeObject);
- // The refcount can be 0 if the object is dieing and someone called
- // a virtual method from the destructor
- if (wrapper == nullptr)
- return nullptr;
- auto *pySelf = reinterpret_cast<PyObject *>(wrapper);
- if (Py_REFCNT(pySelf) == 0)
- return nullptr;
- PyObject *pyMethodName = overrideMethodName(pySelf, funcName, nameCache);
- pyOverride = Shiboken::BindingManager::getOverride(wrapper, pyMethodName);
- if (pyOverride == nullptr) {
- resultCache = true;
- gil.release();
- } else if (Shiboken::Errors::occurred() != nullptr) {
- // Give up.
- Py_XDECREF(pyOverride);
- pyOverride = nullptr;
- }
+ PyObject *&resultCache, PyObject **nameCache)
+{
+ if (Py_IsInitialized() == 0 || resultCache == Py_None)
+ return nullptr; // Bail out, execute C++ call (wrappers may outlive Python).
+
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ SbkObject *wrapper = bindingManager.retrieveWrapper(voidThis, typeObject);
+ // The refcount can be 0 if the object is dieing and someone called
+ // a virtual method from the destructor
+ if (wrapper == nullptr)
+ return nullptr;
+ auto *pySelf = reinterpret_cast<PyObject *>(wrapper);
+ if (Py_REFCNT(pySelf) == 0)
+ return nullptr;
+
+ gil.acquire();
+
+ if (resultCache != nullptr) // recreate the callable from function/self
+ return PepExt_Type_CallDescrGet(resultCache, pySelf, nullptr);
+
+ PyObject *pyMethodName = overrideMethodName(pySelf, funcName, nameCache);
+ auto *wrapper_dict = SbkObject_GetDict_NoRef(pySelf);
+
+ // Note: This special case was implemented for duck-punching, which happens
+ // in the instance dict. It does not work with properties.
+ // This is not cached to avoid leaking. FIXME PYSIDE 7: Remove (PYSIDE-2916)?
+ if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) {
+ Py_INCREF(method);
+ return method;
+ }
+
+ auto *pyOverride = Shiboken::BindingManager::getOverride(wrapper, pyMethodName);
+ if (pyOverride == nullptr) {
+ resultCache = Py_None;
+ Py_INCREF(resultCache);
+ gil.release();
+ return nullptr; // No override, execute C++ call
}
- return pyOverride;
+
+ if (Shiboken::Errors::occurred() != nullptr) {
+ // Give up.
+ Py_XDECREF(pyOverride);
+ resultCache = Py_None;
+ Py_INCREF(resultCache);
+ gil.release();
+ return nullptr; // // Give up.
+ }
+
+ resultCache = pyOverride;
+ // recreate the callable from function/self
+ return PepExt_Type_CallDescrGet(resultCache, pySelf, nullptr);
}
namespace
diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
index 9eea89540..426298bcf 100644
--- a/sources/shiboken6/libshiboken/basewrapper.h
+++ b/sources/shiboken6/libshiboken/basewrapper.h
@@ -123,9 +123,8 @@ LIBSHIBOKEN_API PyObject *Sbk_ReturnFromPython_Self(PyObject *self);
} // extern "C"
LIBSHIBOKEN_API PyObject *Sbk_GetPyOverride(const void *voidThis, PyTypeObject *typeObject,
- Shiboken::GilState &gil,
- const char *funcName, bool &resultCache,
- PyObject **nameCache);
+ Shiboken::GilState &gil, const char *funcName,
+ PyObject *&resultCache, PyObject **nameCache);
namespace Shiboken
{
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
index 25cc5c00a..ca509aefd 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -369,13 +369,6 @@ SbkObject *BindingManager::retrieveWrapper(const void *cptr, PyTypeObject *typeO
PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName)
{
auto *obWrapper = reinterpret_cast<PyObject *>(wrapper);
- auto *wrapper_dict = SbkObject_GetDict_NoRef(obWrapper);
- if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) {
- // Note: This special case was implemented for duck-punching, which happens
- // in the instance dict. It does not work with properties.
- Py_INCREF(method);
- return method;
- }
Shiboken::AutoDecRef method(PyObject_GetAttr(obWrapper, pyMethodName));
if (method.isNull())
@@ -387,9 +380,9 @@ PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName
// crude check for them.
// PYSIDE-535: This macro is redefined in a compatible way in pep384
if (PyMethod_Check(method) != 0) {
- if (PyMethod_GET_SELF(method) != obWrapper)
+ if (PyMethod_Self(method) != obWrapper)
return nullptr;
- function = PyMethod_GET_FUNCTION(method);
+ function = PyMethod_Function(method);
} else if (isCompiledMethod(method)) {
Shiboken::AutoDecRef im_self(PyObject_GetAttr(method, PyName::im_self()));
// Not retaining a reference inline with what PyMethod_GET_SELF does.
@@ -413,13 +406,13 @@ PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName
if (PyObject *defaultMethod = PyDict_GetItem(parentDict.object(), pyMethodName)) {
defaultFound = true;
if (function != defaultMethod)
- return method.release();
+ return function;
}
}
}
// PYSIDE-2255: If no default method was found, use the method.
if (!defaultFound)
- return method.release();
+ return function;
return nullptr;
}
diff --git a/sources/shiboken6/libshiboken/sbkconverter.cpp b/sources/shiboken6/libshiboken/sbkconverter.cpp
index 94bb1e2b4..1f79402b7 100644
--- a/sources/shiboken6/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken6/libshiboken/sbkconverter.cpp
@@ -451,8 +451,11 @@ void nonePythonToCppNullPtr(PyObject *, void *cppOut)
void *cppPointer(PyTypeObject *desiredType, SbkObject *pyIn)
{
assert(pyIn);
- if (!ObjectType::checkType(desiredType))
+ if (!ObjectType::checkType(desiredType)) {
+ std::cerr << __FUNCTION__ << ": Conversion to non SbkObject type " << desiredType->tp_name
+ << " requested, falling back to pass-through.\n";
return pyIn;
+ }
auto *inType = Py_TYPE(pyIn);
if (ObjectType::hasCast(inType))
return ObjectType::cast(inType, pyIn, desiredType);
@@ -485,8 +488,14 @@ static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void
assert(pyIn);
assert(cppOut);
PythonToCppFunc toCpp = IsPythonToCppConvertible(converter, pyIn);
- if (toCpp)
+ if (toCpp) {
toCpp(pyIn, cppOut);
+ } else {
+ std::cerr << __FUNCTION__ << ": Cannot copy-convert " << pyIn;
+ if (pyIn)
+ std::cerr << " (" << Py_TYPE(pyIn)->tp_name << ')';
+ std::cerr << " to C++.\n";
+ }
}
void pythonToCppCopy(PyTypeObject *type, PyObject *pyIn, void *cppOut)
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
index 3f83b0816..8eea431c3 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -30,6 +30,7 @@ from textwrap import dedent
from shibokensupport.signature.mapping import ellipsis, missing_optional_return, PlaceholderType
from shibokensupport.signature.parser import using_snake_case
from shibokensupport.signature import make_snake_case_name
+from collections.abc import Sequence, Iterable
DEFAULT_PARAM_KIND = inspect.Parameter.POSITIONAL_ONLY
@@ -134,9 +135,14 @@ _KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY # noqa E:201
_VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD # noqa E:201
_empty = inspect.Parameter.empty # noqa E:201
-
+# PYSIDE-3098: Iterable and Sequence can occur together in an overload.
+# This needs sorting in order of generality.
+# This happened in the NumPy support of PySide 6.10. Note that the ordering
+# of methods there is completely different and unrelated to this mypy sorting.
default_weights = {
typing.Any: 1000, # noqa E:241
+ Iterable: 500, # noqa E:241
+ Sequence: 400, # noqa E:241
bool: 101, # noqa E:241
int: 102, # noqa E:241
float: 103, # noqa E:241
@@ -346,6 +352,7 @@ def create_signature_union(props, key):
if last == _VAR_POSITIONAL:
kind = _KEYWORD_ONLY
if default is None:
+ ann = typing.Union[ann]
ann = typing.Optional[ann]
if default is not _empty and layout.ellipsis:
default = ellipsis
@@ -367,6 +374,7 @@ def create_signature_union(props, key):
ret_anno = annotations.get('return', _empty)
if ret_anno is not _empty and props["fullname"] in missing_optional_return:
+ ret_anno = typing.Union[ret_anno]
ret_anno = typing.Optional[ret_anno]
return inspect.Signature(params, return_annotation=ret_anno,
__validate_parameters__=False)
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
index c5dc44644..1031e0bb0 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
@@ -69,12 +69,12 @@ class Formatter(Writer):
backup = inspect.formatannotation
@classmethod
- def formatannotation(cls, annotation, base_module=None):
+ def formatannotation(cls, annotation, base_module=None, *args, **kwargs):
if getattr(annotation, '__module__', None) == 'typing':
# do not remove the prefix!
return repr(annotation)
# do the normal action.
- return cls.backup(annotation, base_module)
+ return cls.backup(annotation, base_module, *args, **kwargs)
@classmethod
def fix_typing_prefix(cls, signature):
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
index 2bb3c9a87..84cb15feb 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -509,6 +509,7 @@ def init_PySide6_QtCore():
"PySide6.QtCore.QUrl.ComponentFormattingOptions":
PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why???
"PyUnicode": typing.Text,
+ "QByteArray": typing.Union[PySide6.QtCore.QByteArray, bytes, bytearray, memoryview],
"QByteArrayView": PySide6.QtCore.QByteArray,
"Q_NULLPTR": None,
"QCalendar.Unspecified": PySide6.QtCore.QCalendar.Unspecified,
diff --git a/sources/shiboken6/tests/libsample/bucket.cpp b/sources/shiboken6/tests/libsample/bucket.cpp
index cafd382a9..43a32f414 100644
--- a/sources/shiboken6/tests/libsample/bucket.cpp
+++ b/sources/shiboken6/tests/libsample/bucket.cpp
@@ -40,15 +40,21 @@ bool Bucket::empty()
void Bucket::lock()
{
- m_locked = true;
- while (m_locked) {
- SLEEP(300);
+ bool expected = false;
+ if (m_locked.compare_exchange_strong(expected, true)) {
+ while (m_locked) {
+ SLEEP(300);
+ }
+ } else {
+ std::cerr << __FUNCTION__ << " Attempt to lock twice.\n";
}
}
void Bucket::unlock()
{
- m_locked = false;
+ bool expected = true;
+ if (!m_locked.compare_exchange_strong(expected, false))
+ std::cerr << __FUNCTION__ << " Attempt to unlock twice.\n";
}
bool Bucket::virtualBlockerMethod()
diff --git a/sources/shiboken6/tests/libsample/bucket.h b/sources/shiboken6/tests/libsample/bucket.h
index 73e8edd78..677069fe7 100644
--- a/sources/shiboken6/tests/libsample/bucket.h
+++ b/sources/shiboken6/tests/libsample/bucket.h
@@ -7,6 +7,7 @@
#include "libsamplemacros.h"
#include "objecttype.h"
+#include <atomic>
#include <list>
class ObjectType;
@@ -19,7 +20,7 @@ public:
int pop();
bool empty();
void lock();
- inline bool locked() { return m_locked; }
+ bool locked() { return m_locked.load(); }
void unlock();
virtual bool virtualBlockerMethod();
@@ -27,8 +28,7 @@ public:
private:
std::list<int> m_data;
-
- volatile bool m_locked = false;
+ std::atomic<bool> m_locked{false};
};
#endif // BUCKET_H
diff --git a/sources/shiboken6/tests/libsample/samplenamespace.cpp b/sources/shiboken6/tests/libsample/samplenamespace.cpp
index 18a18d28d..3836f43aa 100644
--- a/sources/shiboken6/tests/libsample/samplenamespace.cpp
+++ b/sources/shiboken6/tests/libsample/samplenamespace.cpp
@@ -97,6 +97,15 @@ int passReferenceToObjectType(const ObjectType &obj, int multiplier)
return obj.objectName().size() * multiplier;
}
+// Exercise specifying complete template specializations as primitive types.
+std::optional<long> optionalMultiply(const std::optional<long> &v1,
+ const std::optional<long> &v2)
+{
+ if (!v1.has_value() || !v2.has_value())
+ return std::nullopt;
+ return v1.value() * v2.value();
+}
+
int variableInNamespace = 42;
} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/libsample/samplenamespace.h b/sources/shiboken6/tests/libsample/samplenamespace.h
index 99a0787ee..63dc2f316 100644
--- a/sources/shiboken6/tests/libsample/samplenamespace.h
+++ b/sources/shiboken6/tests/libsample/samplenamespace.h
@@ -9,6 +9,7 @@
#include "point.h"
#include "objecttype.h"
+#include <optional>
#include <list>
// Anonymous global enum
@@ -157,6 +158,9 @@ LIBSAMPLE_API double passReferenceToValueType(const Point &point, double multipl
// Add a new signature on type system with only a ObjectType pointer as parameter.
LIBSAMPLE_API int passReferenceToObjectType(const ObjectType &obj, int multiplier);
+LIBSAMPLE_API std::optional<long> optionalMultiply(const std::optional<long> &v1,
+ const std::optional<long> &v2);
+
extern LIBSAMPLE_API int variableInNamespace;
} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/samplebinding/sample_test.py b/sources/shiboken6/tests/samplebinding/sample_test.py
index c003ad398..43b84d36e 100644
--- a/sources/shiboken6/tests/samplebinding/sample_test.py
+++ b/sources/shiboken6/tests/samplebinding/sample_test.py
@@ -79,6 +79,13 @@ class ModuleTest(unittest.TestCase):
mo2 = sample.MoveOnlyHandler.passMoveOnly(mo)
self.assertEqual(mo2.value(), v)
+ def testOptionalLong(self):
+ v1 = 2
+ v2 = 3
+ self.assertEqual(sample.SampleNamespace.optionalMultiply(v1, v2), 6)
+ self.assertIsNone(sample.SampleNamespace.optionalMultiply(v1, None))
+ self.assertIsNone(sample.SampleNamespace.optionalMultiply(None, v2))
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
index 3f1b2e96f..391a0804d 100644
--- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
@@ -120,6 +120,25 @@
</conversion-rule>
</primitive-type>
+ <primitive-type name="std::optional&lt;long&gt;" target-langapi-name="PyObject">
+ <conversion-rule>
+ <native-to-target>
+ if (!%in.has_value())
+ Py_RETURN_NONE;
+ return PyLong_FromLong(%in.value());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="Py_None">
+ SBK_UNUSED(%in)
+ %out = %OUTTYPE();
+ </add-conversion>
+ <add-conversion type="PyLong" check="PyLong_CheckExact(%in)">
+ %out = %OUTTYPE(PyLong_AsLong(%in));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
<value-type name="MoveOnly"/>
<object-type name="MoveOnlyHandler"/>