Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/glue/qtcore.cpp57
-rw-r--r--sources/pyside6/libpyside/CMakeLists.txt2
-rw-r--r--sources/pyside6/libpyside/pysidevariantutils.cpp212
-rw-r--r--sources/pyside6/libpyside/pysidevariantutils.h37
-rw-r--r--sources/pyside6/tests/QtCore/deepcopy_test.py6
-rw-r--r--sources/pyside6/tests/QtCore/repr_test.py6
-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/generator/shiboken/cppgenerator.cpp2
-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--testing/runner.py10
19 files changed, 423 insertions, 222 deletions
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/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/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/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/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/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/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 21e167b53..539094075 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";
}
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/testing/runner.py b/testing/runner.py
index ad1e01d65..4d96fdfc2 100644
--- a/testing/runner.py
+++ b/testing/runner.py
@@ -20,7 +20,7 @@ this_dir = os.path.dirname(this_file)
build_scripts_dir = os.path.abspath(os.path.join(this_dir, ".."))
sys.path.append(build_scripts_dir)
-from build_scripts.utils import detect_clang
+from build_scripts.utils import detect_clang # noqa: E402
class TestRunner:
@@ -78,11 +78,12 @@ class TestRunner:
Helper for _find_ctest() that finds the ctest binary in a build
system file (ninja, Makefile).
"""
- look_for = "--force-new-ctest-process"
+ # Looking for a command ending this way:
+ look_for = "\\ctest.exe" if "win32" in sys.platform else "/ctest"
line = None
with open(file_name) as makefile:
for line in makefile:
- if look_for in line:
+ if look_for in line and line.lstrip().startswith("COMMAND"):
break
else:
# We have probably forgotten to build the tests.
@@ -98,7 +99,8 @@ class TestRunner:
raise RuntimeError(msg)
# the ctest program is on the left to look_for
assert line, f"Did not find {look_for}"
- ctest = re.search(r'(\S+|"([^"]+)")\s+' + look_for, line).groups()
+ look = re.escape(look_for)
+ ctest = re.search(fr'(\S+{look}|"([^"]+{look})")', line).groups()
return ctest[1] or ctest[0]
def _find_ctest(self):