-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type Aliases that are generic over ParamSpec don't work #11855
Comments
This is a bit annoying to do so far, as we have to return a CallableType as a type alias but... like... we need to mark that it is missing a ParamSpec. This is OK with TypeVars because I think the best way will be to make essentially a sentinel value and check for that, though it's been annoying to do so far. |
Another example with import asyncio
from typing import Coroutine, Any, TypeVar, Concatenate, Callable, ParamSpec
_T = TypeVar("_T")
_P = ParamSpec("_P")
Coro = Coroutine[Any, Any, _T]
CoroFunc = Callable[_P, Coro[_T]]
class ClassA: ...
CheckFunc = CoroFunc[Concatenate[ClassA, _P], bool]
async def my_check_func(obj: ClassA, a: int, b: str) -> bool:
print(a, b)
return str(a) == b
async def takes_check_func(
check_func: CheckFunc[_P], *args: _P.args, **kwargs: _P.kwargs
):
await check_func(ClassA(), *args, **kwargs)
asyncio.run(takes_check_func(my_check_func, 1, "2"))
# This should generate an error because the signature doesn't match.
asyncio.run(takes_check_func(my_check_func, 1, 2)) |
This may also be related? https://mypy-play.net/?mypy=latest&python=3.10&gist=ae5f16e9b9ca9346f8a28ab60bd9825f from typing import ParamSpec, Callable, Optional, TypeVar
P = ParamSpec("P")
R = TypeVar("R")
x: Callable[P, R] # error
y: Optional[Callable[P, R]] # error
z: Callable[..., R] # fine
|
Also this: https://mypy-play.net/?mypy=latest&python=3.10&gist=c4d6f13911151a073aed0d6650e4af3e from typing import ParamSpec, Callable, Optional, TypeVar
P = ParamSpec("P")
R = TypeVar("R")
def target_func(x: int) -> int:
return 0
def test(x: Callable[P, R]):
pass
def test_optional(x: Optional[Callable[P, R]] = None):
pass
test(target_func) # fine
test_optional(target_func) # error
|
In my case I was trying to annotate a decorator, e.g.
instead of
which could be used as
or
Having an alias would make everything much simpler. PS: Would be cool as well if an unbound
But that would require a PEP. |
Another case which also throws another funny error on from typing import ParamSpec, Callable, Concatenate
class Event: ...
P = ParamSpec("P")
EventHandler = Callable[Concatenate[Event, P], None]
|
I'm experiencing this issue too, is there a workaround for this? |
Possible MFE (minimum failing example): from typing import Callable, ParamSpec
P = ParamSpec("P")
FunctionType = Callable[P, None] main.py:4: error: The first argument to Callable must be a list of types, parameter specification, or "..."
main.py:4: note: See https://mypy.readthedocs.io/en/stable/kinds_of_types.html#callable-types-and-lambdas
Found 1 error in 1 file (checked 1 source file) |
The issue I reported in #14069 is likely a symptom of this issue (and lack of alias support) |
Fixes #11855 Fixes #7084 Fixes #10445 Should fix #4987 After thinking about this for some time, it looks like the best way to implement this is by switching type aliases from unbound to bound type variables. Then I can essentially simply share (or copy in one small place, to avoid cyclic imports) all the logic that currently exists for `ParamSpec` and `Concatenate` in `expand_type()` etc. This will also address a big piece of tech debt, and will get some benefits (almost) for free, such as checking bounds/values for alias type variables, and much tighter handling of unbound type variables. Note that in this PR I change logic for emitting some errors, I try to avoid showing multiple errors for the same location/reason. But this is not an essential part of this PR (it is just some test cases would otherwise fail with even more error messages), I can reconsider if there are objections.
Is there any information on when this fix would be available? (When 0.992 is released?) |
You can track progress on the next release by following #13685 (I think it's unlikely that there'll be a 0.992 release). |
The following is not working for me in from typing import TypeAlias, ParamSpec, Concatenate, Callable
P = ParamSpec("P")
intfun: TypeAlias = Callable[Concatenate[int, P], None]
def foo(i: int) -> None:
pass
a: intfun = foo # ✘ Incompatible types in assignment |
@randolf-scholz, you have defined a generic type alias that has a single type parameter ( So I agree this is a bug in mypy, but your code is also probably not doing what you intended. You might want to file a separate bug since this one has been closed for a while. |
@erictraut So when I use |
I recommend using a callback protocol |
@hauntsaninja Not sure how that would look like, when one writes a Callback-Protocol, how do you make the signature generic? I created a mypy-play with a bunch of test-cases here:
EDIT: Found some older threads about this |
Oh thanks, I see. Basically the Concatenate version of #5876 |
Bug Report
I expect
n = Callable[P, int]
to work, or at leastn: TypeAlias = Callable[P, int]
To Reproduce
Expected Behavior
No errors
Actual Behavior
Your Environment
mypy playground
The text was updated successfully, but these errors were encountered: