pygobject-stubs
pygobject-stubs copied to clipboard
Possible way to type hint callbacks
Right now we hint all the callables that admits variable arguments as Callable[..., T]
. Starting from python 3.10 we can use the combination of Concatenate
and ParamSpec
. Link to documentation.
So for example GAsyncReadyCallback
can be typed as
__P__ = ParamSpec("__P__")
Callable[Concatenate[GObject.Object, Gio.AsyncResult, __P__], None]
@lovetox there are any plans to support 3.10?
Its not about supporting 3.10 rather about not supporting everything that was before, except we cover everything with conditionals.
Python 3.10 is now in debian stable i think we could drop everything else.
Type hints are usually only used for CI and development, so i see no reason why people would need to run type checkers with old python versions.
especially because type checkers have the option to specifically test against older python versions anyway
Good, I will work on this
While ParamSpec and Concatenate both are added to typing in 3.10, they exist in typing_extensions which is available for all Python versions since 3.7.
While ParamSpec and Concatenate both are added to typing in 3.10, they exist in typing_extensions which is available for all Python versions since 3.7.
Thanks for the info. I will use this then
While with pyright
there aren't errors, mypy
throw this:
Argument 3 to "read_async" of "File" has incompatible type "Callable[[Optional[Object], AsyncResult], None]"; expected "Optional[Callable[[Optional[Object], AsyncResult, VarArg(<nothing>), KwArg(<nothing>)], None]]" [arg-type]
The error doesn't make any sense to me, I suppose that it's not correct to use this method for this use case.
Looks correct to me for the most part, the callback
argument takes in a Callable or None, hence its optional. I don't understand the VarArg, KwArg part, maybe its the user_data
argument.
Also, if you don't care about type hinting for Python < 3.7, you could simply add
from __future__ import annotations
and replace:
Optional[str]
with the newer syntax without breaking compatibility:
str | None
It seems that the problem lays on Optional
from typing import Concatenate, ParamSpec, Callable
P = ParamSpec("P")
def func1(func: Callable[Concatenate[str, P], None], *args):
pass
def func2(a: str, b: str):
pass
func1(func2, "hello")
This works
from typing import Concatenate, ParamSpec, Callable, Optional
P = ParamSpec("P")
def func1(func: Optional[Callable[Concatenate[str, P], None]], *args): # Optional func here
pass
def func2(a: str, b: str):
pass
func1(func2, "hello")
This not
A bug in mypy
?
A bug in
mypy
?
Yes probably.
did you try other type checkers like for example pyright?
did you try other type checkers like for example pyright?
With pyright works fine. In the PR I linked an issue that is similar. I have added some comments, let's see if someone is able to fix it
The question for me is, you wrote the MR is blocked by that mypy issue.
Personally for me thats not blocking, there exist at least one type checker who does it right.
mypy has 2.4 k open issues, what if they never fix that issue?
The question for me is, you wrote the MR is blocked by that mypy issue.
Personally for me thats not blocking, there exist at least one type checker who does it right.
mypy has 2.4 k open issues, what if they never fix that issue?
I see your point. Maybe let's wait some time to see if someone came up with a solution
Yeah no hurry, your work, your MR, your decision :) Just wanted to point out that there is more than mypy.