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.txt6
-rw-r--r--sources/pyside6/tests/QtQml/QtQml.pyproject65
-rw-r--r--sources/pyside6/tests/QtQml/bug_451.py1
-rw-r--r--sources/pyside6/tests/QtQml/bug_456.py1
-rw-r--r--sources/pyside6/tests/QtQml/bug_557.py2
-rw-r--r--sources/pyside6/tests/QtQml/bug_726.py2
-rw-r--r--sources/pyside6/tests/QtQml/bug_814.py3
-rw-r--r--sources/pyside6/tests/QtQml/bug_825.py13
-rw-r--r--sources/pyside6/tests/QtQml/bug_825_old.py80
-rw-r--r--sources/pyside6/tests/QtQml/bug_847.py4
-rw-r--r--sources/pyside6/tests/QtQml/bug_926.py2
-rw-r--r--sources/pyside6/tests/QtQml/bug_995.py4
-rw-r--r--sources/pyside6/tests/QtQml/bug_997.py4
-rw-r--r--sources/pyside6/tests/QtQml/connect_python_qml.py3
-rw-r--r--sources/pyside6/tests/QtQml/javascript_exceptions.py4
-rw-r--r--sources/pyside6/tests/QtQml/listproperty.py87
-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/qqmlcomponent_test.py36
-rw-r--r--sources/pyside6/tests/QtQml/qquickview_test.py1
-rw-r--r--sources/pyside6/tests/QtQml/registersingletontype.py77
-rw-r--r--sources/pyside6/tests/QtQml/registersingletontype.qml2
-rw-r--r--sources/pyside6/tests/QtQml/signal_arguments.py1
-rw-r--r--sources/pyside6/tests/QtQml/signal_types.py124
-rw-r--r--sources/pyside6/tests/QtQml/signal_types.qml26
26 files changed, 619 insertions, 39 deletions
diff --git a/sources/pyside6/tests/QtQml/CMakeLists.txt b/sources/pyside6/tests/QtQml/CMakeLists.txt
index fc931c0f2..30bf7e786 100644
--- a/sources/pyside6/tests/QtQml/CMakeLists.txt
+++ b/sources/pyside6/tests/QtQml/CMakeLists.txt
@@ -1,8 +1,12 @@
+# 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)
@@ -13,8 +17,10 @@ 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)
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_451.py b/sources/pyside6/tests/QtQml/bug_451.py
index 299864ae4..d81a99d94 100644
--- a/sources/pyside6/tests/QtQml/bug_451.py
+++ b/sources/pyside6/tests/QtQml/bug_451.py
@@ -28,6 +28,7 @@ from PySide6.QtQml import QmlElement
QML_IMPORT_NAME = "test.PythonObject"
QML_IMPORT_MAJOR_VERSION = 1
+
@QmlElement
class PythonObject(QObject):
def __init__(self):
diff --git a/sources/pyside6/tests/QtQml/bug_456.py b/sources/pyside6/tests/QtQml/bug_456.py
index 7148102cc..7743ee3fd 100644
--- a/sources/pyside6/tests/QtQml/bug_456.py
+++ b/sources/pyside6/tests/QtQml/bug_456.py
@@ -19,6 +19,7 @@ from PySide6.QtQml import QmlElement
QML_IMPORT_NAME = "test.RotateValue"
QML_IMPORT_MAJOR_VERSION = 1
+
@QmlElement
class RotateValue(QObject):
def __init__(self):
diff --git a/sources/pyside6/tests/QtQml/bug_557.py b/sources/pyside6/tests/QtQml/bug_557.py
index cc06a4877..eb43973f6 100644
--- a/sources/pyside6/tests/QtQml/bug_557.py
+++ b/sources/pyside6/tests/QtQml/bug_557.py
@@ -23,6 +23,6 @@ component = QQmlComponent(engine)
# This should segfault if the QDeclarativeComponent has not QQmlEngine
file = Path(__file__).resolve().parent / 'foo.qml'
-assert(not file.is_file())
+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
index 7ddc8e93b..56c1e70f1 100644
--- a/sources/pyside6/tests/QtQml/bug_726.py
+++ b/sources/pyside6/tests/QtQml/bug_726.py
@@ -18,6 +18,8 @@ from PySide6.QtQml import QmlElement
QML_IMPORT_NAME = "test.ProxyObject"
QML_IMPORT_MAJOR_VERSION = 1
+
+
@QmlElement
class ProxyObject(QObject):
def __init__(self):
diff --git a/sources/pyside6/tests/QtQml/bug_814.py b/sources/pyside6/tests/QtQml/bug_814.py
index 9db6488ef..0e7858b6c 100644
--- a/sources/pyside6/tests/QtQml/bug_814.py
+++ b/sources/pyside6/tests/QtQml/bug_814.py
@@ -29,13 +29,14 @@ 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' }
+ return {Qt.DisplayRole: b'pysideModelData'}
def rowCount(self, parent=QModelIndex()):
return 3
diff --git a/sources/pyside6/tests/QtQml/bug_825.py b/sources/pyside6/tests/QtQml/bug_825.py
index 9771d0634..a8bd304ec 100644
--- a/sources/pyside6/tests/QtQml/bug_825.py
+++ b/sources/pyside6/tests/QtQml/bug_825.py
@@ -1,6 +1,11 @@
# 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
@@ -25,8 +30,8 @@ class MetaA(type):
pass
-class A(object):
- __metaclass__ = MetaA
+class A(object, metaclass=MetaA):
+ pass
MetaB = type(QQuickPaintedItem)
@@ -37,8 +42,8 @@ class MetaC(MetaA, MetaB):
pass
-class C(A, B):
- __metaclass__ = MetaC
+class C(A, B, metaclass=MetaC):
+ pass
class Bug825 (C):
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
index 8ccde82ff..947eb494e 100644
--- a/sources/pyside6/tests/QtQml/bug_847.py
+++ b/sources/pyside6/tests/QtQml/bug_847.py
@@ -17,7 +17,7 @@ from init_paths import init_test_paths
init_test_paths(False)
from helper.helper import quickview_errorstring
-from helper.usesqguiapplication import UsesQGuiApplication
+from helper.usesqapplication import UsesQApplication
from PySide6.QtCore import Slot, Signal, QUrl, QTimer, QCoreApplication
from PySide6.QtQuick import QQuickView
@@ -34,7 +34,7 @@ class View(QQuickView):
self.called.emit(x, y)
-class TestQML(UsesQGuiApplication):
+class TestQML(UsesQApplication):
def done(self, x, y):
self._sucess = True
self.app.quit()
diff --git a/sources/pyside6/tests/QtQml/bug_926.py b/sources/pyside6/tests/QtQml/bug_926.py
index c4853b9ad..085e9a68f 100644
--- a/sources/pyside6/tests/QtQml/bug_926.py
+++ b/sources/pyside6/tests/QtQml/bug_926.py
@@ -41,7 +41,7 @@ class MyClass (QObject):
class TestBug926 (unittest.TestCase):
def testIt(self):
app = QGuiApplication([])
- qmlRegisterType(MyClass,'Example', 1, 0, 'MyClass')
+ qmlRegisterType(MyClass, 'Example', 1, 0, 'MyClass')
view = QQuickView()
file = Path(__file__).resolve().parent / 'bug_926.qml'
self.assertTrue(file.is_file())
diff --git a/sources/pyside6/tests/QtQml/bug_995.py b/sources/pyside6/tests/QtQml/bug_995.py
index bd1315d52..868c584e2 100644
--- a/sources/pyside6/tests/QtQml/bug_995.py
+++ b/sources/pyside6/tests/QtQml/bug_995.py
@@ -11,7 +11,7 @@ from init_paths import init_test_paths
init_test_paths(False)
from helper.helper import adjust_filename
-from helper.usesqguiapplication import UsesQGuiApplication
+from helper.usesqapplication import UsesQApplication
from PySide6.QtCore import QUrl
from PySide6.QtGui import QGuiApplication
@@ -19,7 +19,7 @@ from PySide6.QtQuick import QQuickView
app = QGuiApplication([])
file = Path(__file__).resolve().parent / 'bug_995.qml'
-assert(file.is_file())
+assert (file.is_file())
view = QQuickView(QUrl.fromLocalFile(file))
view.show()
view.resize(200, 200)
diff --git a/sources/pyside6/tests/QtQml/bug_997.py b/sources/pyside6/tests/QtQml/bug_997.py
index cc7cf4d66..501c221c3 100644
--- a/sources/pyside6/tests/QtQml/bug_997.py
+++ b/sources/pyside6/tests/QtQml/bug_997.py
@@ -11,13 +11,13 @@ from init_paths import init_test_paths
init_test_paths(False)
from helper.helper import quickview_errorstring
-from helper.usesqguiapplication import UsesQGuiApplication
+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(UsesQGuiApplication):
+class TestBug(UsesQApplication):
def setUp(self):
super().setUp()
diff --git a/sources/pyside6/tests/QtQml/connect_python_qml.py b/sources/pyside6/tests/QtQml/connect_python_qml.py
index f0df1c83d..2e60aec4f 100644
--- a/sources/pyside6/tests/QtQml/connect_python_qml.py
+++ b/sources/pyside6/tests/QtQml/connect_python_qml.py
@@ -42,7 +42,8 @@ class TestConnectionWithInvalidSignature(TimedQGuiApplication):
root = view.rootObject()
self.assertTrue(root, quickview_errorstring(view))
button = root.findChild(QObject, "buttonMouseArea")
- self.assertRaises(TypeError, QObject.connect, [button,SIGNAL('entered()'), self.onButtonFailClicked])
+ self.assertRaises(TypeError, QObject.connect,
+ [button, SIGNAL('entered()'), self.onButtonFailClicked])
button.entered.connect(self.onButtonClicked)
button.entered.emit()
view.show()
diff --git a/sources/pyside6/tests/QtQml/javascript_exceptions.py b/sources/pyside6/tests/QtQml/javascript_exceptions.py
index ec99c930d..e2b530aaf 100644
--- a/sources/pyside6/tests/QtQml/javascript_exceptions.py
+++ b/sources/pyside6/tests/QtQml/javascript_exceptions.py
@@ -11,7 +11,7 @@ from init_paths import init_test_paths
init_test_paths(False)
from helper.helper import quickview_errorstring
-from helper.usesqguiapplication import UsesQGuiApplication
+from helper.usesqapplication import UsesQApplication
from PySide6.QtCore import Slot, Property, Signal, QObject, QUrl
from PySide6.QtQml import QJSEngine, qmlRegisterType
@@ -54,7 +54,7 @@ class TestClass(QObject):
test_2 = True
-class JavaScriptExceptionsTest(UsesQGuiApplication):
+class JavaScriptExceptionsTest(UsesQApplication):
def test_jsengine(self):
engine = QJSEngine()
test_object = TestClass()
diff --git a/sources/pyside6/tests/QtQml/listproperty.py b/sources/pyside6/tests/QtQml/listproperty.py
index 8916aefe5..884600d29 100644
--- a/sources/pyside6/tests/QtQml/listproperty.py
+++ b/sources/pyside6/tests/QtQml/listproperty.py
@@ -7,11 +7,25 @@ import unittest
from pathlib import Path
sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
-from init_paths import init_test_paths
+from init_paths import init_test_paths # noqa: E402
init_test_paths(False)
-from PySide6.QtCore import QObject
-from PySide6.QtQml import ListProperty
+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):
@@ -22,7 +36,46 @@ def dummyFunc():
pass
-class TestListProperty(unittest.TestCase):
+@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
@@ -31,7 +84,7 @@ class TestListProperty(unittest.TestCase):
try:
ListProperty(QObject)
ListProperty(InheritsQObject)
- except:
+ except Exception:
type_check_error = True
self.assertFalse(type_check_error)
@@ -47,21 +100,37 @@ class TestListProperty(unittest.TestCase):
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=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:
+ except Exception:
method_check_error = True
self.assertFalse(method_check_error)
try:
- ListPropery(QObject, append=QObject())
- except:
+ 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/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/qquickview_test.py b/sources/pyside6/tests/QtQml/qquickview_test.py
index 5cf5550ed..226509669 100644
--- a/sources/pyside6/tests/QtQml/qquickview_test.py
+++ b/sources/pyside6/tests/QtQml/qquickview_test.py
@@ -22,6 +22,7 @@ from PySide6.QtQuick import QQuickView
class MyObject(QObject):
titleChanged = Signal()
+
def __init__(self, text, parent=None):
QObject.__init__(self, parent)
self._text = text
diff --git a/sources/pyside6/tests/QtQml/registersingletontype.py b/sources/pyside6/tests/QtQml/registersingletontype.py
index f2e318e46..6beca1131 100644
--- a/sources/pyside6/tests/QtQml/registersingletontype.py
+++ b/sources/pyside6/tests/QtQml/registersingletontype.py
@@ -12,13 +12,18 @@ init_test_paths(False)
from helper.helper import quickview_errorstring
-from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject
+from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import (qmlRegisterSingletonType, qmlRegisterSingletonInstance,
- QmlElement, QmlSingleton)
+ QmlElement, QmlSingleton, QJSValue)
from PySide6.QtQuick import QQuickView
+
+URI = "Singletons"
+
+
finalResult = 0
+qObjectQmlTypeId = 0
class SingletonQObject(QObject):
@@ -46,9 +51,10 @@ def singletonQJSValueCallback(engine):
return engine.evaluate("new Object({data: 50})")
-QML_IMPORT_NAME = "Singletons"
+QML_IMPORT_NAME = URI
QML_IMPORT_MAJOR_VERSION = 1
+
@QmlElement
@QmlSingleton
class DecoratedSingletonQObject(QObject):
@@ -65,37 +71,82 @@ class DecoratedSingletonQObject(QObject):
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([])
- qmlRegisterSingletonType(SingletonQObject, 'Singletons', 1, 0, 'SingletonQObjectNoCallback')
- qmlRegisterSingletonType(SingletonQObject, 'Singletons', 1, 0, 'SingletonQObjectCallback',
+ qObjectQmlTypeId = qmlRegisterSingletonType(SingletonQObject, URI, 1, 0,
+ 'SingletonQObjectNoCallback')
+ qmlRegisterSingletonType(SingletonQObject, URI, 1, 0, 'SingletonQObjectCallback',
singletonQObjectCallback)
- qmlRegisterSingletonType('Singletons', 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
+ qmlRegisterSingletonType(URI, 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
# Accepts only QObject derived types
l = [1, 2]
with self.assertRaises(TypeError):
- qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', l)
+ qmlRegisterSingletonInstance(SingletonQObject, URI, 1, 0, 'SingletonInstance', l)
# Modify value on the instance
s = SingletonQObject()
s.setData(99)
- qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', s)
+ qmlRegisterSingletonInstance(SingletonQObject, URI, 1, 0, 'SingletonInstance', s)
- view = QQuickView()
+ 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.close)
+ QTimer.singleShot(250, view.testSlot)
app.exec()
- self.assertEqual(finalResult, 499)
+ 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()
+if __name__ == '__main__': unittest.main()
diff --git a/sources/pyside6/tests/QtQml/registersingletontype.qml b/sources/pyside6/tests/QtQml/registersingletontype.qml
index 4c45b198e..31ca7fe4d 100644
--- a/sources/pyside6/tests/QtQml/registersingletontype.qml
+++ b/sources/pyside6/tests/QtQml/registersingletontype.qml
@@ -9,6 +9,6 @@ Item {
SingletonQObjectCallback.data += SingletonQObjectNoCallback.data
+ SingletonQJSValue.data
+ SingletonInstance.data
- + DecoratedSingletonQObject.data;
+ + DecoratedSingletonQObject.data + DecoratedSingletonWithCreate.data;
}
}
diff --git a/sources/pyside6/tests/QtQml/signal_arguments.py b/sources/pyside6/tests/QtQml/signal_arguments.py
index 304c83ca3..f5b0f8bd3 100644
--- a/sources/pyside6/tests/QtQml/signal_arguments.py
+++ b/sources/pyside6/tests/QtQml/signal_arguments.py
@@ -20,6 +20,7 @@ from PySide6.QtQml import QmlElement
QML_IMPORT_NAME = "test.Obj"
QML_IMPORT_MAJOR_VERSION = 1
+
@QmlElement
class Obj(QObject):
def __init__(self):
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)
+ }
+ }
+}