typing: Making QObject.findChildren type-aware

Florian Bruhin me at the-compiler.org
Sun Jul 9 00:37:06 BST 2023


Hey,

Another relatively simple one, hopefully!

The current type hints for QObject.findChildren are:

    @typing.overload
    def findChildren(self, type: type, name: str = ..., options: Qt.FindChildOption = ...) -> typing.List['QObject']: ...
    @typing.overload
    def findChildren(self, types: typing.Tuple, name: str = ..., options: Qt.FindChildOption = ...) -> typing.List['QObject']: ...
    @typing.overload
    def findChildren(self, type: type, re: 'QRegularExpression', options: Qt.FindChildOption = ...) -> typing.List['QObject']: ...
    @typing.overload
    def findChildren(self, types: typing.Tuple, re: 'QRegularExpression', options: Qt.FindChildOption = ...) -> typing.List['QObject']: ...
    @typing.overload
    def findChild(self, type: type, name: str = ..., options: Qt.FindChildOption = ...) -> 'QObject': ...
    @typing.overload
    def findChild(self, types: typing.Tuple, name: str = ..., options: Qt.FindChildOption = ...) -> 'QObject': ...

which means that one needs to use typing.cast to make the type system aware
that it's in fact not a QObject - for (a somewhat contrived) example:

    from PyQt6.QtCore import QThread, QObject
    obj = QObject()
    thread = QThread(obj)
    thread2 = obj.findChild(QThread)
    print(thread2.isRunning())

results in:

    error: "QObject" has no attribute "isRunning"  [attr-defined]

PyQt6-stubs has this improved here:
https://github.com/python-qt-tools/PyQt6-stubs/blob/main/PyQt6-stubs/QtCore.pyi#L1393-L1404

and does this instead:

    @typing.overload
    def findChildren(self, type: typing.Type[QObjectT], name: str = ..., options: Qt.FindChildOption = ...) -> typing.List["QObjectT"]: ...
    @typing.overload
    def findChildren(self, types: typing.Tuple[typing.Type[QObjectT], ...], name: str = ..., options: Qt.FindChildOption = ...) -> typing.List["QObjectT"]: ...
    @typing.overload
    def findChildren(self, type: typing.Type[QObjectT], re: "QRegularExpression", options: Qt.FindChildOption = ...) -> typing.List["QObjectT"]: ...
    @typing.overload
    def findChildren(self, types: typing.Tuple[typing.Type[QObjectT], ...], re: "QRegularExpression", options: Qt.FindChildOption = ...) -> typing.List["QObjectT"]: ...
    @typing.overload
    def findChild(self, type: typing.Type[QObjectT], name: str = ..., options: Qt.FindChildOption = ...) -> "QObjectT": ...
    @typing.overload
    def findChild(self, types: typing.Tuple[typing.Type[QObjectT], ...], name: str = ..., options: Qt.FindChildOption = ...) -> "QObjectT": ...

with:

    QObjectT = typing.TypeVar("QObjectT", bound=QObject)

which makes the respective "type" / "types" argument based a type variable, and
teaches the type system that the return value will be of the type passed in as
an argument.

(Probably could drop the quotes in the return types too, since they are now not
referring to the QObject class this was defined in anymore)

Florian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20230709/84d7e902/attachment-0001.sig>


More information about the PyQt mailing list