From 2b070c19699109b05eb69e27453acad95f9d4289 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 12 Sep 2020 19:58:04 -0400 Subject: [PATCH 1/6] Use TypeVar to help with QObject.findChild[ren]() --- PyQt5-stubs/QtCore.pyi | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/PyQt5-stubs/QtCore.pyi b/PyQt5-stubs/QtCore.pyi index 4cbf8fd3..268e7e00 100644 --- a/PyQt5-stubs/QtCore.pyi +++ b/PyQt5-stubs/QtCore.pyi @@ -45,6 +45,9 @@ PYQT_SIGNAL = typing.Union[pyqtSignal, pyqtBoundSignal] PYQT_SLOT = typing.Union[typing.Callable[..., None], pyqtBoundSignal] +QObjectT = typing.TypeVar("QObjectT", bound="QObject") + + class QtMsgType(int): ... QtDebugMsg = ... # type: QtMsgType QtWarningMsg = ... # type: QtMsgType @@ -1793,19 +1796,19 @@ class QObject(sip.wrapper): def setObjectName(self, name: str) -> None: ... def objectName(self) -> str: ... @typing.overload - def findChildren(self, type: type, name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload def findChildren(self, types: typing.Tuple, name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload - def findChildren(self, type: type, regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, type: typing.Type[QObjectT], regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload def findChildren(self, types: typing.Tuple, regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload - def findChildren(self, type: type, re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, type: typing.Type[QObjectT], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload def findChildren(self, types: typing.Tuple, re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload - def findChild(self, type: type, name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... + def findChild(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> QObjectT: ... @typing.overload def findChild(self, types: typing.Tuple, name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... def tr(self, sourceText: str, disambiguation: typing.Optional[str] = ..., n: int = ...) -> str: ... From 8cc9e413d12d2e425490fa55a8b4c3aa900cdb92 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sun, 13 Sep 2020 14:13:49 -0400 Subject: [PATCH 2/6] At least type the inputs to multi-type findChild[ren] --- PyQt5-stubs/QtCore.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PyQt5-stubs/QtCore.pyi b/PyQt5-stubs/QtCore.pyi index 268e7e00..4c03fb1a 100644 --- a/PyQt5-stubs/QtCore.pyi +++ b/PyQt5-stubs/QtCore.pyi @@ -1798,19 +1798,19 @@ class QObject(sip.wrapper): @typing.overload def findChildren(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload - def findChildren(self, types: typing.Tuple, name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, types: typing.Tuple[typing.Type[QObject]], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload def findChildren(self, type: typing.Type[QObjectT], regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload - def findChildren(self, types: typing.Tuple, regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, types: typing.Tuple[typing.Type[QObject]], regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload def findChildren(self, type: typing.Type[QObjectT], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload - def findChildren(self, types: typing.Tuple, re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, types: typing.Tuple[typing.Type[QObject]], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload def findChild(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> QObjectT: ... @typing.overload - def findChild(self, types: typing.Tuple, name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... + def findChild(self, types: typing.Tuple[typing.Type[QObject]], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... def tr(self, sourceText: str, disambiguation: typing.Optional[str] = ..., n: int = ...) -> str: ... def eventFilter(self, a0: 'QObject', a1: 'QEvent') -> bool: ... def event(self, a0: 'QEvent') -> bool: ... From 9f27a2b7774f9fbb36812f0c3141e7e08f7506d7 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 1 Oct 2020 10:53:22 -0400 Subject: [PATCH 3/6] Correct to allow multiple types in the tuples --- PyQt5-stubs/QtCore.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PyQt5-stubs/QtCore.pyi b/PyQt5-stubs/QtCore.pyi index a906e6ae..8efb85f4 100644 --- a/PyQt5-stubs/QtCore.pyi +++ b/PyQt5-stubs/QtCore.pyi @@ -1801,19 +1801,19 @@ class QObject(sip.wrapper): @typing.overload def findChildren(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload - def findChildren(self, types: typing.Tuple[typing.Type[QObject]], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, types: typing.Tuple[typing.Type[QObject], ...], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload def findChildren(self, type: typing.Type[QObjectT], regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload - def findChildren(self, types: typing.Tuple[typing.Type[QObject]], regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, types: typing.Tuple[typing.Type[QObject], ...], regExp: 'QRegExp', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload def findChildren(self, type: typing.Type[QObjectT], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List[QObjectT]: ... @typing.overload - def findChildren(self, types: typing.Tuple[typing.Type[QObject]], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... + def findChildren(self, types: typing.Tuple[typing.Type[QObject], ...], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload def findChild(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> QObjectT: ... @typing.overload - def findChild(self, types: typing.Tuple[typing.Type[QObject]], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... + def findChild(self, types: typing.Tuple[typing.Type[QObject], ...], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... def tr(self, sourceText: str, disambiguation: typing.Optional[str] = ..., n: int = ...) -> str: ... def eventFilter(self, a0: 'QObject', a1: 'QEvent') -> bool: ... def event(self, a0: 'QEvent') -> bool: ... From 1060dd56af8add04de4008958de032c9d9baf03b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 1 Oct 2020 11:21:52 -0400 Subject: [PATCH 4/6] Add minimal tests for findChildren updates --- tests/qobject.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/qobject.py diff --git a/tests/qobject.py b/tests/qobject.py new file mode 100644 index 00000000..c210fd31 --- /dev/null +++ b/tests/qobject.py @@ -0,0 +1,15 @@ +import typing + +from PyQt5 import QtCore +from PyQt5 import QtWidgets + + +q = QtCore.QObject() + +a = q.findChildren(QtCore.QObject) # type: typing.List[QtCore.QObject] +b = q.findChildren(QtWidgets.QWidget) # type: typing.List[QtWidgets.QWidget] +c = q.findChildren((QtCore.QObject,)) # type: typing.List[QtCore.QObject] +d = q.findChildren((QtWidgets.QWidget,)) # type: typing.List[QtCore.QObject] +# desired error +# Incompatible types in assignment (expression has type "List[QObject]", variable has type "List[QWidget]") +# e = q.findChildren((QtWidgets.QWidget,)) # type: typing.List[QtWidgets.QWidget] From 42d75d0807d7dedeba33697e3c59547b4835150b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 1 Oct 2020 23:00:27 -0400 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b760748..851676a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added ### Changed +* [#58](https://github.com/stlehmann/PyQt5-stubs/pull/50) improves QObject.findChild and findChildren * [#50](https://github.com/stlehmann/PyQt5-stubs/pull/50) fixes QTest QAbstractItemModelTester.FailureReportingMode attributes * [#46](https://github.com/stlehmann/PyQt5-stubs/pull/46) fixes QCoreApplication and QObject signals * [#48](https://github.com/stlehmann/PyQt5-stubs/pull/48) fixes some signals for QClipBoard, QWindows, QQuickView and QQml{Application,}Engine From 9eb7b8e500b820336fbd9ef53a02a33f6a0120b8 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 1 Oct 2020 23:19:29 -0400 Subject: [PATCH 6/6] Make QObject.findChild() return optional --- PyQt5-stubs/QtCore.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PyQt5-stubs/QtCore.pyi b/PyQt5-stubs/QtCore.pyi index c872333a..3df7c2fa 100644 --- a/PyQt5-stubs/QtCore.pyi +++ b/PyQt5-stubs/QtCore.pyi @@ -1816,9 +1816,9 @@ class QObject(sip.wrapper): @typing.overload def findChildren(self, types: typing.Tuple[typing.Type[QObject], ...], re: 'QRegularExpression', options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.List['QObject']: ... @typing.overload - def findChild(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> QObjectT: ... + def findChild(self, type: typing.Type[QObjectT], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> typing.Optional[QObjectT]: ... @typing.overload - def findChild(self, types: typing.Tuple[typing.Type[QObject], ...], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'QObject': ... + def findChild(self, types: typing.Tuple[typing.Type[QObject], ...], name: str = ..., options: typing.Union[Qt.FindChildOptions, Qt.FindChildOption] = ...) -> 'typing.Optional[QObject]': ... def tr(self, sourceText: str, disambiguation: typing.Optional[str] = ..., n: int = ...) -> str: ... def eventFilter(self, a0: 'QObject', a1: 'QEvent') -> bool: ... def event(self, a0: 'QEvent') -> bool: ...