Open Apakottur opened 1 year ago
I created a new test file and ran pytest with your exact code on Python 3.11 and it seemed to pass. Let me know if i missed anything.
[case checkasync]
# flags: --python-version 3.11
from typing import Generic, TypeVar
T = TypeVar("T")
class Cls(Generic[T]):
pass
def create_cls(arg: T) -> Cls[tuple[T]]:
return Cls()
async def inner(var: Cls[tuple[T]]) -> T | None:
return None
async def outer(x: int) -> int | None:
c = create_cls(x)
return await inner(c)
[builtins fixtures/tuple.pyi]
I'm getting the same results as you, the unit test is passing. However running the mypy executable directly on the code still yields the issue. What can lead to a difference between the unit test and the regular execution?
Here's an even smaller snippet to reproduce the error:
from typing import Generic, TypeVar
T = TypeVar("T")
class Cls(Generic[T]):
pass
async def inner(c: Cls[T]) -> T | None:
return None
async def outer(c: Cls[T]) -> T | None:
return await inner(c)
I'll check it out tonight? My guess is the pytest does not run the same code on the file as the regular execution ? Maybe we can collaborate on this issue on discord if you have one.
Made some progress, here's an even simpler snippet that also fails in the mypy unit tests:
from typing import Generic, TypeVar
T = TypeVar("T")
class Cls(Generic[T]):
pass
def inner(c: Cls[T]) -> T | int:
return 1
def outer(c: Cls[T]) -> T | int:
return inner(c)
There's no async/await even, so it seems to be a problem purely with generics.
mypy can sometimes over eagerly use type context in cases like this. Removing type context by putting it on its own line can often fix (as can supplying exactly the context you want via annotation). That is:
def outer(c: Cls[T]) -> T | int:
ret = inner(c)
return ret
Using a covariant type var would also "fix", if acceptable in your real world case.
Thanks for the reply @hauntsaninja !
In case it matters, my real world case involves the Select class from SQLAlchemy, and the .one_or_none
function which has the same T -> T | None
pattern.
I have hundreds of instances of this issue, so having to create a variable every time is not ideal (not to mention that linters like Ruff will try to optimize this statement and remove the variable).
Using covariant
does work but requires some extra hacking because this happens in a 3rd party lib.
I've made a PR that fixes the issue based on your comment, which also fixes the issue in my real world case.
Bug report
Mypy is not consistent between sync and async variants of the same code.
How to reproduce
Consider the following code:
Running
mypy test.py
yields no errors, as expected.However, if we make the functions async:
Then running
mypy test.py
gives:Expected Behavior
Mypy should give no errors in the async case, there's no difference in any of the function signatures.
Your Environment
mypy 1.5.0 (compiled: yes)
mypy.ini
(and other config files): None