-
-
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
Regression since mypy 1.7 with functions that return a generic protocol #17191
Comments
To add a bit more information, the same example works fine if the However, being able to extract a type from the param spec as seen in the first code sample is really useful. In particular, the type of the first argument might appear in other methods of the protocol, for instance: # An object that can convert I to O with parameters P
class ConvertorProtocol(Protocol[I, P, O]):
def convert(self, __source: I, *args: P.args, **kwargs: P.kwargs) -> O:
...
def prepare(self, *args: P.args, **kwargs: P.kwargs) -> Callable[[I], O]:
... |
I just came up with a simpler example that can reproduce the regression, without from typing import (
Generic,
TypeVar,
Callable,
Concatenate,
ParamSpec,
reveal_type,
)
from dataclasses import dataclass
X = TypeVar("X")
P = ParamSpec("P")
I = TypeVar("I", contravariant=True)
O = TypeVar("O", covariant=True)
@dataclass
class Convertor(Generic[I, P, O]):
convert: Callable[Concatenate[I, P], O]
def as_list(source: X, repeat: int = 1) -> list[X]:
return [source] * repeat
as_list_convertor = Convertor(convert=as_list)
if __name__ == "__main__":
reveal_type(as_list_convertor.convert)
result = as_list_convertor.convert(1, repeat=3)
reveal_type(result)
assert result == [1, 1, 1] You can see in the playground that it passes with mypy 1.6 but starts failing with mypy 1.7. |
I am having the same issue, from typing import Protocol, Sequence, reveal_type, Any
class ClassDecorator[T, **P](Protocol):
def __call__(self, cls: type[T], /, *args: P.args, **kwargs: P.kwargs) -> type[T]: ...
def as_class_decorator[T, **P](x: ClassDecorator[T, P]) -> ClassDecorator[T, P]:
return x
def pprint_sequence[S: Sequence](cls: type[S], /, **kwds: Any) -> type[S]:
return cls
reveal_type(as_class_decorator(pprint_sequence))
# >>> mypy: ClassDecorator[Never, [**kwds: Any]]
# >>> pyright: ClassDecorator[S@pprint_sequence, (**kwds: Any)]
# if we assign to a variable first, we at least don't get `Never`
fn = as_class_decorator(pprint_sequence)
reveal_type(fn)
# >>> mypy: ClassDecorator[Any, [**kwds: Any]]
# >>> pyright: ClassDecorator[S@pprint_sequence, (**kwds: Any)] |
EDIT: I found a simpler example reproducing the regression, see below
The following code used to pass with mypy 1.6.1
However, it no longer passes with mypy 1.7.0 and later:
error: Argument 1 to "convert" of "ConvertorProtocol" has incompatible type "int"; expected Never [arg-type]
Try it in the playground.
Note that this sample works in the pyright playground.
The text was updated successfully, but these errors were encountered: