typing: Making pyqtSlot typed

Florian Bruhin me at the-compiler.org
Thu Jun 29 23:17:13 BST 2023


Hey,

last one for today :)

pyqtSlot is currently typed as returning Any:

    def pyqtSlot(
        *types,
        name: typing.Optional[str] = ...,
        result: typing.Optional[str] = ...,
    ) -> typing.Any: ...

which means that incorrect code such as:

    from PyQt6.QtCore import pyqtSlot

    @pyqtSlot(int)
    def func(a: int) -> None:
        print(a)

    func("not-an-int")

can't be typechecked because the pyqtSlot decorator loses the type
information:

    slot.py:3: error: Untyped decorator makes function "func" untyped [misc]

A minimal improvement wound be:

    FuncT = typing.TypeVar("FuncT", bound=typing.Callable)
    def pyqtSlot(*types, name: typing.Optional[str] = ..., result:
typing.Optional[str] = ...) -> typing.Callable[[FuncT], FuncT]: ...

read as:

    - FuncT is a type variable, representing any callable
    - Calling pyqtSlot as e.g. pyqtSlot(int) returns a callable
      (the decorator)
    - That decorator takes a FuncT as argument, and returns a FuncT

Thus, we can teach the type system that @pyqtSlot does not touch the
decorated function's signature, which then results in mypy catching this
properly:

    slot.py:7: error: Argument 1 to "func" has incompatible type "str";
expected "int"  [arg-type]
        func("not-an-int")

Interestingly, the PyQt6-stubs project has far more complex typing for
pyqtSlot:

https://github.com/python-qt-tools/PyQt6-
stubs/blob/f623a641cd5cdff53342177e4fbbf9cae8172336/PyQt6-
stubs/QtCore.pyi#L7537-L7563

It's unclear to me how that works in detail and if it's really needed.
The minimal fix above fixes all related errors for my project (but I
don't e.g. use QML).

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/20230630/e1d36e31/attachment.sig>


More information about the PyQt mailing list