-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Failed TypeVar
substitution by asynccontextmanager
#9922
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
Comments
This might be a typeshed bug; relevant definitions are for |
Note that mypy currently special cases contextlib.contextmanager (but doesn't special case contextlib.asynccontextmanager): Line 172 in 92923b2
This is something PEP 612 should help with. |
I think mypy is doing the right thing here given the current definition of I confirmed that it works as expected if the typeshed definition of _P = ParamSpec("_P")
def asynccontextmanager(func: Callable[_P, AsyncIterator[_T]]) -> Callable[_P, AsyncContextManager[_T]]: ... We need to wait for python/typeshed#4827. |
I looked into how I tried to add a regression test, by copying over the non-async version, but it seems to fail, unable to find A unit test using minimal stubs works though. And I believe this test more accurately reflects the issue. Please let me know what to do from here, if this fix can be used. |
PEP 612 targets Python 3.10. Does that mean special casing for < 3.10 will still be necessary? I would like to submit a temporary fix for it, but I am having trouble getting a unit test to work. Specifically, a test in #!/usr/bin/bash
# Check out into current directory if not already done.
if [ -z "$(ls -A .)" ]; then
git clone [email protected]:BoniLindsley/mypy.git . #
fi
# Make sure things are up to date.
git submodule update --init
python3 -m pip install --upgrade --requirement test-requirements.txt
# Add test if not already done.
test_file=test-data/unit/pythoneval.test
if ! grep testAsyncContextManager $test_file > /dev/null; then
cat << EOF >> test-data/unit/pythoneval.test
[case testAsyncContextManager]
# flags: --python-version 3.7
import contextlib
from contextlib import asynccontextmanager
from typing import AsyncIterator
@asynccontextmanager
async def f(x: int) -> AsyncIterator[str]:
yield 'foo'
@contextlib.asynccontextmanager
async def g(*x: str) -> AsyncIterator[int]:
yield 1
reveal_type(f)
reveal_type(g)
with f('') as s:
reveal_type(s)
[out]
_program.py:13: note: Revealed type is 'def (x: builtins.int) -> typing.AsyncContextManager[builtins.str*]'
_program.py:14: note: Revealed type is 'def (*x: builtins.str) -> typing.AsyncContextManager[builtins.int*]'
_program.py:16: error: Argument 1 to "f" has incompatible type "str"; expected "int"
_program.py:17: note: Revealed type is 'builtins.str*'
EOF
fi
# The actual test.
python3 -m pytest --quiet -k testAsyncContextManager The test is expected to fail, since this does not include the fix, and to produce a diff with wrong revealed types. But the error from it is instead
So, the question is, how do I make the test find Environment: Debian, pyenv, Python 3.9.1. |
Closes #9922 ### Description Extending the existing special case for `contextlib.contextmanager` to `contextlib.asynccontextmanager`. When used with `TypeVar` gives much better type. ## Test Plan I hope I have included the unit test you need. My minimal reproduction is: ``` from contextlib import asynccontextmanager from typing import AsyncGenerator, Type, TypeVar R = TypeVar("R") @asynccontextmanager async def foo( cls: Type[R], ) -> AsyncGenerator[R, None]: yield cls() async def bar() -> int: async with foo(int) as foo_int: return ( foo_int # error: Incompatible return value type (got "R", expected "int") ) ```
Closes python#9922 ### Description Extending the existing special case for `contextlib.contextmanager` to `contextlib.asynccontextmanager`. When used with `TypeVar` gives much better type. ## Test Plan I hope I have included the unit test you need. My minimal reproduction is: ``` from contextlib import asynccontextmanager from typing import AsyncGenerator, Type, TypeVar R = TypeVar("R") @asynccontextmanager async def foo( cls: Type[R], ) -> AsyncGenerator[R, None]: yield cls() async def bar() -> int: async with foo(int) as foo_int: return ( foo_int # error: Incompatible return value type (got "R", expected "int") ) ```
Bug Report
Return type of
contextlib.asynccontextmanager
does not substitutetyping.TypeVar
determined from parameters.To Reproduce
Pass the following script to
mypy
, usingmypy --config-file= main.py
or otherwise.Expected Behavior
The type of
number
should beint
. In particular, assignment of the integer2
to it should be compatible, and somypy
should return without errors.Actual Behavior
The variable
number
is assigned, what I assume, is theTypeVar
. This leads to an incompatible assignment of2
.As a side note, a non-
async
counterpart of this behaves as expected, and does not produce any errors.Your Environment
--config-file=
mypy.ini
(and other config files): Not applicable.Debian bullseye/sid
andWindows 10 version 1909 build 18363.1256
The text was updated successfully, but these errors were encountered: