Bug Report
I found a really weird bug while writing a decorator that returns a Protocol that itself uses a concatenated ParamSpec. I managed to get to a small reproducible example:
P = ParamSpec("P")
T = TypeVar("T")
X = TypeVar("X")
class Wrapped(Protocol[P, T]):
__call__: Callable[P, T]
def decorator(
func: Callable[Concatenate[X, P], T],
) -> Wrapped[Concatenate[X, P], T]:
# Do something with X
return func
@decorator
def first(
source: Iterable[T],
) -> T:
return next(iter(source))
item = first(range(2))
reveal_type(item)
print(item.real)
Playground link
Expected Behavior
It works as expected using either one of those two decorators instead:
# Decorator without `Concatenate`
def decorator(
func: Callable[P, T],
) -> Wrapped[P, T]:
# Do something with X
return func
# Decorator without `Protocol`
def decorator(
func: Callable[Concatenate[X, P], T],
) -> Callable[Concatenate[X, P], T]:
# Do something with X
return func
In those two cases, mypy is happy and reports an int as expected:
note: Revealed type is "builtins.int"
Actual Behavior
Instead, mypy is confused and expects i to be a range:
note: Revealed type is "builtins.range"
error: "range" has no attribute "upper" [attr-defined]
Your Environment
- Mypy version used:
v1.4.1 and mypy 1.6.0+dev.d2022a0007c0eb176ccaf37a9aa54c958be7fb10 (compiled: no)
- Python version used:
3.10.4 and 3.11
Bug Report
I found a really weird bug while writing a decorator that returns a
Protocolthat itself uses a concatenatedParamSpec. I managed to get to a small reproducible example:Playground link
Expected Behavior
It works as expected using either one of those two decorators instead:
In those two cases, mypy is happy and reports an
intas expected:Actual Behavior
Instead, mypy is confused and expects
ito be arange:Your Environment
v1.4.1andmypy 1.6.0+dev.d2022a0007c0eb176ccaf37a9aa54c958be7fb10 (compiled: no)3.10.4and3.11