[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    typing: Making pyqtSlot typed
From:       Florian Bruhin <me () the-compiler ! org>
Date:       2023-06-29 22:20:44
Message-ID: 168807724493.488012.13861475162499528206 () aragog ! localdomain
[Download RAW message or body]


Whoops. Resent without line-wrapping... switched to a new mail-client
which is based on PyQt btw: https://github.com/akissinger/dodo

Sorry for the noise!

-----------

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


[Attachment #3 (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic