typing: Making QObject.findChildren type-aware

Phil Thompson phil at riverbankcomputing.com
Wed Jul 12 12:50:11 BST 2023


On 09/07/2023 00:37, Florian Bruhin wrote:
> 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

Fixed in the next PyQt snapshots.

Phil


More information about the PyQt mailing list