aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/tests/QtQml
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/tests/QtQml')
-rw-r--r--sources/pyside6/tests/QtQml/CMakeLists.txt37
-rw-r--r--sources/pyside6/tests/QtQml/ModuleType.qml8
-rw-r--r--sources/pyside6/tests/QtQml/QtQml.pyproject65
-rw-r--r--sources/pyside6/tests/QtQml/bug_1029.py43
-rw-r--r--sources/pyside6/tests/QtQml/bug_1029.qml18
-rw-r--r--sources/pyside6/tests/QtQml/bug_451.py93
-rw-r--r--sources/pyside6/tests/QtQml/bug_451.qml31
-rw-r--r--sources/pyside6/tests/QtQml/bug_456.py63
-rw-r--r--sources/pyside6/tests/QtQml/bug_456.qml36
-rw-r--r--sources/pyside6/tests/QtQml/bug_557.py28
-rw-r--r--sources/pyside6/tests/QtQml/bug_726.py63
-rw-r--r--sources/pyside6/tests/QtQml/bug_726.qml36
-rw-r--r--sources/pyside6/tests/QtQml/bug_814.py65
-rw-r--r--sources/pyside6/tests/QtQml/bug_814.qml13
-rw-r--r--sources/pyside6/tests/QtQml/bug_825.py80
-rw-r--r--sources/pyside6/tests/QtQml/bug_825.qml13
-rw-r--r--sources/pyside6/tests/QtQml/bug_825_old.py80
-rw-r--r--sources/pyside6/tests/QtQml/bug_847.py70
-rw-r--r--sources/pyside6/tests/QtQml/bug_847.qml37
-rw-r--r--sources/pyside6/tests/QtQml/bug_915.py40
-rw-r--r--sources/pyside6/tests/QtQml/bug_926.py57
-rw-r--r--sources/pyside6/tests/QtQml/bug_926.qml20
-rw-r--r--sources/pyside6/tests/QtQml/bug_951.py51
-rw-r--r--sources/pyside6/tests/QtQml/bug_951.qml10
-rw-r--r--sources/pyside6/tests/QtQml/bug_995.py31
-rw-r--r--sources/pyside6/tests/QtQml/bug_995.qml15
-rw-r--r--sources/pyside6/tests/QtQml/bug_997.py51
-rw-r--r--sources/pyside6/tests/QtQml/bug_997.qml13
-rw-r--r--sources/pyside6/tests/QtQml/connect_python_qml.py55
-rw-r--r--sources/pyside6/tests/QtQml/connect_python_qml.qml23
-rw-r--r--sources/pyside6/tests/QtQml/groupedproperty.py112
-rw-r--r--sources/pyside6/tests/QtQml/groupedproperty.qml9
-rw-r--r--sources/pyside6/tests/QtQml/hw.qml23
-rw-r--r--sources/pyside6/tests/QtQml/javascript_exceptions.py91
-rw-r--r--sources/pyside6/tests/QtQml/javascript_exceptions.qml28
-rw-r--r--sources/pyside6/tests/QtQml/listproperty.py136
-rw-r--r--sources/pyside6/tests/QtQml/listproperty.qml50
-rw-r--r--sources/pyside6/tests/QtQml/qmlregistertype_test.py53
-rw-r--r--sources/pyside6/tests/QtQml/qmlregistertype_test.qml7
-rw-r--r--sources/pyside6/tests/QtQml/qqmlapplicationengine.qml23
-rw-r--r--sources/pyside6/tests/QtQml/qqmlapplicationengine_test.py38
-rw-r--r--sources/pyside6/tests/QtQml/qqmlcomponent_test.py36
-rw-r--r--sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.py84
-rw-r--r--sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.qml42
-rw-r--r--sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile_component.qml10
-rw-r--r--sources/pyside6/tests/QtQml/qqmlnetwork_test.py76
-rw-r--r--sources/pyside6/tests/QtQml/qquickitem_grabToImage.py69
-rw-r--r--sources/pyside6/tests/QtQml/qquickitem_grabToImage.qml44
-rw-r--r--sources/pyside6/tests/QtQml/qquickview_test.py87
-rw-r--r--sources/pyside6/tests/QtQml/registerattached.py101
-rw-r--r--sources/pyside6/tests/QtQml/registerattached.qml20
-rw-r--r--sources/pyside6/tests/QtQml/registerextended.py74
-rw-r--r--sources/pyside6/tests/QtQml/registerextended.qml9
-rw-r--r--sources/pyside6/tests/QtQml/registerforeign.py52
-rw-r--r--sources/pyside6/tests/QtQml/registerforeign.qml8
-rw-r--r--sources/pyside6/tests/QtQml/registerparserstatus.py60
-rw-r--r--sources/pyside6/tests/QtQml/registerparserstatus.qml8
-rw-r--r--sources/pyside6/tests/QtQml/registerqmlfile.py30
-rw-r--r--sources/pyside6/tests/QtQml/registersingletontype.py152
-rw-r--r--sources/pyside6/tests/QtQml/registersingletontype.qml14
-rw-r--r--sources/pyside6/tests/QtQml/registertype.py116
-rw-r--r--sources/pyside6/tests/QtQml/registertype.qml32
-rw-r--r--sources/pyside6/tests/QtQml/registeruncreatable.qml13
-rw-r--r--sources/pyside6/tests/QtQml/registeruncreatabletype.py62
-rw-r--r--sources/pyside6/tests/QtQml/signal_arguments.py61
-rw-r--r--sources/pyside6/tests/QtQml/signal_arguments.qml36
-rw-r--r--sources/pyside6/tests/QtQml/signal_types.py124
-rw-r--r--sources/pyside6/tests/QtQml/signal_types.qml26
-rw-r--r--sources/pyside6/tests/QtQml/view.qml19
-rw-r--r--sources/pyside6/tests/QtQml/viewmodel.qml16
70 files changed, 3296 insertions, 0 deletions
diff --git a/sources/pyside6/tests/QtQml/CMakeLists.txt b/sources/pyside6/tests/QtQml/CMakeLists.txt
new file mode 100644
index 000000000..30bf7e786
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+PYSIDE_TEST(bug_451.py)
+PYSIDE_TEST(bug_456.py)
+PYSIDE_TEST(bug_557.py)
+PYSIDE_TEST(bug_726.py)
+PYSIDE_TEST(bug_814.py)
+PYSIDE_TEST(bug_825_old.py)
+PYSIDE_TEST(bug_825.py)
+PYSIDE_TEST(bug_847.py)
+PYSIDE_TEST(bug_915.py)
+PYSIDE_TEST(bug_926.py)
+PYSIDE_TEST(bug_951.py)
+PYSIDE_TEST(bug_995.py)
+PYSIDE_TEST(bug_997.py)
+PYSIDE_TEST(bug_1029.py)
+PYSIDE_TEST(groupedproperty.py)
+PYSIDE_TEST(listproperty.py)
+PYSIDE_TEST(qmlregistertype_test.py)
+PYSIDE_TEST(qqmlapplicationengine_test.py)
+PYSIDE_TEST(qqmlnetwork_test.py)
+PYSIDE_TEST(qqmlcomponent_test.py)
+PYSIDE_TEST(qquickview_test.py)
+PYSIDE_TEST(connect_python_qml.py)
+PYSIDE_TEST(registerattached.py)
+PYSIDE_TEST(registerextended.py)
+PYSIDE_TEST(registerparserstatus.py)
+PYSIDE_TEST(registertype.py)
+PYSIDE_TEST(registerforeign.py)
+PYSIDE_TEST(registerqmlfile.py)
+PYSIDE_TEST(registeruncreatabletype.py)
+PYSIDE_TEST(registersingletontype.py)
+PYSIDE_TEST(javascript_exceptions.py)
+PYSIDE_TEST(qqmlincubator_incubateWhile.py)
+PYSIDE_TEST(qquickitem_grabToImage.py)
+PYSIDE_TEST(signal_arguments.py)
diff --git a/sources/pyside6/tests/QtQml/ModuleType.qml b/sources/pyside6/tests/QtQml/ModuleType.qml
new file mode 100644
index 000000000..d7e5e653c
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/ModuleType.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQml
+
+QtObject {
+ objectName: "moduleType"
+}
diff --git a/sources/pyside6/tests/QtQml/QtQml.pyproject b/sources/pyside6/tests/QtQml/QtQml.pyproject
new file mode 100644
index 000000000..5a05c71a1
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/QtQml.pyproject
@@ -0,0 +1,65 @@
+{
+ "files": ["ModuleType.qml",
+ "bug_1029.py",
+ "bug_1029.qml",
+ "bug_451.py",
+ "bug_451.qml",
+ "bug_456.py",
+ "bug_456.qml",
+ "bug_557.py",
+ "bug_726.py",
+ "bug_726.qml",
+ "bug_814.py",
+ "bug_814.qml",
+ "bug_825.py",
+ "bug_825.qml",
+ "bug_847.py",
+ "bug_847.qml",
+ "bug_915.py",
+ "bug_926.py",
+ "bug_926.qml",
+ "bug_951.py",
+ "bug_951.qml",
+ "bug_995.py",
+ "bug_995.qml",
+ "bug_997.py",
+ "bug_997.qml",
+ "connect_python_qml.py",
+ "connect_python_qml.qml",
+ "groupedproperty.py",
+ "groupedproperty.qml",
+ "hw.qml",
+ "javascript_exceptions.py",
+ "javascript_exceptions.qml",
+ "listproperty.py",
+ "qqmlapplicationengine.qml",
+ "qqmlapplicationengine_test.py",
+ "qqmlincubator_incubateWhile.py",
+ "qqmlincubator_incubateWhile.qml",
+ "qqmlincubator_incubateWhile_component.qml",
+ "qqmlnetwork_test.py",
+ "qquickitem_grabToImage.py",
+ "qquickitem_grabToImage.qml",
+ "qquickview_test.py",
+ "registerattached.py",
+ "registerattached.qml",
+ "registerextended.py",
+ "registerextended.qml",
+ "registerforeign.py",
+ "registerforeign.qml",
+ "registerparserstatus.py",
+ "registerparserstatus.qml",
+ "registerqmlfile.py",
+ "registersingletontype.py",
+ "registersingletontype.qml",
+ "registertype.py",
+ "registertype.qml",
+ "registeruncreatable.qml",
+ "registeruncreatabletype.py",
+ "signal_arguments.py",
+ "signal_arguments.qml",
+ "signal_types.py",
+ "signal_types.qml",
+ "view.qml",
+ "viewmodel.qml"]
+}
diff --git a/sources/pyside6/tests/QtQml/bug_1029.py b/sources/pyside6/tests/QtQml/bug_1029.py
new file mode 100644
index 000000000..69ca5c18d
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_1029.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 QUrl
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import qmlRegisterType
+from PySide6.QtQuick import QQuickView, QQuickItem
+
+
+def register_qml_types():
+ class TestClass(QQuickItem):
+ def __init__(self, parent=None):
+ QQuickItem.__init__(self, parent)
+
+ qmlRegisterType(TestClass, "UserTypes", 1, 0, "TestClass")
+
+
+def main():
+ app = QGuiApplication([])
+
+ # reg qml types here
+ register_qml_types()
+
+ # force gc to run
+ gc.collect()
+
+ view = QQuickView()
+ url = QUrl(__file__.replace(".py", ".qml"))
+ view.setSource(url)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/sources/pyside6/tests/QtQml/bug_1029.qml b/sources/pyside6/tests/QtQml/bug_1029.qml
new file mode 100644
index 000000000..e4e95f865
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_1029.qml
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import UserTypes 1.0
+
+Rectangle
+{
+ width: 200
+ height: 200
+
+ color: "#ff0000"
+
+ TestClass
+ {
+
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_451.py b/sources/pyside6/tests/QtQml/bug_451.py
new file mode 100644
index 000000000..d81a99d94
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_451.py
@@ -0,0 +1,93 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''
+Test bug 451: http://bugs.openbossa.org/show_bug.cgi?id=451
+
+An archive of said bug:
+https://srinikom.github.io/pyside-bz-archive/451.html
+'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import QObject, QUrl, Property
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQuick import QQuickView
+from PySide6.QtQml import QmlElement
+
+
+QML_IMPORT_NAME = "test.PythonObject"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class PythonObject(QObject):
+ def __init__(self):
+ super().__init__(None)
+ self._called = ""
+ self._arg1 = None
+ self._arg2 = None
+
+ def setCalled(self, v):
+ self._called = v
+
+ def setArg1(self, v):
+ self._arg1 = v
+
+ def setArg2(self, v):
+ self._arg2 = v
+
+ def getCalled(self):
+ return self._called
+
+ def getArg1(self):
+ return self._arg1
+
+ def getArg2(self):
+ return self._arg2
+
+ called = Property(str, getCalled, setCalled)
+ arg1 = Property(int, getArg1, setArg1)
+ arg2 = Property('QVariant', getArg2, setArg2)
+
+
+class TestBug(unittest.TestCase):
+ def testQMLFunctionCall(self):
+ app = QGuiApplication(sys.argv)
+ view = QQuickView()
+
+ obj = PythonObject()
+ view.setInitialProperties({"python": obj})
+ file = Path(__file__).resolve().parent / 'bug_451.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root = view.rootObject()
+ self.assertTrue(root, quickview_errorstring(view))
+ root.simpleFunction()
+ self.assertEqual(obj.called, "simpleFunction")
+
+ root.oneArgFunction(42)
+ self.assertEqual(obj.called, "oneArgFunction")
+ self.assertEqual(obj.arg1, 42)
+
+ root.twoArgFunction(10, app)
+ self.assertEqual(obj.called, "twoArgFunction")
+ self.assertEqual(obj.arg1, 10)
+ self.assertEqual(obj.arg2, app)
+
+ rvalue = root.returnFunction()
+ self.assertEqual(obj.called, "returnFunction")
+ self.assertEqual(rvalue, 42)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_451.qml b/sources/pyside6/tests/QtQml/bug_451.qml
new file mode 100644
index 000000000..0867b861f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_451.qml
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import test.PythonObject 1.0
+
+Rectangle {
+ id: page
+ required property PythonObject python
+
+ function simpleFunction() {
+ python.called = "simpleFunction"
+ }
+
+ function oneArgFunction(x) {
+ python.called = "oneArgFunction"
+ python.arg1 = x
+ }
+
+ function twoArgFunction(x, y) {
+ python.called = "twoArgFunction"
+ python.arg1 = x
+ python.arg2 = y
+ }
+
+ function returnFunction() {
+ python.called = "returnFunction"
+ return 42
+ }
+
+}
diff --git a/sources/pyside6/tests/QtQml/bug_456.py b/sources/pyside6/tests/QtQml/bug_456.py
new file mode 100644
index 000000000..7743ee3fd
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_456.py
@@ -0,0 +1,63 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+from PySide6.QtCore import QObject, QTimer, QUrl, Property, Slot
+from PySide6.QtQuick import QQuickView
+from PySide6.QtQml import QmlElement
+
+QML_IMPORT_NAME = "test.RotateValue"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class RotateValue(QObject):
+ def __init__(self):
+ super().__init__()
+
+ @Slot(result=int)
+ def val(self):
+ return 100
+
+ def setRotation(self, v):
+ self._rotation = v
+
+ def getRotation(self):
+ return self._rotation
+
+ rotation = Property(int, getRotation, setRotation)
+
+
+class TestConnectionWithInvalidSignature(TimedQGuiApplication):
+
+ def testSlotRetur(self):
+ view = QQuickView()
+ rotatevalue = RotateValue()
+
+ timer = QTimer()
+ timer.start(2000)
+
+ view.setInitialProperties({"rotatevalue": rotatevalue})
+ file = Path(__file__).resolve().parent / 'bug_456.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root = view.rootObject()
+ self.assertTrue(root, quickview_errorstring(view))
+ button = root.findChild(QObject, "buttonMouseArea")
+ view.show()
+ button.entered.emit()
+ self.assertEqual(rotatevalue.rotation, 100)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_456.qml b/sources/pyside6/tests/QtQml/bug_456.qml
new file mode 100644
index 000000000..092cca325
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_456.qml
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import test.RotateValue 1.0
+
+Rectangle {
+ id: page
+
+ width: 500; height: 200
+ color: "lightgray"
+ required property RotateValue rotatevalue
+
+ Rectangle {
+ id: button
+ width: 150; height: 40
+ color: "darkgray"
+ anchors.horizontalCenter: page.horizontalCenter
+ y: 120
+ MouseArea {
+ id: buttonMouseArea
+ objectName: "buttonMouseArea"
+ anchors.fill: parent
+ onEntered: {
+ rotatevalue.rotation = rotatevalue.val()
+ }
+ }
+ Text {
+ id: buttonText
+ text: "Press me!"
+ anchors.horizontalCenter: button.horizontalCenter
+ anchors.verticalCenter: button.verticalCenter
+ font.pointSize: 16;
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_557.py b/sources/pyside6/tests/QtQml/bug_557.py
new file mode 100644
index 000000000..eb43973f6
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_557.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import adjust_filename
+
+from PySide6.QtCore import QUrl
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import QQmlEngine, QQmlComponent
+
+app = QGuiApplication(sys.argv)
+
+engine = QQmlEngine()
+component = QQmlComponent(engine)
+
+# This should segfault if the QDeclarativeComponent has not QQmlEngine
+file = Path(__file__).resolve().parent / 'foo.qml'
+assert (not file.is_file())
+component.loadUrl(QUrl.fromLocalFile(file))
+
diff --git a/sources/pyside6/tests/QtQml/bug_726.py b/sources/pyside6/tests/QtQml/bug_726.py
new file mode 100644
index 000000000..56c1e70f1
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_726.py
@@ -0,0 +1,63 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+from PySide6.QtCore import QObject, QUrl, Slot
+from PySide6.QtQuick import QQuickView
+from PySide6.QtQml import QmlElement
+
+QML_IMPORT_NAME = "test.ProxyObject"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class ProxyObject(QObject):
+ def __init__(self):
+ super().__init__()
+ self._o = None
+ self._receivedName = ""
+
+ @Slot(result='QObject*')
+ def getObject(self):
+ if self._o:
+ return self._o
+
+ self._o = QObject()
+ self._o.setObjectName("PySideObject")
+ return self._o
+
+ @Slot(str)
+ def receivedObject(self, name):
+ self._receivedName = name
+
+
+class TestConnectionWithInvalidSignature(TimedQGuiApplication):
+
+ def testSlotRetur(self):
+ view = QQuickView()
+ proxy = ProxyObject()
+
+ view.setInitialProperties({"proxy": proxy})
+ file = Path(__file__).resolve().parent / 'bug_726.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root = view.rootObject()
+ self.assertTrue(root, quickview_errorstring(view))
+ button = root.findChild(QObject, "buttonMouseArea")
+ view.show()
+ button.entered.emit()
+ self.assertEqual(proxy._receivedName, "PySideObject")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_726.qml b/sources/pyside6/tests/QtQml/bug_726.qml
new file mode 100644
index 000000000..f80c9cdda
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_726.qml
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import test.ProxyObject 1.0
+
+Rectangle {
+ id: page
+
+ width: 500; height: 200
+ color: "lightgray"
+ required property ProxyObject proxy
+
+ Rectangle {
+ id: button
+ width: 150; height: 40
+ color: "darkgray"
+ anchors.horizontalCenter: page.horizontalCenter
+ y: 120
+ MouseArea {
+ id: buttonMouseArea
+ objectName: "buttonMouseArea"
+ anchors.fill: parent
+ onEntered: {
+ proxy.receivedObject(proxy.getObject().objectName)
+ }
+ }
+ Text {
+ id: buttonText
+ text: "Press me!"
+ anchors.horizontalCenter: button.horizontalCenter
+ anchors.verticalCenter: button.verticalCenter
+ font.pointSize: 16;
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_814.py b/sources/pyside6/tests/QtQml/bug_814.py
new file mode 100644
index 000000000..0e7858b6c
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_814.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2011 Thomas Perl <m@thp.io>
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+# Test case for PySide bug 814
+# http://bugs.pyside.org/show_bug.cgi?id=814
+# archive:
+# https://srinikom.github.io/pyside-bz-archive/814.html
+# 2011-04-08 Thomas Perl <m@thp.io>
+# Released under the same terms as PySide itself
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtCore import QUrl, QAbstractListModel, QModelIndex, Qt
+from PySide6.QtQuick import QQuickView
+from PySide6.QtQml import QmlElement
+
+QML_IMPORT_NAME = "test.ListModel"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class ListModel(QAbstractListModel):
+ def __init__(self):
+ super().__init__()
+
+ def roleNames(self):
+ return {Qt.DisplayRole: b'pysideModelData'}
+
+ def rowCount(self, parent=QModelIndex()):
+ return 3
+
+ def data(self, index, role):
+ if index.isValid() and role == Qt.DisplayRole:
+ return 'blubb'
+ return None
+
+
+class TestBug814(TimedQGuiApplication):
+ def testAbstractItemModelTransferToQML(self):
+ view = QQuickView()
+ model = ListModel()
+ view.setInitialProperties({"pythonModel": model})
+ file = Path(__file__).resolve().parent / 'bug_814.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root = view.rootObject()
+ self.assertTrue(root, quickview_errorstring(view))
+ view.show()
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/sources/pyside6/tests/QtQml/bug_814.qml b/sources/pyside6/tests/QtQml/bug_814.qml
new file mode 100644
index 000000000..4331e424f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_814.qml
@@ -0,0 +1,13 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import test.ListModel 1.0
+
+ListView {
+ required property ListModel pythonModel
+ width: 300; height: 300
+ delegate: Text { text: pysideModelData }
+ model: pythonModel
+}
+
diff --git a/sources/pyside6/tests/QtQml/bug_825.py b/sources/pyside6/tests/QtQml/bug_825.py
new file mode 100644
index 000000000..a8bd304ec
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_825.py
@@ -0,0 +1,80 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""
+This is the corrected version for Python 3.
+Unfortunately, this touches a Python 3.8 error that was fixed late.
+"""
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import Qt, QUrl, QTimer
+from PySide6.QtGui import QGuiApplication, QPen
+from PySide6.QtWidgets import QGraphicsItem
+from PySide6.QtQml import qmlRegisterType
+from PySide6.QtQuick import QQuickView, QQuickItem, QQuickPaintedItem
+
+paintCalled = False
+
+
+class MetaA(type):
+ pass
+
+
+class A(object, metaclass=MetaA):
+ pass
+
+
+MetaB = type(QQuickPaintedItem)
+B = QQuickPaintedItem
+
+
+class MetaC(MetaA, MetaB):
+ pass
+
+
+class C(A, B, metaclass=MetaC):
+ pass
+
+
+class Bug825 (C):
+ def __init__(self, parent=None):
+ QQuickPaintedItem.__init__(self, parent)
+
+ def paint(self, painter):
+ global paintCalled
+ pen = QPen(Qt.black, 2)
+ painter.setPen(pen)
+ painter.drawPie(self.boundingRect(), 0, 128)
+ paintCalled = True
+
+
+class TestBug825 (unittest.TestCase):
+ def testIt(self):
+ global paintCalled
+ app = QGuiApplication([])
+ qmlRegisterType(Bug825, 'bugs', 1, 0, 'Bug825')
+ self.assertRaises(TypeError, qmlRegisterType, A, 'bugs', 1, 0, 'A')
+
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'bug_825.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+ QTimer.singleShot(250, view.close)
+ app.exec()
+ self.assertTrue(paintCalled)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_825.qml b/sources/pyside6/tests/QtQml/bug_825.qml
new file mode 100644
index 000000000..77c6b5014
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_825.qml
@@ -0,0 +1,13 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import bugs 1.0
+
+Item {
+ width: 300; height: 200
+
+ Bug825 {
+ anchors.fill: parent
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_825_old.py b/sources/pyside6/tests/QtQml/bug_825_old.py
new file mode 100644
index 000000000..c44fa75f4
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_825_old.py
@@ -0,0 +1,80 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""
+This is the now incorrect old version from Python 2.
+It happens to work in another way and will be retained.
+"""
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import Qt, QUrl, QTimer
+from PySide6.QtGui import QGuiApplication, QPen
+from PySide6.QtWidgets import QGraphicsItem
+from PySide6.QtQml import qmlRegisterType
+from PySide6.QtQuick import QQuickView, QQuickItem, QQuickPaintedItem
+
+paintCalled = False
+
+
+class MetaA(type):
+ pass
+
+
+class A(object):
+ __metaclass__ = MetaA
+
+
+MetaB = type(QQuickPaintedItem)
+B = QQuickPaintedItem
+
+
+class MetaC(MetaA, MetaB):
+ pass
+
+
+class C(A, B):
+ __metaclass__ = MetaC
+
+
+class Bug825 (C):
+ def __init__(self, parent=None):
+ QQuickPaintedItem.__init__(self, parent)
+
+ def paint(self, painter):
+ global paintCalled
+ pen = QPen(Qt.black, 2)
+ painter.setPen(pen)
+ painter.drawPie(self.boundingRect(), 0, 128)
+ paintCalled = True
+
+
+class TestBug825 (unittest.TestCase):
+ def testIt(self):
+ global paintCalled
+ app = QGuiApplication([])
+ qmlRegisterType(Bug825, 'bugs', 1, 0, 'Bug825')
+ self.assertRaises(TypeError, qmlRegisterType, A, 'bugs', 1, 0, 'A')
+
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'bug_825.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+ QTimer.singleShot(250, view.close)
+ app.exec()
+ self.assertTrue(paintCalled)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_847.py b/sources/pyside6/tests/QtQml/bug_847.py
new file mode 100644
index 000000000..947eb494e
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_847.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2011 Thomas Perl <m@thp.io>
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+# Testcase for PySide bug 847
+# Released under the same terms as PySide itself
+# 2011-05-04 Thomas Perl <m@thp.io>
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.usesqapplication import UsesQApplication
+
+from PySide6.QtCore import Slot, Signal, QUrl, QTimer, QCoreApplication
+from PySide6.QtQuick import QQuickView
+
+
+class View(QQuickView):
+ def __init__(self):
+ super().__init__()
+
+ called = Signal(int, int)
+
+ @Slot(int, int)
+ def blubb(self, x, y):
+ self.called.emit(x, y)
+
+
+class TestQML(UsesQApplication):
+ def done(self, x, y):
+ self._sucess = True
+ self.app.quit()
+ print("done called")
+
+ def testPythonSlot(self):
+ self._sucess = False
+ view = View()
+
+ # Connect first, then set the property.
+ view.called.connect(self.done)
+ file = Path(__file__).resolve().parent / 'bug_847.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ while view.status() == QQuickView.Loading:
+ self.app.processEvents()
+ self.assertEqual(view.status(), QQuickView.Ready)
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.rootObject().setProperty('pythonObject', view)
+
+ view.show()
+ while not view.isExposed():
+ self.app.processEvents()
+
+ # Essentially a timeout in case method invocation fails.
+ QTimer.singleShot(30000, QCoreApplication.instance().quit)
+ self.app.exec()
+ self.assertTrue(self._sucess)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/sources/pyside6/tests/QtQml/bug_847.qml b/sources/pyside6/tests/QtQml/bug_847.qml
new file mode 100644
index 000000000..18efd80ce
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_847.qml
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 500
+ height: 500
+ color: 'red'
+
+ property variant pythonObject: undefined
+
+ Text {
+ anchors.centerIn: parent
+ text: 'click me'
+ color: 'white'
+ }
+
+ onPythonObjectChanged: {
+ if (pythonObject) {
+ // Delay execution of method invocation, so that the event loop has a chance to start,
+ // which will subsequently be stopped by the method.
+ timer.start()
+ }
+ }
+
+ Timer {
+ id: timer
+ interval: 100; running: false;
+ onTriggered: {
+ if (pythonObject) {
+ pythonObject.blubb(42, 84)
+ }
+ }
+ }
+}
+
diff --git a/sources/pyside6/tests/QtQml/bug_915.py b/sources/pyside6/tests/QtQml/bug_915.py
new file mode 100644
index 000000000..3095eba2a
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_915.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtQuick import QQuickView, QQuickItem
+
+
+class TestBug915(TimedQGuiApplication):
+ def testReturnPolicy(self):
+ view = QQuickView()
+
+ item1 = QQuickItem()
+ item1.setObjectName("Item1")
+ item1.setParentItem(view.contentItem())
+ self.assertEqual(item1.objectName(), "Item1") # check if the item still valid
+
+ item2 = QQuickItem()
+ item2.setObjectName("Item2")
+ item2.setParentItem(view.contentItem())
+ item1 = None
+ self.assertEqual(item2.objectName(), "Item2") # check if the item still valid
+
+ view = None
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
diff --git a/sources/pyside6/tests/QtQml/bug_926.py b/sources/pyside6/tests/QtQml/bug_926.py
new file mode 100644
index 000000000..085e9a68f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_926.py
@@ -0,0 +1,57 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import sys
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import QUrl, QTimer, QObject, Signal, Property
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import qmlRegisterType
+from PySide6.QtQuick import QQuickView
+
+
+class MyClass (QObject):
+
+ def __init__(self):
+ super().__init__()
+ self.__url = QUrl()
+
+ def getUrl(self):
+ return self.__url
+
+ def setUrl(self, value):
+ newUrl = QUrl(value)
+ if (newUrl != self.__url):
+ self.__url = newUrl
+ self.urlChanged.emit()
+
+ urlChanged = Signal()
+ urla = Property(QUrl, getUrl, setUrl, notify=urlChanged)
+
+
+class TestBug926 (unittest.TestCase):
+ def testIt(self):
+ app = QGuiApplication([])
+ qmlRegisterType(MyClass, 'Example', 1, 0, 'MyClass')
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'bug_926.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+
+ view.show()
+ QTimer.singleShot(0, app.quit)
+ app.exec()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_926.qml b/sources/pyside6/tests/QtQml/bug_926.qml
new file mode 100644
index 000000000..6f7b608d0
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_926.qml
@@ -0,0 +1,20 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import Example 1.0
+
+Rectangle {
+ width: 100
+ height: 62
+
+ MyClass {
+ id: myClass
+ urla: "http://www.pyside.org"
+ }
+
+ Text {
+ id: name
+ text: myClass.urla
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_951.py b/sources/pyside6/tests/QtQml/bug_951.py
new file mode 100644
index 000000000..8a512d06f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_951.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtCore import QUrl
+from PySide6.QtQml import qmlRegisterType
+from PySide6.QtQuick import QQuickItem, QQuickView
+
+
+class MyItem(QQuickItem):
+ COMPONENT_COMPLETE_CALLED = False
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setObjectName("myitem")
+
+ def componentComplete(self):
+ MyItem.COMPONENT_COMPLETE_CALLED = True
+ super(MyItem, self).componentComplete()
+
+
+class TestRegisterQMLType(TimedQGuiApplication):
+ def setup(self):
+ super.setup(100 * 3) # 3s
+
+ def testSignalEmission(self):
+ qmlRegisterType(MyItem, "my.item", 1, 0, "MyItem")
+
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'bug_951.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+
+ self.app.exec()
+ self.assertTrue(MyItem.COMPONENT_COMPLETE_CALLED)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_951.qml b/sources/pyside6/tests/QtQml/bug_951.qml
new file mode 100644
index 000000000..02bf0c708
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_951.qml
@@ -0,0 +1,10 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import my.item 1.0
+Rectangle{
+ width:10
+ height:10
+ MyItem{ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_995.py b/sources/pyside6/tests/QtQml/bug_995.py
new file mode 100644
index 000000000..868c584e2
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_995.py
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import adjust_filename
+from helper.usesqapplication import UsesQApplication
+
+from PySide6.QtCore import QUrl
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQuick import QQuickView
+
+app = QGuiApplication([])
+file = Path(__file__).resolve().parent / 'bug_995.qml'
+assert (file.is_file())
+view = QQuickView(QUrl.fromLocalFile(file))
+view.show()
+view.resize(200, 200)
+contentItem = view.contentItem()
+item = contentItem.childAt(100, 100)
+
+# it CAN NOT crash here
+print(item)
+
diff --git a/sources/pyside6/tests/QtQml/bug_995.qml b/sources/pyside6/tests/QtQml/bug_995.qml
new file mode 100644
index 000000000..4f47cbd05
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_995.qml
@@ -0,0 +1,15 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 100
+ height: 100
+ color: "red"
+
+ Text {
+ text: "Hello World"
+ anchors.centerIn: parent
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/bug_997.py b/sources/pyside6/tests/QtQml/bug_997.py
new file mode 100644
index 000000000..501c221c3
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_997.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.usesqapplication import UsesQApplication
+from PySide6.QtCore import QCoreApplication, QTimer, QUrl, Slot
+from PySide6.QtQml import QQmlPropertyMap
+from PySide6.QtQuick import QQuickView
+
+
+class TestBug(UsesQApplication):
+
+ def setUp(self):
+ super().setUp()
+ self._complete = False
+
+ @Slot()
+ def complete(self):
+ self._complete = True
+ self.app.quit()
+
+ def testQMLFunctionCall(self):
+ ownerData = QQmlPropertyMap()
+ ownerData.insert('name', 'John Smith')
+ ownerData.insert('phone', '555-5555')
+ ownerData.insert('newValue', '')
+
+ self._view = QQuickView()
+ self._view.engine().quit.connect(self.complete)
+ self._view.setInitialProperties({'owner': ownerData})
+ file = Path(__file__).resolve().parent / 'bug_997.qml'
+ self.assertTrue(file.is_file())
+ self._view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(self._view.rootObject(), quickview_errorstring(self._view))
+ self._view.show()
+ if not self._complete:
+ self.app.exec()
+ self.assertEqual(ownerData.value('newName'), ownerData.value('name'))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/bug_997.qml b/sources/pyside6/tests/QtQml/bug_997.qml
new file mode 100644
index 000000000..23188f31f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/bug_997.qml
@@ -0,0 +1,13 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Text {
+ required property var owner
+ text: owner.name + " " + owner.phone
+ Component.onCompleted: {
+ owner.newName = owner.name
+ Qt.quit()
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/connect_python_qml.py b/sources/pyside6/tests/QtQml/connect_python_qml.py
new file mode 100644
index 000000000..2e60aec4f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/connect_python_qml.py
@@ -0,0 +1,55 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''
+Test case for bug #442
+
+archive:
+https://srinikom.github.io/pyside-bz-archive/442.html
+'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+from PySide6.QtCore import QObject, QUrl, SIGNAL
+from PySide6.QtGui import QColor
+from PySide6.QtQuick import QQuickItem, QQuickView
+
+
+class TestConnectionWithInvalidSignature(TimedQGuiApplication):
+ def onButtonClicked(self):
+ self.buttonClicked = True
+ self.app.quit()
+
+ def onButtonFailClicked(self):
+ pass
+
+ def testFailConnection(self):
+ self.buttonClicked = False
+ self.buttonFailClicked = False
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'connect_python_qml.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root = view.rootObject()
+ self.assertTrue(root, quickview_errorstring(view))
+ button = root.findChild(QObject, "buttonMouseArea")
+ self.assertRaises(TypeError, QObject.connect,
+ [button, SIGNAL('entered()'), self.onButtonFailClicked])
+ button.entered.connect(self.onButtonClicked)
+ button.entered.emit()
+ view.show()
+ self.app.exec()
+ self.assertTrue(self.buttonClicked)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/connect_python_qml.qml b/sources/pyside6/tests/QtQml/connect_python_qml.qml
new file mode 100644
index 000000000..1ed171e96
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/connect_python_qml.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Rectangle {
+ id: page
+ width: 500; height: 200
+ color: "lightgray"
+
+ Rectangle {
+ id: button
+ width: 150; height: 40
+ color: "darkgray"
+ anchors.horizontalCenter: page.horizontalCenter
+ y: 150
+ MouseArea {
+ id: buttonMouseArea
+ objectName: "buttonMouseArea"
+ anchors.fill: parent
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/groupedproperty.py b/sources/pyside6/tests/QtQml/groupedproperty.py
new file mode 100644
index 000000000..4554d4b31
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/groupedproperty.py
@@ -0,0 +1,112 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""Test grouped properties (PYSIDE-1836)."""
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 (QCoreApplication, QUrl, QObject, Property)
+from PySide6.QtQml import (QQmlComponent, QQmlEngine, QmlAnonymous, QmlElement)
+
+
+QML_IMPORT_NAME = "grouped"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlAnonymous
+class ShoeDescription(QObject):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._brand = ""
+ self._size = 0
+ self._price = 0
+
+ @Property(str)
+ def brand(self):
+ return self._brand
+
+ @brand.setter
+ def brand(self, b):
+ self._brand = b
+
+ @Property(int)
+ def size(self):
+ return self._size
+
+ @size.setter
+ def size(self, s):
+ self._size = s
+
+ @Property(int)
+ def price(self):
+ return self._price
+
+ @price.setter
+ def price(self, p):
+ self._price = p
+
+
+@QmlElement
+class Person(QObject):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._name = ""
+ self._shoe = ShoeDescription()
+
+ @Property(str)
+ def name(self):
+ return self._name
+
+ @name.setter
+ def name(self, n):
+ self._name = n
+
+ @Property(ShoeDescription)
+ def shoe(self):
+ return self._shoe
+
+
+def component_error(component):
+ result = ""
+ for e in component.errors():
+ if result:
+ result += "\n"
+ result += str(e)
+ return result
+
+
+class TestQmlGroupedProperties(unittest.TestCase):
+ def testIt(self):
+ app = QCoreApplication(sys.argv)
+ file = Path(__file__).resolve().parent / "groupedproperty.qml"
+ url = QUrl.fromLocalFile(file)
+ engine = QQmlEngine()
+ component = QQmlComponent(engine, url)
+ person = component.create()
+ self.assertTrue(person, component_error(component))
+
+ # Check the meta type of the property
+ meta_object = person.metaObject()
+ index = meta_object.indexOfProperty("shoe")
+ self.assertTrue(index > 0)
+ meta_property = meta_object.property(index)
+ meta_type = meta_property.metaType()
+ self.assertTrue(meta_type.isValid())
+
+ # Check the values
+ self.assertEqual(person.shoe.brand, "Bikey")
+ self.assertEqual(person.shoe.price, 90)
+ self.assertEqual(person.shoe.size, 12)
+
+ del engine
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/groupedproperty.qml b/sources/pyside6/tests/QtQml/groupedproperty.qml
new file mode 100644
index 000000000..d32bd6005
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/groupedproperty.qml
@@ -0,0 +1,9 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import grouped
+
+Person {
+ name: "Bob Jones"
+ shoe { size: 12; brand: "Bikey"; price: 90 }
+}
diff --git a/sources/pyside6/tests/QtQml/hw.qml b/sources/pyside6/tests/QtQml/hw.qml
new file mode 100644
index 000000000..723901d96
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/hw.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Rectangle {
+ id: page
+ width: 500; height: 200
+ color: "lightgray"
+
+ Text {
+ id: helloText
+ text: "Hello world!"
+ y: 30
+ anchors.horizontalCenter: page.horizontalCenter
+ font.pointSize: 24; font.bold: true
+ }
+
+ Image {
+ // It's okay for this to fail.
+ source: "http://localhost/logo.png"
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/javascript_exceptions.py b/sources/pyside6/tests/QtQml/javascript_exceptions.py
new file mode 100644
index 000000000..e2b530aaf
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/javascript_exceptions.py
@@ -0,0 +1,91 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.usesqapplication import UsesQApplication
+
+from PySide6.QtCore import Slot, Property, Signal, QObject, QUrl
+from PySide6.QtQml import QJSEngine, qmlRegisterType
+from PySide6.QtQuick import QQuickView
+
+test_error_message = "This is an error."
+
+method_test_string = """
+(function (obj) {
+ obj.methodThrows();
+})
+"""
+
+property_test_string = """
+(function (obj) {
+ obj.propertyThrows;
+})
+"""
+
+test_1 = False
+test_2 = False
+
+
+class TestClass(QObject):
+ @Slot()
+ def methodThrows(self):
+ raise TypeError(test_error_message)
+
+ @Property(str)
+ def propertyThrows(self):
+ raise TypeError(test_error_message)
+
+ @Slot(int)
+ def passTest(self, test):
+ global test_1, test_2
+
+ if test == 1:
+ test_1 = True
+ else:
+ test_2 = True
+
+
+class JavaScriptExceptionsTest(UsesQApplication):
+ def test_jsengine(self):
+ engine = QJSEngine()
+ test_object = TestClass()
+ test_value = engine.newQObject(test_object)
+
+ result_1 = engine.evaluate(method_test_string).call([test_value])
+
+ self.assertTrue(result_1.isError())
+ self.assertEqual(result_1.property('message').toString(), test_error_message)
+ self.assertEqual(result_1.property('name').toString(), 'TypeError')
+
+ result_2 = engine.evaluate(property_test_string).call([test_value])
+
+ self.assertTrue(result_2.isError())
+ self.assertEqual(result_2.property('message').toString(), test_error_message)
+ self.assertEqual(result_2.property('name').toString(), 'TypeError')
+
+ def test_qml_type(self):
+ qmlRegisterType(TestClass, 'JavaScriptExceptions', 1, 0, 'JavaScriptExceptions')
+
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'javascript_exceptions.qml'
+ self.assertTrue(file.is_file())
+ qml_url = QUrl.fromLocalFile(file)
+
+ view.setSource(qml_url)
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+
+ self.assertTrue(test_1)
+ self.assertTrue(test_2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/javascript_exceptions.qml b/sources/pyside6/tests/QtQml/javascript_exceptions.qml
new file mode 100644
index 000000000..1ab0fa3bb
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/javascript_exceptions.qml
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import QtQuick.Controls 2.0
+import JavaScriptExceptions 1.0
+
+Rectangle {
+ JavaScriptExceptions {
+ id: obj
+ }
+
+ Component.onCompleted: {
+ // Method call test
+ try {
+ obj.methodThrows();
+ } catch(e) {
+ obj.passTest(1);
+ }
+
+ // Property accessor test
+ try {
+ obj.propertyThrows;
+ } catch(e) {
+ obj.passTest(2);
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/listproperty.py b/sources/pyside6/tests/QtQml/listproperty.py
new file mode 100644
index 000000000..884600d29
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/listproperty.py
@@ -0,0 +1,136 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths # noqa: E402
+init_test_paths(False)
+
+from helper.usesqapplication import UsesQApplication # noqa: E402, F401
+
+from PySide6.QtCore import QObject, QUrl, Property, qInstallMessageHandler # noqa: E402
+from PySide6.QtQml import ListProperty, QmlElement # noqa: E402
+from PySide6.QtQuick import QQuickView # noqa: E402
+
+
+QML_IMPORT_NAME = "test.ListPropertyTest"
+QML_IMPORT_MAJOR_VERSION = 1
+
+output_messages = []
+
+
+def message_handler(mode, context, message):
+ global output_messages
+ output_messages.append(f"{message}")
+
+
+class InheritsQObject(QObject):
+ pass
+
+
+def dummyFunc():
+ pass
+
+
+@QmlElement
+class Person(QObject):
+ def __init__(self, parent=None):
+ super().__init__(parent=None)
+ self._name = ''
+ self._friends = []
+
+ def appendFriend(self, friend):
+ self._friends.append(friend)
+
+ def friendCount(self):
+ return len(self._friends)
+
+ def friend(self, index):
+ return self._friends[index]
+
+ def removeLastItem(self):
+ if len(self._friends) > 0:
+ self._friends.pop()
+
+ def replace(self, index, friend):
+ if 0 <= index < len(self._friends):
+ self._friends[index] = friend
+
+ def clear(self):
+ self._friends.clear()
+
+ @Property(str, final=True)
+ def name(self):
+ return self._name
+
+ @name.setter
+ def name(self, value):
+ self._name = value
+
+ friends = ListProperty(QObject, append=appendFriend, count=friendCount, at=friend,
+ removeLast=removeLastItem, replace=replace, clear=clear)
+
+
+class TestListProperty(UsesQApplication):
+ def testIt(self):
+
+ # Verify that type checking works properly
+ type_check_error = False
+
+ try:
+ ListProperty(QObject)
+ ListProperty(InheritsQObject)
+ except Exception:
+ type_check_error = True
+
+ self.assertFalse(type_check_error)
+
+ try:
+ ListProperty(int)
+ except TypeError:
+ type_check_error = True
+
+ self.assertTrue(type_check_error)
+
+ # Verify that method validation works properly
+ method_check_error = False
+
+ try:
+ ListProperty(QObject, append=None, at=None, count=None, replace=None, clear=None,
+ removeLast=None) # Explicitly setting None
+ ListProperty(QObject, append=dummyFunc)
+ ListProperty(QObject, count=dummyFunc, at=dummyFunc)
+ except Exception:
+ method_check_error = True
+
+ self.assertFalse(method_check_error)
+
+ try:
+ ListProperty(QObject, append=QObject())
+ except Exception:
+ method_check_error = True
+
+ self.assertTrue(method_check_error)
+
+ def testListPropParameters(self):
+ global output_messages
+ qInstallMessageHandler(message_handler)
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'listproperty.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ view.show()
+ self.assertEqual(output_messages[0], "List length: 3")
+ self.assertEqual(output_messages[1], "First element: Alice")
+ self.assertEqual(output_messages[2], "Removing last item: Charlie")
+ self.assertEqual(output_messages[3], "Replacing last item: Bob")
+ self.assertEqual(output_messages[4], "Replaced last item: David")
+ self.assertEqual(output_messages[5], "List length after clearing: 0")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/listproperty.qml b/sources/pyside6/tests/QtQml/listproperty.qml
new file mode 100644
index 000000000..7b71e30ba
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/listproperty.qml
@@ -0,0 +1,50 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick 2.0
+import test.ListPropertyTest
+
+Rectangle {
+ width: 360
+ height: 360
+
+ Person {
+ id: person
+ friends: [
+ Person{
+ name: "Alice"
+ },
+ Person{
+ name: "Bob"
+ },
+ Person{
+ name: "Charlie"
+ }
+ ]
+ }
+
+ Person{
+ id: david
+ name: "David"
+ }
+
+ Component.onCompleted: {
+ // Access the length of the list
+ console.log("List length: " + person.friends.length);
+
+ // Access the first element of the list
+ console.log("First element: " + person.friends[0].name);
+
+ // Remove the last item of the list
+ console.log("Removing last item: " + person.friends.pop().name);
+
+ // Repalce the last item of the list
+ console.log("Replacing last item: " + person.friends[person.friends.length - 1].name);
+ person.friends[person.friends.length - 1] = david;
+ console.log("Replaced last item: " + person.friends[person.friends.length - 1].name);
+
+ // Clear the list
+ person.friends = [];
+ console.log("List length after clearing: " + person.friends.length);
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/qmlregistertype_test.py b/sources/pyside6/tests/QtQml/qmlregistertype_test.py
new file mode 100644
index 000000000..0042d6fd3
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qmlregistertype_test.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.usesqapplication import UsesQApplication
+
+
+from PySide6.QtCore import QCoreApplication, QObject # noqa: F401
+from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterType
+
+
+class BaseClass(QObject):
+ def __init__(self, p=None):
+ super().__init__(p)
+
+
+class ChildClass(BaseClass):
+ def __init__(self, p=None):
+ super().__init__(p)
+
+
+class TestQmlRegisterType(UsesQApplication):
+ """Test the legacy QML register functions."""
+
+ def test(self):
+ qmlRegisterType(BaseClass, 'test', 1, 0, 'BaseClass')
+ qmlRegisterType(ChildClass, 'test', 1, 0, 'ChildClass')
+ # PYSIDE-2709: qmlRegisterType() would set additional class info
+ # on the meta objects for registration which caused another meta
+ # object to be created, breaking inheritance.
+ child = ChildClass()
+ base = BaseClass()
+ self.assertTrue(child.metaObject().inherits(base.metaObject()))
+
+ engine = QQmlApplicationEngine()
+ file = Path(__file__).resolve().parent / 'qmlregistertype_test.qml'
+
+ engine.load(file)
+ rootObjects = engine.rootObjects()
+ self.assertTrue(rootObjects)
+ self.assertTrue(type(rootObjects[0]), ChildClass)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qmlregistertype_test.qml b/sources/pyside6/tests/QtQml/qmlregistertype_test.qml
new file mode 100644
index 000000000..108bb84b1
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qmlregistertype_test.qml
@@ -0,0 +1,7 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import test
+
+ChildClass {
+}
diff --git a/sources/pyside6/tests/QtQml/qqmlapplicationengine.qml b/sources/pyside6/tests/QtQml/qqmlapplicationengine.qml
new file mode 100644
index 000000000..77149ecdc
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlapplicationengine.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Window
+
+Window {
+ width: 300
+ height: 200
+ visible: true
+
+ Item {
+ width: 200
+ height: 60
+ Text {
+ anchors {
+ verticalCenter: parent.verticalCenter;
+ horizontalCenter: parent.horizontalCenter;
+ }
+ text: "Text"
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/qqmlapplicationengine_test.py b/sources/pyside6/tests/QtQml/qqmlapplicationengine_test.py
new file mode 100644
index 000000000..ea54e9e25
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlapplicationengine_test.py
@@ -0,0 +1,38 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for QQmlApplicationEngine'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtCore import QUrl, QObject, QTimer, Qt
+from PySide6.QtQml import QQmlApplicationEngine
+
+
+class TestQQmlApplicationEngine(TimedQGuiApplication):
+
+ def testQQmlApplicationEngine(self):
+ engine = QQmlApplicationEngine()
+
+ qml_file_path = Path(__file__).resolve().parent / "qqmlapplicationengine.qml"
+
+ # PYSIDE-1736: load from a string.
+ engine.load(os.fspath(qml_file_path))
+ rootObjects = engine.rootObjects()
+ self.assertTrue(rootObjects)
+ window = rootObjects[0]
+ window.setTitle("TestQQmlApplicationEngine")
+ QTimer.singleShot(100, window.close)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qqmlcomponent_test.py b/sources/pyside6/tests/QtQml/qqmlcomponent_test.py
new file mode 100644
index 000000000..5521c64fa
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlcomponent_test.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 Property, QObject
+from PySide6.QtQml import QQmlComponent
+
+
+class WithComponent(QObject):
+ def get_component(self):
+ return None
+
+ component = Property(QQmlComponent, fget=get_component)
+
+
+class TestQmlSupport(unittest.TestCase):
+
+ def testMetatypeValid(self):
+ m = WithComponent.staticMetaObject
+ c = m.property(m.indexOfProperty("component"))
+
+ self.assertTrue(c.typeId() > 0)
+ self.assertTrue(c.typeName() == "QQmlComponent*")
+ self.assertTrue(c.metaType().isValid())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.py b/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.py
new file mode 100644
index 000000000..12a73e398
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import QObject, QUrl, Slot, QTimer
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import QQmlIncubationController, VolatileBool
+from PySide6.QtQuick import QQuickView
+
+
+class CustomIncubationController(QObject, QQmlIncubationController):
+ def __init__(self, test):
+ QObject.__init__(self)
+ QQmlIncubationController.__init__(self)
+ self.test = test
+ self.interrupted = False
+
+ # Incubate every 50 milliseconds
+ self.startTimer(50)
+ self.incubationShouldContinue = VolatileBool(True)
+ self.test.assertEqual(self.incubationShouldContinue.get(), True)
+
+ @Slot()
+ def interrupter(self):
+ if not self.interrupted:
+ self.interrupted = True
+ self.incubationShouldContinue.set(False)
+ self.test.assertEqual(self.incubationShouldContinue.get(), False)
+ QTimer.singleShot(0, QGuiApplication.instance().quit)
+
+ def timerEvent(self, ev):
+ # Incubate items for 2000 milliseconds, or until the volatile bool is set to false.
+ self.incubateWhile(self.incubationShouldContinue, 2000)
+
+
+class TestBug(unittest.TestCase):
+ def testIncubateWhileCall(self):
+ app = QGuiApplication(sys.argv)
+ view = QQuickView()
+ controller = CustomIncubationController(self)
+ view.engine().setIncubationController(controller)
+ view.setResizeMode(QQuickView.SizeRootObjectToView)
+ file = Path(__file__).resolve().parent / 'qqmlincubator_incubateWhile.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+
+ root = view.rootObject()
+ # The QML code will issue an interrupt signal after half of its items are loaded.
+ root.shouldInterrupt.connect(controller.interrupter)
+ res = app.exec()
+
+ itemsToCreate = root.property("itemsToCreate")
+ loadedItems = root.property("loadedItems")
+ self.assertEqual(loadedItems, itemsToCreate / 2)
+
+ # Finish incubating the remaining items.
+ controller.incubateFor(1000)
+ loadedItems = root.property("loadedItems")
+ self.assertEqual(loadedItems, itemsToCreate)
+
+ # Deleting the view before it goes out of scope is required to make sure all child QML
+ # instances are destroyed in the correct order.
+ del view
+ del app
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.qml b/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.qml
new file mode 100644
index 000000000..803dec128
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+import QtQuick 2.0
+
+
+Rectangle {
+ id: root
+ objectName: "theNicestRoot"
+ width: 400; height: 400
+
+ signal shouldInterrupt()
+ property int loadedItems: 0
+ property int itemsToCreate: 10
+
+ Row {
+ anchors.centerIn: parent
+ spacing: 20
+
+ Rectangle {
+ id: initialRectangle
+ width: 10; height: 10
+ color: "red"
+ }
+
+ Repeater {
+ model: itemsToCreate
+ Loader {
+ id: loader
+ asynchronous: true
+ source: "qqmlincubator_incubateWhile_component.qml"
+ onLoaded: {
+ root.loadedItems += 1
+
+ // Interrupt incubation after half of the items are loaded.
+ if (root.loadedItems >= (itemsToCreate / 2)) {
+ root.shouldInterrupt()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile_component.qml b/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile_component.qml
new file mode 100644
index 000000000..0f6693952
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlincubator_incubateWhile_component.qml
@@ -0,0 +1,10 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 10; height: 10
+ color: "yellow"
+}
diff --git a/sources/pyside6/tests/QtQml/qqmlnetwork_test.py b/sources/pyside6/tests/QtQml/qqmlnetwork_test.py
new file mode 100644
index 000000000..abdb4529e
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qqmlnetwork_test.py
@@ -0,0 +1,76 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for QQmlNetwork'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 QUrl, QTimer
+from PySide6.QtGui import QGuiApplication, QWindow
+from PySide6.QtQuick import QQuickView
+from PySide6.QtQml import QQmlNetworkAccessManagerFactory
+from PySide6.QtNetwork import QNetworkAccessManager
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+
+request_created = False
+
+
+def check_done():
+ global request_created
+ if request_created:
+ windows = QGuiApplication.topLevelWindows()
+ if windows:
+ windows[0].close()
+
+
+class CustomManager(QNetworkAccessManager):
+ """CustomManager (running in a different thread)"""
+ def createRequest(self, op, req, data=None):
+ global request_created
+ print(">> createRequest ", self, op, req.url(), data)
+ request_created = True
+ return QNetworkAccessManager.createRequest(self, op, req, data)
+
+
+class CustomFactory(QQmlNetworkAccessManagerFactory):
+ def create(self, parent=None):
+ return CustomManager()
+
+
+class TestQQmlNetworkFactory(TimedQGuiApplication):
+ def setUp(self):
+ super().setUp(timeout=2000)
+
+ def testQQuickNetworkFactory(self):
+ view = QQuickView()
+ self.factory = CustomFactory()
+ view.engine().setNetworkAccessManagerFactory(self.factory)
+
+ file = Path(__file__).resolve().parent / 'hw.qml'
+ self.assertTrue(file.is_file())
+ url = QUrl.fromLocalFile(file)
+
+ view.setSource(url)
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+
+ self.assertEqual(view.status(), QQuickView.Ready)
+
+ timer = QTimer()
+ timer.timeout.connect(check_done)
+ timer.start(50)
+ self.app.exec()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qquickitem_grabToImage.py b/sources/pyside6/tests/QtQml/qquickitem_grabToImage.py
new file mode 100644
index 000000000..25341b0b2
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qquickitem_grabToImage.py
@@ -0,0 +1,69 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+from PySide6.QtCore import QTimer, QUrl
+from PySide6.QtGui import QColor
+from PySide6.QtQuick import QQuickItem, QQuickView
+
+
+class TestGrabToSharedPointerImage(TimedQGuiApplication):
+ def setUp(self):
+ super().setUp(1000)
+
+ def testQQuickItemGrabToImageSharedPointer(self):
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'qquickitem_grabToImage.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+
+ # Get the QQuickItem objects for the blue Rectangle and the Image item.
+ root = view.rootObject()
+ blueRectangle = root.findChild(QQuickItem, "blueRectangle")
+ imageContainer = root.findChild(QQuickItem, "imageContainer")
+
+ # Start the image grabbing.
+ grabResultSharedPtr = blueRectangle.grabToImage()
+
+ # Implicit call of operator bool() of the smart pointer, to check that it holds
+ # a valid pointer.
+ self.assertTrue(grabResultSharedPtr)
+
+ self.grabbedColor = None
+
+ def onGrabReady():
+ # Signal early exit.
+ QTimer.singleShot(50, self.app.quit)
+
+ # Show the grabbed image in the QML Image item.
+ imageContainer.setProperty("source", grabResultSharedPtr.url())
+
+ # Wait for signal when grabbing is complete.
+ grabResultSharedPtr.ready.connect(onGrabReady)
+ self.app.exec()
+
+ # Get the first pixel color of the grabbed image.
+ self.image = grabResultSharedPtr.image()
+ self.assertTrue(self.image)
+ self.grabbedColor = self.image.pixelColor(0, 0)
+ self.assertTrue(self.grabbedColor.isValid())
+
+ # Compare the grabbed color with the one we set in the rectangle.
+ blueColor = QColor("blue")
+ self.assertEqual(self.grabbedColor, blueColor)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qquickitem_grabToImage.qml b/sources/pyside6/tests/QtQml/qquickitem_grabToImage.qml
new file mode 100644
index 000000000..90235f078
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qquickitem_grabToImage.qml
@@ -0,0 +1,44 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 600
+ height: 600
+
+ Rectangle {
+ id: blue
+ objectName: "blueRectangle"
+ width: 200
+ height: 200
+ anchors.top: root.top
+ anchors.horizontalCenter: root.horizontalCenter
+ color: "blue"
+ }
+
+ Text {
+ text: qsTr("Original blue rectangle")
+ anchors.left: blue.right
+ anchors.verticalCenter: blue.verticalCenter
+ }
+
+ Image {
+ id: imageContainer
+ objectName: "imageContainer"
+ width: 200
+ height: 200
+ anchors.bottom: root.bottom
+ anchors.horizontalCenter: root.horizontalCenter
+ }
+
+ Text {
+ text: qsTr("Image with the source URL set to the result of calling QQuickItem::grabToImage on the rectangle. If you see a second blue rectangle, that means it works.")
+ anchors.left: imageContainer.right
+ anchors.verticalCenter: imageContainer.verticalCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ width: 200
+ }
+
+}
diff --git a/sources/pyside6/tests/QtQml/qquickview_test.py b/sources/pyside6/tests/QtQml/qquickview_test.py
new file mode 100644
index 000000000..226509669
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/qquickview_test.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for QQuickView'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtCore import QUrl, QObject, Property, Slot, Signal
+from PySide6.QtQml import QQmlEngine, QQmlContext
+from PySide6.QtQuick import QQuickView
+
+
+class MyObject(QObject):
+ titleChanged = Signal()
+
+ def __init__(self, text, parent=None):
+ QObject.__init__(self, parent)
+ self._text = text
+
+ def getText(self):
+ return self._text
+
+ @Slot(str)
+ def qmlText(self, text):
+ self._qmlText = text
+
+ title = Property(str, getText, notify=titleChanged)
+
+
+class TestQQuickView(TimedQGuiApplication):
+
+ def testQQuickViewList(self):
+ view = QQuickView()
+
+ dataList = ["Item 1", "Item 2", "Item 3", "Item 4"]
+
+ view.setInitialProperties({"model": dataList})
+
+ file = Path(__file__).resolve().parent / 'view.qml'
+ self.assertTrue(file.is_file())
+ url = QUrl.fromLocalFile(file)
+ view.setSource(url)
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+
+ self.assertEqual(view.status(), QQuickView.Ready)
+ rootObject = view.rootObject()
+ self.assertTrue(rootObject)
+ context = QQmlEngine.contextForObject(rootObject)
+ self.assertTrue(context)
+ self.assertTrue(context.engine())
+
+ test_context = QQmlContext(context) # Context properties, PYSIDE-1921
+ prop_pair = QQmlContext.PropertyPair()
+ prop_pair.name = "testProperty"
+ prop_pair.value = 42
+ test_context.setContextProperties([prop_pair])
+ self.assertTrue(test_context.contextProperty("testProperty"), 42)
+
+ def testModelExport(self):
+ view = QQuickView()
+ dataList = [MyObject("Item 1"), MyObject("Item 2"), MyObject("Item 3"), MyObject("Item 4")]
+
+ view.setInitialProperties({"model": dataList})
+
+ file = Path(__file__).resolve().parent / 'viewmodel.qml'
+ self.assertTrue(file.is_file())
+ url = QUrl.fromLocalFile(file)
+ view.setSource(url)
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.show()
+
+ self.assertEqual(view.status(), QQuickView.Ready)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registerattached.py b/sources/pyside6/tests/QtQml/registerattached.py
new file mode 100644
index 000000000..dd300dc89
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerattached.py
@@ -0,0 +1,101 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 (QCoreApplication, QUrl, QObject, Property)
+from PySide6.QtQml import (QQmlComponent, QQmlEngine, QmlAnonymous,
+ QmlAttached, QmlElement, ListProperty,
+ qmlAttachedPropertiesObject)
+
+
+QML_IMPORT_NAME = "TestLayouts"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+EXPECTED_MARGINS = [10, 20]
+
+
+def component_error(component):
+ result = ""
+ for e in component.errors():
+ if result:
+ result += "\n"
+ result += str(e)
+ return result
+
+
+@QmlAnonymous
+class TestLayoutAttached(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._leftMargin = 0
+
+ @Property(int)
+ def leftMargin(self):
+ return self._leftMargin
+
+ @leftMargin.setter
+ def leftMargin(self, m):
+ self._leftMargin = m
+
+
+@QmlElement
+class TestWidget(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+
+@QmlElement
+@QmlAttached(TestLayoutAttached)
+class TestLayout(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._widgets = []
+
+ def widget(self, n):
+ return self._widgets[n]
+
+ def widgetCount(self):
+ return len(self._widgets)
+
+ def addWidget(self, w):
+ self._widgets.append(w)
+
+ @staticmethod
+ def qmlAttachedProperties(self, o):
+ return TestLayoutAttached(o)
+
+ widgets = ListProperty(TestWidget, addWidget)
+
+
+class TestQmlAttached(unittest.TestCase):
+ def testIt(self):
+ app = QCoreApplication(sys.argv)
+ file = Path(__file__).resolve().parent / 'registerattached.qml'
+ url = QUrl.fromLocalFile(file)
+ engine = QQmlEngine()
+ component = QQmlComponent(engine, url)
+ layout = component.create()
+ self.assertTrue(layout, component_error(component))
+
+ actual_margins = []
+ for i in range(layout.widgetCount()):
+ w = layout.widget(i)
+ a = qmlAttachedPropertiesObject(TestLayout, w, False)
+ actual_margins.append(a.leftMargin)
+ self.assertEqual(EXPECTED_MARGINS, actual_margins)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registerattached.qml b/sources/pyside6/tests/QtQml/registerattached.qml
new file mode 100644
index 000000000..7ae8730bd
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerattached.qml
@@ -0,0 +1,20 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import TestLayouts
+
+TestLayout {
+ id: layout
+
+ widgets: [
+ TestWidget {
+ id: widget1
+ TestLayout.leftMargin: 10
+ },
+
+ TestWidget {
+ id: widget2
+ TestLayout.leftMargin: 20
+ }
+ ]
+}
diff --git a/sources/pyside6/tests/QtQml/registerextended.py b/sources/pyside6/tests/QtQml/registerextended.py
new file mode 100644
index 000000000..b87b5aaaf
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerextended.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 (QCoreApplication, QUrl, QObject,
+ Property)
+from PySide6.QtQml import (QQmlComponent, QQmlEngine, QmlExtended,
+ QmlElement)
+
+
+"""Test for the QmlExtended decorator. Extends a class TestWidget
+ by a property leftMargin through a TestExtension and verifies the setting."""
+
+
+QML_IMPORT_NAME = "TestExtension"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+def component_error(component):
+ result = ""
+ for e in component.errors():
+ if result:
+ result += "\n"
+ result += str(e)
+ return result
+
+
+class TestExtension(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._leftMargin = 0
+
+ @Property(int)
+ def leftMargin(self):
+ return self._leftMargin
+
+ @leftMargin.setter
+ def leftMargin(self, m):
+ self._leftMargin = m
+
+
+@QmlElement
+@QmlExtended(TestExtension)
+class TestWidget(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+
+class TestQmlExtended(unittest.TestCase):
+ def testIt(self):
+ app = QCoreApplication(sys.argv)
+ file = Path(__file__).resolve().parent / 'registerextended.qml'
+ url = QUrl.fromLocalFile(file)
+ engine = QQmlEngine()
+ component = QQmlComponent(engine, url)
+ widget = component.create()
+ self.assertTrue(widget, component_error(component))
+ extension = widget.findChild(TestExtension)
+ self.assertTrue(extension)
+ self.assertEqual(extension.leftMargin, 10)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registerextended.qml b/sources/pyside6/tests/QtQml/registerextended.qml
new file mode 100644
index 000000000..74095f83f
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerextended.qml
@@ -0,0 +1,9 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import TestExtension
+
+TestWidget {
+ id: widget1
+ leftMargin: 10
+}
diff --git a/sources/pyside6/tests/QtQml/registerforeign.py b/sources/pyside6/tests/QtQml/registerforeign.py
new file mode 100644
index 000000000..d9a982d95
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerforeign.py
@@ -0,0 +1,52 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import qmlcomponent_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtCore import Property, QObject, QUrl, qVersion
+from PySide6.QtGui import QGuiApplication, QRasterWindow
+from PySide6.QtQml import (QmlNamedElement, QmlForeign, QQmlEngine,
+ QQmlComponent)
+
+
+"""Test the QmlForeign decorator, letting the QQmlEngine create a QRasterWindow."""
+
+
+QML_IMPORT_NAME = "Foreign"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlNamedElement("QRasterWindow")
+@QmlForeign(QRasterWindow)
+class RasterWindowForeign(QObject):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+
+class TestQmlForeign(TimedQGuiApplication):
+
+ def testIt(self):
+ engine = QQmlEngine()
+ file = Path(__file__).resolve().parent / 'registerforeign.qml'
+ self.assertTrue(file.is_file())
+ component = QQmlComponent(engine, QUrl.fromLocalFile(file))
+ window = component.create()
+ self.assertTrue(window, qmlcomponent_errorstring(component))
+ self.assertEqual(type(window), QRasterWindow)
+ window.setTitle(f"Qt {qVersion()}")
+ window.show()
+ self.app.exec()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registerforeign.qml b/sources/pyside6/tests/QtQml/registerforeign.qml
new file mode 100644
index 000000000..0537abb7c
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerforeign.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import Foreign
+
+QRasterWindow {
+ id: rasterWindow
+}
diff --git a/sources/pyside6/tests/QtQml/registerparserstatus.py b/sources/pyside6/tests/QtQml/registerparserstatus.py
new file mode 100644
index 000000000..bbcc14635
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerparserstatus.py
@@ -0,0 +1,60 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 (QCoreApplication, QUrl)
+from PySide6.QtQml import (QQmlComponent, QQmlEngine,
+ QmlElement, QPyQmlParserStatus)
+
+
+QML_IMPORT_NAME = "ParserStatus"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+def component_error(component):
+ result = ""
+ for e in component.errors():
+ if result:
+ result += "\n"
+ result += str(e)
+ return result
+
+
+@QmlElement
+class TestItem(QPyQmlParserStatus):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.component_complete_called = False
+ self.class_begin_called = False
+
+ def componentComplete(self):
+ self.component_complete_called = True
+
+ def classBegin(self):
+ self.class_begin_called = True
+
+
+class TestQmlAttached(unittest.TestCase):
+ def testIt(self):
+ app = QCoreApplication(sys.argv)
+ file = Path(__file__).resolve().parent / 'registerparserstatus.qml'
+ url = QUrl.fromLocalFile(file)
+ engine = QQmlEngine()
+ component = QQmlComponent(engine, url)
+ item = component.create()
+ self.assertTrue(item, component_error(component))
+ self.assertTrue(item.component_complete_called)
+ self.assertTrue(item.class_begin_called)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registerparserstatus.qml b/sources/pyside6/tests/QtQml/registerparserstatus.qml
new file mode 100644
index 000000000..a39f03227
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerparserstatus.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import ParserStatus
+
+TestItem {
+ id: item
+}
diff --git a/sources/pyside6/tests/QtQml/registerqmlfile.py b/sources/pyside6/tests/QtQml/registerqmlfile.py
new file mode 100644
index 000000000..335652e5d
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registerqmlfile.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+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 QDir, QUrl
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import qmlRegisterType
+
+
+class TestQmlSupport(unittest.TestCase):
+
+ def testIt(self):
+ app = QGuiApplication([])
+
+ file = os.fspath(Path(__file__).resolve().parent / 'ModuleType.qml')
+ url = QUrl.fromLocalFile(QDir.fromNativeSeparators(file))
+ result = qmlRegisterType(url, "CustomModule", 1, 0, "ModuleType")
+ self.assertTrue(result != -1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registersingletontype.py b/sources/pyside6/tests/QtQml/registersingletontype.py
new file mode 100644
index 000000000..6beca1131
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registersingletontype.py
@@ -0,0 +1,152 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject, Slot
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import (qmlRegisterSingletonType, qmlRegisterSingletonInstance,
+ QmlElement, QmlSingleton, QJSValue)
+from PySide6.QtQuick import QQuickView
+
+
+URI = "Singletons"
+
+
+finalResult = 0
+qObjectQmlTypeId = 0
+
+
+class SingletonQObject(QObject):
+ def __init__(self, parent=None):
+ QObject.__init__(self, parent)
+ self._data = 100
+
+ def getData(self):
+ return self._data
+
+ def setData(self, data):
+ global finalResult
+ finalResult = self._data = data
+
+ data = Property(int, getData, setData)
+
+
+def singletonQObjectCallback(engine):
+ obj = SingletonQObject()
+ obj.setData(50)
+ return obj
+
+
+def singletonQJSValueCallback(engine):
+ return engine.evaluate("new Object({data: 50})")
+
+
+QML_IMPORT_NAME = URI
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@QmlSingleton
+class DecoratedSingletonQObject(QObject):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._data = 200
+
+ def getData(self):
+ return self._data
+
+ def setData(self, data):
+ self._data = data
+
+ data = Property(int, getData, setData)
+
+
+@QmlElement
+@QmlSingleton
+class DecoratedSingletonWithCreate(QObject):
+ def __init__(self, data, parent=None):
+ super().__init__(parent)
+ self._data = data
+
+ @staticmethod
+ def create(engine):
+ return DecoratedSingletonWithCreate(400)
+
+ def getData(self):
+ return self._data
+
+ def setData(self, data):
+ self._data = data
+
+ data = Property(int, getData, setData)
+
+
+class TestQuickView(QQuickView):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._singleton_instance_qobject_int = False
+ self._singleton_instance_qobject_str = False
+ self._singleton_instance_jsvalue_int = False
+
+ @Slot()
+ def testSlot(self):
+ engine = self.engine()
+ instance = engine.singletonInstance(qObjectQmlTypeId)
+ if instance is not None and isinstance(instance, QObject):
+ self._singleton_instance_qobject_int = True
+ instance = engine.singletonInstance(URI, 'SingletonQObjectNoCallback')
+ if instance is not None and isinstance(instance, QObject):
+ self._singleton_instance_qobject_str = True
+ instance = engine.singletonInstance(URI, 'SingletonQJSValue')
+ if instance is not None and isinstance(instance, QJSValue):
+ self._singleton_instance_jsvalue_int = True
+ self.close()
+
+
+class TestQmlSupport(unittest.TestCase):
+ def testIt(self):
+ app = QGuiApplication([])
+
+ qObjectQmlTypeId = qmlRegisterSingletonType(SingletonQObject, URI, 1, 0,
+ 'SingletonQObjectNoCallback')
+ qmlRegisterSingletonType(SingletonQObject, URI, 1, 0, 'SingletonQObjectCallback',
+ singletonQObjectCallback)
+
+ qmlRegisterSingletonType(URI, 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
+
+ # Accepts only QObject derived types
+ l = [1, 2]
+ with self.assertRaises(TypeError):
+ qmlRegisterSingletonInstance(SingletonQObject, URI, 1, 0, 'SingletonInstance', l)
+
+ # Modify value on the instance
+ s = SingletonQObject()
+ s.setData(99)
+ qmlRegisterSingletonInstance(SingletonQObject, URI, 1, 0, 'SingletonInstance', s)
+
+ view = TestQuickView()
+ file = Path(__file__).resolve().parent / 'registersingletontype.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ self.assertTrue(view.rootObject(), quickview_errorstring(view))
+ view.resize(200, 200)
+ view.show()
+ QTimer.singleShot(250, view.testSlot)
+ app.exec()
+ self.assertEqual(finalResult, 899)
+ self.assertTrue(view._singleton_instance_qobject_int)
+ self.assertTrue(view._singleton_instance_qobject_str)
+ self.assertTrue(view._singleton_instance_jsvalue_int)
+
+
+if __name__ == '__main__': unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registersingletontype.qml b/sources/pyside6/tests/QtQml/registersingletontype.qml
new file mode 100644
index 000000000..31ca7fe4d
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registersingletontype.qml
@@ -0,0 +1,14 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import Singletons 1.0
+
+Item {
+ Component.onCompleted: {
+ SingletonQObjectCallback.data += SingletonQObjectNoCallback.data
+ + SingletonQJSValue.data
+ + SingletonInstance.data
+ + DecoratedSingletonQObject.data + DecoratedSingletonWithCreate.data;
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/registertype.py b/sources/pyside6/tests/QtQml/registertype.py
new file mode 100644
index 000000000..6c9874f32
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registertype.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+
+from PySide6.QtCore import Property, QObject, QTimer, QUrl
+from PySide6.QtGui import QGuiApplication, QPen, QColor, QPainter
+from PySide6.QtQml import (qjsEngine, qmlContext, qmlEngine, qmlRegisterType,
+ ListProperty, QmlElement, QmlNamedElement)
+from PySide6.QtQuick import QQuickView, QQuickItem, QQuickPaintedItem
+
+
+QML_IMPORT_NAME = "Charts"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class PieSlice (QQuickPaintedItem):
+ def __init__(self, parent=None):
+ QQuickPaintedItem.__init__(self, parent)
+ self._color = QColor()
+ self._fromAngle = 0
+ self._angleSpan = 0
+
+ def getColor(self):
+ return self._color
+
+ def setColor(self, value):
+ self._color = value
+
+ def getFromAngle(self):
+ return self._angle
+
+ def setFromAngle(self, value):
+ self._fromAngle = value
+
+ def getAngleSpan(self):
+ return self._angleSpan
+
+ def setAngleSpan(self, value):
+ self._angleSpan = value
+
+ color = Property(QColor, getColor, setColor)
+ fromAngle = Property(int, getFromAngle, setFromAngle)
+ angleSpan = Property(int, getAngleSpan, setAngleSpan)
+
+ def paint(self, painter):
+ global paintCalled
+ pen = QPen(self._color, 2)
+ painter.setPen(pen)
+ painter.setRenderHints(QPainter.Antialiasing, True)
+ painter.drawPie(self.boundingRect(), self._fromAngle * 16, self._angleSpan * 16)
+ paintCalled = True
+
+
+@QmlNamedElement("PieChart")
+class PieChartOriginalName(QQuickItem):
+ def __init__(self, parent=None):
+ QQuickItem.__init__(self, parent)
+ self._name = ''
+ self._slices = []
+
+ def getName(self):
+ return self._name
+
+ def setName(self, value):
+ self._name = value
+
+ name = Property(str, getName, setName)
+
+ def appendSlice(self, _slice):
+ global appendCalled
+ _slice.setParentItem(self)
+ self._slices.append(_slice)
+ appendCalled = True
+
+ slices = ListProperty(PieSlice, append=appendSlice)
+
+
+appendCalled = False
+paintCalled = False
+
+
+class TestQmlSupport(unittest.TestCase):
+
+ def testIt(self):
+ app = QGuiApplication([])
+
+ view = QQuickView()
+ file = Path(__file__).resolve().parent / 'registertype.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root_object = view.rootObject()
+ self.assertTrue(root_object, quickview_errorstring(view))
+ self.assertTrue(qjsEngine(root_object))
+ self.assertEqual(qmlEngine(root_object), view.engine())
+ self.assertTrue(qmlContext(root_object))
+
+ view.show()
+ QTimer.singleShot(250, view.close)
+ app.exec()
+ self.assertTrue(appendCalled)
+ self.assertTrue(paintCalled)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registertype.qml b/sources/pyside6/tests/QtQml/registertype.qml
new file mode 100644
index 000000000..3be2f9f04
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registertype.qml
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import Charts 1.0
+
+Item {
+ width: 300; height: 200
+
+ PieChart {
+ anchors.centerIn: parent
+ width: 100; height: 100
+
+ slices: [
+ PieSlice {
+ anchors.fill: parent
+ color: "red"
+ fromAngle: 0; angleSpan: 110
+ },
+ PieSlice {
+ anchors.fill: parent
+ color: "black"
+ fromAngle: 110; angleSpan: 50
+ },
+ PieSlice {
+ anchors.fill: parent
+ color: "blue"
+ fromAngle: 160; angleSpan: 100
+ }
+ ]
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/registeruncreatable.qml b/sources/pyside6/tests/QtQml/registeruncreatable.qml
new file mode 100644
index 000000000..b121c014d
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registeruncreatable.qml
@@ -0,0 +1,13 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import Charts 1.0
+
+Item {
+ width: 300; height: 200
+
+ Uncreatable {
+ name : 'uncreatable'
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/registeruncreatabletype.py b/sources/pyside6/tests/QtQml/registeruncreatabletype.py
new file mode 100644
index 000000000..3a4df69f6
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/registeruncreatabletype.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import qmlcomponent_errorstring
+
+from PySide6.QtCore import Property, QObject, QUrl
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import QmlElement, QmlUncreatable, QQmlEngine, QQmlComponent
+
+noCreationReason = 'Cannot create an item of type: Uncreatable (expected)'
+
+QML_IMPORT_NAME = "Charts"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@QmlUncreatable(noCreationReason)
+class Uncreatable(QObject):
+ def __init__(self, parent=None):
+ QObject.__init__(self, parent)
+ self._name = 'uncreatable'
+
+ def getName(self):
+ return self._name
+
+ def setName(self, value):
+ self._name = value
+
+ name = Property(str, getName, setName)
+
+
+class TestQmlSupport(unittest.TestCase):
+
+ def testIt(self):
+ app = QGuiApplication([])
+
+ engine = QQmlEngine()
+ file = Path(__file__).resolve().parent / 'registeruncreatable.qml'
+ self.assertTrue(file.is_file())
+ component = QQmlComponent(engine, QUrl.fromLocalFile(file))
+
+ # Check that the uncreatable item produces the correct error
+ self.assertEqual(component.status(), QQmlComponent.Error)
+ errorFound = False
+ for e in component.errors():
+ if noCreationReason in e.toString():
+ errorFound = True
+ break
+ self.assertTrue(errorFound)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/signal_arguments.py b/sources/pyside6/tests/QtQml/signal_arguments.py
new file mode 100644
index 000000000..f5b0f8bd3
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/signal_arguments.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtQuick import QQuickView
+from PySide6.QtCore import QObject, Signal, Slot, QUrl, QTimer, Property
+from PySide6.QtQml import QmlElement
+
+QML_IMPORT_NAME = "test.Obj"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class Obj(QObject):
+ def __init__(self):
+ super().__init__()
+ self.value = 0
+
+ sumResult = Signal(int, name="sumResult", arguments=['sum'])
+
+ @Slot(int, int)
+ def sum(self, arg1, arg2):
+ self.sumResult.emit(arg1 + arg2)
+
+ @Slot(str)
+ def sendValue(self, s):
+ self.value = int(s)
+
+
+class TestConnectionWithQml(TimedQGuiApplication):
+
+ def testSignalArguments(self):
+ view = QQuickView()
+ obj = Obj()
+
+ view.setInitialProperties({"o": obj})
+ file = Path(__file__).resolve().parent / 'signal_arguments.qml'
+ self.assertTrue(file.is_file())
+ view.setSource(QUrl.fromLocalFile(file))
+ root = view.rootObject()
+ self.assertTrue(root, quickview_errorstring(view))
+ button = root.findChild(QObject, "button")
+ self.assertTrue(button)
+ view.show()
+ button.clicked.emit()
+ self.assertEqual(obj.value, 42)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/signal_arguments.qml b/sources/pyside6/tests/QtQml/signal_arguments.qml
new file mode 100644
index 000000000..dbc991c77
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/signal_arguments.qml
@@ -0,0 +1,36 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+import QtQuick 2.5
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.2
+import test.Obj 1.0
+
+Rectangle {
+ visible: true
+ required property Obj o
+ GridLayout {
+ Button {
+ id: button
+ objectName: "button"
+ text: "sum!"
+ onClicked: {
+ o.sum(40, 2)
+ }
+ }
+ Text {
+ id: sumResultText
+ }
+ }
+ Connections {
+ target: o
+ function onSumResult(sum) {
+ // set the value on the Qml side
+ sumResultText.text = sum
+ // set internal Python value from the already
+ // modified value
+ o.sendValue(sumResultText.text)
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/signal_types.py b/sources/pyside6/tests/QtQml/signal_types.py
new file mode 100644
index 000000000..240c0fd6e
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/signal_types.py
@@ -0,0 +1,124 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import json
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import quickview_errorstring
+from helper.timedqguiapplication import TimedQGuiApplication
+
+from PySide6.QtQuick import QQuickView
+from PySide6.QtCore import QObject, Signal, Slot, QUrl
+from PySide6.QtQml import QmlElement
+
+"""PYSIDE-2098: Roundtrip test for signals using QVariantList/QVariantMap.
+
+@QmlElement Obj has signals of list/dict type which are connected to an
+instance of Connections in QML. The QML instance sends them back to Obj's
+slots and additionally sends them back as stringified JSON. This verifies that
+a conversion is done instead of falling back to the default PyObject
+passthrough converter, resulting in a QVariant<PyObject> and reference leaks
+on the PyObject.
+"""
+
+QML_IMPORT_NAME = "test.Obj"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class Obj(QObject):
+ listSignal = Signal(list)
+ dictSignal = Signal(dict)
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._last_data = None
+ self._last_json_data = None
+
+ def clear(self):
+ self._last_data = None
+ self._last_json_data = None
+
+ def last_data(self):
+ """Last data received."""
+ return self._last_data
+
+ def last_json_data(self):
+ """Last data converted from JSON."""
+ return self._last_json_data
+
+ def emit_list(self, test_list):
+ self.listSignal.emit(test_list)
+
+ def emit_dict(self, test_dict):
+ self.dictSignal.emit(test_dict)
+
+ @Slot(list)
+ def list_slot(self, l):
+ self._last_data = l
+ print("list_slot", l)
+
+ @Slot(dict)
+ def dict_slot(self, d):
+ self._last_data = d
+ print("dict_slot", d)
+
+ @Slot(str)
+ def json_slot(self, s):
+ self._last_json_data = json.loads(s)
+ print(f'json_slot "{s}"->', self._last_json_data)
+
+
+class TestConnectionWithQml(TimedQGuiApplication):
+
+ def setUp(self):
+ super().setUp()
+ self._view = QQuickView()
+ self._obj = Obj()
+
+ self._view.setInitialProperties({"o": self._obj})
+ file = Path(__file__).resolve().parent / "signal_types.qml"
+ self.assertTrue(file.is_file())
+ self._view.setSource(QUrl.fromLocalFile(file))
+ root = self._view.rootObject()
+ self.assertTrue(root, quickview_errorstring(self._view))
+
+ def tearDown(self):
+ super().tearDown()
+ del self._view
+ self._view = None
+
+ def testVariantList(self):
+ self._obj.clear()
+ test_list = [1, 2]
+ before_refcount = sys.getrefcount(test_list)
+ self._obj.emit_list(test_list)
+ received = self._obj.last_data()
+ self.assertTrue(isinstance(received, list))
+ self.assertEqual(test_list, received)
+ self.assertEqual(test_list, self._obj.last_json_data())
+ refcount = sys.getrefcount(test_list)
+ self.assertEqual(before_refcount, refcount)
+
+ def testVariantDict(self):
+ self._obj.clear()
+ test_dict = {"1": 1, "2": 2}
+ before_refcount = sys.getrefcount(test_dict)
+ self._obj.emit_dict(test_dict)
+ received = self._obj.last_data()
+ self.assertTrue(isinstance(received, dict))
+ self.assertEqual(test_dict, received)
+ self.assertEqual(test_dict, self._obj.last_json_data())
+ refcount = sys.getrefcount(test_dict)
+ self.assertEqual(before_refcount, refcount)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sources/pyside6/tests/QtQml/signal_types.qml b/sources/pyside6/tests/QtQml/signal_types.qml
new file mode 100644
index 000000000..6b03b3abd
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/signal_types.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import test.Obj
+
+Rectangle {
+ visible: true
+ required property Obj o
+
+ Connections {
+ target: o
+ function onListSignal(list) {
+ var json_data = JSON.stringify(list)
+ console.log("Connections.onListSignal: " + typeof(list) + " " + json_data)
+ o.list_slot(list)
+ o.json_slot(json_data)
+ }
+ function onDictSignal(dict) {
+ var json_data = JSON.stringify(dict)
+ console.log("Connections.onDictSignal: " + typeof(dict) + " " + json_data)
+ o.dict_slot(dict)
+ o.json_slot(json_data)
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/view.qml b/sources/pyside6/tests/QtQml/view.qml
new file mode 100644
index 000000000..8557271c2
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/view.qml
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ anchors.fill: parent
+ model: myModel
+ delegate: Component {
+ Rectangle {
+ required property string modelData
+ height: 25
+ width: 100
+ Text { text: modelData }
+ }
+ }
+}
diff --git a/sources/pyside6/tests/QtQml/viewmodel.qml b/sources/pyside6/tests/QtQml/viewmodel.qml
new file mode 100644
index 000000000..33db6072e
--- /dev/null
+++ b/sources/pyside6/tests/QtQml/viewmodel.qml
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+
+ListView {
+ width: 100; height: 100
+ anchors.fill: parent
+
+ delegate: Rectangle {
+ height: 25
+ width: 100
+ Text { text: model.modelData.title }
+ }
+}
+