Skip to content

Commit bd1c7e0

Browse files
authored
Add more tests (#195)
2 parents d671620 + d583c83 commit bd1c7e0

12 files changed

+240
-20
lines changed

CHANGELOG.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## To be released
8-
98
### Added
109
* [#192](https://github.com./python-qt-tools/PyQt5-stubs/pull/192) Add missing platform specific stubs:
1110
* Windows specific: QAxContainer.pyi QtWinExtras.pyi QtCore.QWinEventNotifier
1211
* MacOs X specific: QtMacExtras.pyi QtWidgets.QMacCocoaViewContainer
12+
* [#195](https://github.com./python-qt-tools/PyQt5-stubs/pull/195) Add more tests based on the historical PR and issues:
13+
* check that QTest methods are static
14+
* check all pyqtSlot() usage
15+
* check sip.voidptr behavior
16+
* check sip.array[int] type
17+
* check comparison operators for QModelIndex, QTableWidgetItem, QListWidgetItem, QTreeWidgetItem
18+
* check QProgressDialog.setCancelButton() accepts optional None
19+
* check signal connect() call returns a QMetaObject.Connection
20+
* check argument for disconnect() is optional
21+
* check QCoreApplication.instance() may return None
22+
1323

1424
### Changed
1525
* [#198](https://github.com./python-qt-tools/PyQt5-stubs/pull/198) Corrected `QTableWidget.cellWidget()` to return an an optional `QWidget` instead of a list of `QWidgets`.

PyQt5-stubs/QtCore.pyi

+6
Original file line numberDiff line numberDiff line change
@@ -3503,6 +3503,12 @@ class QModelIndex(sip.simplewrapper):
35033503
def row(self) -> int: ...
35043504
def child(self, arow: int, acolumn: int) -> 'QModelIndex': ...
35053505

3506+
def __eq__(self, other: object) -> bool: ...
3507+
def __ne__(self, other: object) -> bool: ...
3508+
def __ge__(self, other: 'QModelIndex') -> bool: ...
3509+
def __gt__(self, other: 'QModelIndex') -> bool: ...
3510+
def __le__(self, other: 'QModelIndex') -> bool: ...
3511+
def __lt__(self, other: 'QModelIndex') -> bool: ...
35063512

35073513
class QPersistentModelIndex(sip.simplewrapper):
35083514

PyQt5-stubs/QtWidgets.pyi

+15-4
Original file line numberDiff line numberDiff line change
@@ -7352,6 +7352,12 @@ class QListWidgetItem(sip.wrapper):
73527352
def flags(self) -> QtCore.Qt.ItemFlags: ...
73537353
def listWidget(self) -> 'QListWidget': ...
73547354
def clone(self) -> 'QListWidgetItem': ...
7355+
def __eq__(self, other: object) -> bool: ...
7356+
def __ne__(self, other: object) -> bool: ...
7357+
def __ge__(self, other: 'QListWidgetItem') -> bool: ...
7358+
def __gt__(self, other: 'QListWidgetItem') -> bool: ...
7359+
def __le__(self, other: 'QListWidgetItem') -> bool: ...
7360+
def __lt__(self, other: 'QListWidgetItem') -> bool: ...
73557361

73567362

73577363
class QListWidget(QListView):
@@ -10576,11 +10582,11 @@ class QTableWidgetItem(sip.wrapper):
1057610582
def tableWidget(self) -> 'QTableWidget': ...
1057710583
def clone(self) -> 'QTableWidgetItem': ...
1057810584
def __eq__(self, other: object) -> bool: ...
10579-
def __ge__(self, other: object) -> bool: ...
10580-
def __gt__(self, other: object) -> bool: ...
10581-
def __le__(self, other: object) -> bool: ...
10582-
def __lt__(self, other: object) -> bool: ...
1058310585
def __ne__(self, other: object) -> bool: ...
10586+
def __ge__(self, other: 'QTableWidgetItem') -> bool: ...
10587+
def __gt__(self, other: 'QTableWidgetItem') -> bool: ...
10588+
def __le__(self, other: 'QTableWidgetItem') -> bool: ...
10589+
def __lt__(self, other: 'QTableWidgetItem') -> bool: ...
1058410590

1058510591

1058610592
class QTableWidget(QTableView):
@@ -11320,6 +11326,11 @@ class QTreeWidgetItem(sip.wrapper):
1132011326
@typing.overload
1132111327
def __init__(self, other: 'QTreeWidgetItem') -> None: ...
1132211328

11329+
def __eq__(self, other: object) -> bool: ...
11330+
def __ne__(self, other: object) -> bool: ...
11331+
def __ge__(self, other: 'QTreeWidgetItem') -> bool: ...
11332+
def __gt__(self, other: 'QTreeWidgetItem') -> bool: ...
11333+
def __le__(self, other: 'QTreeWidgetItem') -> bool: ...
1132311334
def __lt__(self, other: 'QTreeWidgetItem') -> bool: ...
1132411335

1132511336
def emitDataChanged(self) -> None: ...

tests/pyqtsignal.py

+15
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,26 @@
55
class Class(QtCore.QObject):
66
signal = QtCore.pyqtSignal([str]) # type: typing.ClassVar[QtCore.pyqtSignal]
77

8+
def __init__(self) -> None:
9+
super().__init__()
810

11+
def my_slot(self) -> None:
12+
pass
13+
14+
# check that method exists
915
Class.signal.__get__
1016

1117
instance = Class()
1218
instance.signal.emit
1319
instance.signal.connect
1420
instance.signal.disconnect
1521
instance.signal[str].emit
22+
23+
# use some of them
24+
connection = QtCore.QMetaObject.Connection()
25+
26+
connection = instance.signal.connect(instance.my_slot)
27+
instance.signal.disconnect()
28+
connection = instance.signal.connect(instance.my_slot)
29+
instance.signal.disconnect(connection)
30+

tests/pyqtslot.py

+81-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from PyQt5.QtCore import pyqtSlot
1+
from typing import Union
2+
3+
from PyQt5.QtCore import pyqtSlot, QObject
24

35
@pyqtSlot(str)
46
def func_none(s: str) -> None:
@@ -8,9 +10,84 @@ def func_none(s: str) -> None:
810
def func_int(s: str) -> int:
911
return 42
1012

11-
@pyqtSlot(str, result='int')
13+
@pyqtSlot(str, result='int') # this means int here
1214
def func_str(s: str) -> str:
1315
return '42'
1416

15-
func_none("test")
16-
x = func_int("test") # type: int
17+
@pyqtSlot(str, name='toto', revision=33, result=int)
18+
def func_toto(s: str) -> int:
19+
return 33
20+
21+
n = None
22+
n = func_none("test")
23+
24+
i = 0
25+
i = func_int("test")
26+
27+
s = ''
28+
s = func_str('test')
29+
30+
print( func_toto('123') )
31+
32+
### Other example extracted from pyqtSlot documentation
33+
34+
class Foo(QObject):
35+
36+
@pyqtSlot()
37+
def foo_noarg(self) -> None:
38+
""" C++: void foo() """
39+
pass
40+
41+
@pyqtSlot(int, str)
42+
def foo_int_str(self, arg1: int, arg2: str) -> None:
43+
""" C++: void foo(int, QString) """
44+
pass
45+
46+
@pyqtSlot(int, name='bar')
47+
def foo_int(self, arg1: int) -> None:
48+
""" C++: void bar(int) """
49+
pass
50+
51+
@pyqtSlot(int, result=int)
52+
def foo_int2(self, arg1: int) -> int:
53+
""" C++: int foo(int) """
54+
pass
55+
56+
# make sure that the return type is type-checked
57+
@pyqtSlot(int, result=int) # type: ignore[arg-type]
58+
def foo_int_with_return_arg_error(self, arg1: int) -> str:
59+
""" C++: int foo(int) """
60+
pass
61+
62+
# mypy can not typecheck the pyqtSlot() arguments vs method arguments
63+
@pyqtSlot(int, result=int)
64+
def foo_int_with_arg_error(self, arg1: str) -> int:
65+
""" C++: int foo(int) """
66+
pass
67+
68+
@pyqtSlot(int, QObject)
69+
def foo_qobject(self, arg1: QObject) -> None:
70+
""" C++: int foo(int, QObject *) """
71+
pass
72+
73+
@pyqtSlot(int)
74+
@pyqtSlot('QString')
75+
def valueChanged(self, value: Union[int, str]) -> None:
76+
""" Two slots will be defined in the QMetaObject. """
77+
pass
78+
79+
80+
f = Foo()
81+
82+
n = f.foo_noarg()
83+
84+
n = f.foo_int_str(33, 'abc')
85+
86+
n = f.foo_int(33)
87+
88+
i = f.foo_int2(33)
89+
90+
n = f.foo_qobject(QObject())
91+
92+
n = f.valueChanged(33)
93+
n = f.valueChanged('abc')

tests/qapplication.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from typing import Optional
2+
3+
from PyQt5.QtCore import QCoreApplication
4+
5+
# let the default type propagate to app
6+
app = QCoreApplication.instance()
7+
8+
# ensure that QCoreApplication.instance() may also return None
9+
app = None

tests/qmodelindex.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from PyQt5.QtCore import QModelIndex
2+
3+
qmi = QModelIndex()
4+
qmi = qmi.siblingAtRow(33)
5+
qmi = qmi.siblingAtColumn(45)
6+
7+
result = True
8+
result = (qmi == qmi)
9+
result = (qmi != qmi)
10+
result = (qmi <= qmi)
11+
result = (qmi >= qmi)
12+
result = (qmi < qmi)
13+
result = (qmi > qmi)

tests/qprogressdialog.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from typing import Optional
2+
from PyQt5.QtWidgets import QProgressDialog, QPushButton
3+
4+
qpd = QProgressDialog()
5+
button1 = None # type: Optional[QPushButton]
6+
button2 = None
7+
button3 = QPushButton()
8+
qpd.setCancelButton(button1)
9+
qpd.setCancelButton(button2)
10+
qpd.setCancelButton(button3)

tests/qtest.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from PyQt5.QtTest import QTest
2+
3+
# check that this is a static method
4+
QTest.qWait(33)
5+

tests/qtreewidgetitem.py

-11
This file was deleted.

tests/siparray.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from PyQt5.QtDataVisualization import QCustom3DVolume
2+
from PyQt5 import sip
3+
4+
v = sip.voidptr(0)
5+
a = v.asarray(1)
6+
7+
volume = QCustom3DVolume()
8+
volume.setTextureData(a)
9+
a = volume.textureData()
10+
11+
# more voidptr tests
12+
v = sip.voidptr(None)
13+
v = sip.voidptr(b'123', 0)
14+
v = sip.voidptr(bytearray(b'123'), 0, False)
15+
v = sip.voidptr(v)

tests/viewitems.py

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from PyQt5.QtWidgets import QTableWidgetItem, QListWidgetItem, QTreeWidgetItem
2+
3+
4+
qti = QTableWidgetItem('')
5+
6+
# Check all comparison informtaion
7+
result = True
8+
result = (qti == qti)
9+
result = (qti != qti)
10+
result = (qti <= qti)
11+
result = (qti >= qti)
12+
result = (qti < qti)
13+
result = (qti > qti)
14+
15+
try:
16+
# comparison does not work, there should be also a type error
17+
result = qti < object() # type: ignore[operator]
18+
except TypeError:
19+
pass
20+
21+
class MyTableWidgetItem(QTableWidgetItem):
22+
23+
# add comparison indicator to allow custom sorting of items
24+
def __lt__(self, other: QTableWidgetItem) -> bool:
25+
return super().__lt__(other)
26+
27+
28+
qli = QListWidgetItem()
29+
result = True
30+
result = (qli == qli)
31+
result = (qli != qli)
32+
result = (qli <= qli)
33+
result = (qli >= qli)
34+
result = (qli < qli)
35+
result = (qli > qli)
36+
37+
class MyListWidgetItem(QListWidgetItem):
38+
39+
# add comparison indicator to allow custom sorting of items
40+
def __lt__(self, other: QListWidgetItem) -> bool:
41+
return super().__lt__(other)
42+
43+
44+
qtwi = QTreeWidgetItem([])
45+
result = True
46+
result = (qtwi == qtwi)
47+
result = (qtwi != qtwi)
48+
result = (qtwi <= qtwi)
49+
result = (qtwi >= qtwi)
50+
result = (qtwi < qtwi)
51+
result = (qtwi > qtwi)
52+
53+
54+
class MyTreeWidgetItem(QTreeWidgetItem):
55+
56+
# add comparison indicator to allow custom sorting of items
57+
def __lt__(self, other: QTreeWidgetItem) -> bool:
58+
return super().__lt__(other)
59+
60+

0 commit comments

Comments
 (0)