I’ve got a ‘problem’ in my code where mypy doesn’t register that I’ve typed things correctly, even though I think I have.
I’ve pared this down to a somewhat minimal example, which is below.
The following mypy does recognise things are correct:
import asyncio
from typing import Protocol
class P(Protocol):
async def __call__(self, a: int, b: int) -> bool: ...
class C:
async def m(self, a: int, b: int) -> bool:
return a < b
async def f(p: P) -> bool:
ans = await p(a=1, b=2)
return ans
async def g():
c = C()
ans = await f(c.m)
print(ans)
asyncio.run(g())
and here it does not:
from datetime import datetime
from typing import Protocol
from attrs import frozen
@frozen
class MyClass:
async def __aenter__(self) -> "MyClass":
return self
async def __aexit__(
self,
_exc_type: type[BaseException] | None,
_exc_value: BaseException | None,
_traceback: object,
) -> None:
pass
@classmethod
async def from_yaml(
cls,
) -> "MyClass":
return cls()
async def get_internal_trades(
self,
start_execution_time: datetime | None = None,
offset: int = 0,
page_size: int = 150,
) -> list["dict"]:
return []
class InternalTradesGetter(Protocol):
"""Type stub to represent a get_internal_trades function."""
async def __call__(
self,
start_execution_time: datetime | None,
offset: int,
limit: int,
) -> list[dict]: ...
async def fun(trades_getter: InternalTradesGetter) -> None:
return None
async def main() -> None:
async with await MyClass.from_yaml() as pbc:
await fun(pbc.get_internal_trades)
Does anyone recognise what’s going on?
Is there a Python typing rule I missed?
The mypy error message is
Argument 1 to "fun" has incompatible type "Callable[[datetime | None, int, int], Coroutine[Any, Any, list[dict[Any, Any]]]]"; expected "InternalTradesGetter"
"InternalTradesGetter.__call__" has type "Callable[[Arg(datetime | None, 'start_execution_time'), Arg(int, 'offset'), Arg(int, 'limit')], Coroutine[Any, Any, list[dict[Any, Any]]]]"
so it seems that something here is causing information about the argument names to get discarded.