Skip to content

Use types.CoroutineType instead of typing.Coroutine #19288

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4704,7 +4704,7 @@ def type_requires_usage(self, typ: Type) -> tuple[str, ErrorCode] | None:
if isinstance(proper_type, Instance):
# We use different error codes for generic awaitable vs coroutine.
# Coroutines are on by default, whereas generic awaitables are not.
if proper_type.type.fullname == "typing.Coroutine":
if proper_type.type.fullname == "types.CoroutineType":
return ("Are you missing an await?", UNUSED_COROUTINE)
if proper_type.type.get("__await__") is not None:
return ("Are you missing an await?", UNUSED_AWAITABLE)
Expand Down
2 changes: 1 addition & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -6336,7 +6336,7 @@ def is_async_def(t: Type) -> bool:
and len(t.args) >= 4
):
t = get_proper_type(t.args[3])
return isinstance(t, Instance) and t.type.fullname == "typing.Coroutine"
return isinstance(t, Instance) and t.type.fullname == "types.CoroutineType"


def is_non_empty_tuple(t: Type) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,7 @@ def return_type_incompatible_with_supertype(
isinstance(original, Instance)
and isinstance(override, Instance)
and override.type.fullname == "typing.AsyncIterator"
and original.type.fullname == "typing.Coroutine"
and original.type.fullname == "types.CoroutineType"
and len(original.args) == 3
and original.args[2] == override
):
Expand Down
7 changes: 3 additions & 4 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1029,12 +1029,11 @@ def analyze_func_def(self, defn: FuncDef) -> None:
pass
else:
# A coroutine defined as `async def foo(...) -> T: ...`
# has external return type `Coroutine[Any, Any, T]`.
# has external return type `CoroutineType[Any, Any, T]`.
any_type = AnyType(TypeOfAny.special_form)
ret_type = self.named_type_or_none(
"typing.Coroutine", [any_type, any_type, defn.type.ret_type]
ret_type = self.named_type(
"types.CoroutineType", [any_type, any_type, defn.type.ret_type]
)
assert ret_type is not None, "Internal error: typing.Coroutine not found"
defn.type = defn.type.copy_modified(ret_type=ret_type)
self.wrapped_coro_return_types[defn] = defn.type

Expand Down
14 changes: 14 additions & 0 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ def __invert__(self: _T) -> _T: pass
__rxor__ = __xor__
"""

stubtest_types_stub = """
from typing import Coroutine, TypeVar

_T = TypeVar('_T')
_U = TypeVar('_U')
_V = TypeVar('_V')

class CoroutineType(Coroutine[_T, _U, _V]):
pass
"""


def run_stubtest_with_stderr(
stub: str, runtime: str, options: list[str], config_file: str | None = None
Expand All @@ -168,6 +179,8 @@ def run_stubtest_with_stderr(
f.write(stubtest_typing_stub)
with open("enum.pyi", "w") as f:
f.write(stubtest_enum_stub)
with open("types.pyi", "w") as f:
f.write(stubtest_types_stub)
with open(f"{TEST_MODULE_NAME}.pyi", "w") as f:
f.write(stub)
with open(f"{TEST_MODULE_NAME}.py", "w") as f:
Expand Down Expand Up @@ -292,6 +305,7 @@ class X:

@collect_cases
def test_coroutines(self) -> Iterator[Case]:
yield Case(stub="import types", runtime="import types", error=None)
yield Case(stub="def bar() -> int: ...", runtime="async def bar(): return 5", error="bar")
# Don't error for this one -- we get false positives otherwise
yield Case(stub="async def foo() -> int: ...", runtime="def foo(): return 5", error=None)
Expand Down
43 changes: 24 additions & 19 deletions test-data/unit/check-async-await.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async def f() -> int:

async def f() -> int:
return 0
_ = reveal_type(f()) # N: Revealed type is "typing.Coroutine[Any, Any, builtins.int]"
_ = reveal_type(f()) # N: Revealed type is "types.CoroutineType[Any, Any, builtins.int]"
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

Expand Down Expand Up @@ -53,6 +53,7 @@ async def f(x: T) -> T:
y = await f(x)
reveal_type(y)
return y
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
[out]
main:6: note: Revealed type is "T`-1"
Expand All @@ -65,6 +66,7 @@ async def f(x: T) -> T:
y = await f(x) # type: Any
reveal_type(y)
return y
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
[out]
main:6: note: Revealed type is "Any"
Expand All @@ -77,6 +79,7 @@ async def f(x: T) -> T:
y = await f(x) # type: int
reveal_type(y)
return x
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
[out]
main:5: error: Argument 1 to "f" has incompatible type "T"; expected "int"
Expand All @@ -92,6 +95,7 @@ async def f() -> int:
x = await g()
return x
[typing fixtures/typing-async.pyi]
[builtins fixtures/async_await.pyi]
[out]
main:7: error: Incompatible types in "await" (actual type "Generator[int, None, str]", expected type "Awaitable[Any]")

Expand All @@ -103,6 +107,7 @@ def g() -> Iterator[Any]:
async def f() -> int:
x = await g()
return x
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
[out]
main:6: error: Incompatible types in "await" (actual type "Iterator[Any]", expected type "Awaitable[Any]")
Expand Down Expand Up @@ -177,7 +182,7 @@ async def f() -> None:
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
[out]
main:7: error: "Coroutine[Any, Any, AsyncGenerator[str, None]]" has no attribute "__aiter__" (not async iterable)
main:7: error: "CoroutineType[Any, Any, AsyncGenerator[str, None]]" has no attribute "__aiter__" (not async iterable)
main:7: note: Maybe you forgot to use "await"?

[case testAsyncForErrorCanBeIgnored]
Expand Down Expand Up @@ -381,7 +386,7 @@ def g() -> Generator[Any, None, str]:
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
[out]
main:6: error: "yield from" can't be applied to "Coroutine[Any, Any, str]"
main:6: error: "yield from" can't be applied to "CoroutineType[Any, Any, str]"

[case testAwaitableSubclass]

Expand Down Expand Up @@ -453,7 +458,7 @@ async def h() -> None:
async def wrong_return() -> Generator[int, None, None]: # E: The return type of an async generator function should be "AsyncGenerator" or one of its supertypes
yield 3

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncGeneratorReturnIterator]
Expand All @@ -468,7 +473,7 @@ async def use_gen() -> None:
async for item in gen():
reveal_type(item) # N: Revealed type is "builtins.int"

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncGeneratorManualIter]
Expand All @@ -485,7 +490,7 @@ async def user() -> None:

reveal_type(await gen.__anext__()) # N: Revealed type is "builtins.int"

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncGeneratorAsend]
Expand All @@ -505,7 +510,7 @@ async def h() -> None:
await g.asend(()) # E: Argument 1 to "asend" of "AsyncGenerator" has incompatible type "tuple[()]"; expected "str"
reveal_type(await g.asend('hello')) # N: Revealed type is "builtins.int"

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncGeneratorAthrow]
Expand All @@ -523,7 +528,7 @@ async def h() -> None:
reveal_type(v) # N: Revealed type is "builtins.str"
reveal_type(await g.athrow(BaseException)) # N: Revealed type is "builtins.str"

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncGeneratorNoSyncIteration]
Expand All @@ -549,7 +554,7 @@ async def f() -> AsyncGenerator[int, None]:
async def gen() -> AsyncGenerator[int, None]:
yield from f() # E: "yield from" in async function

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncGeneratorNoReturnWithValue]
Expand Down Expand Up @@ -588,7 +593,7 @@ async def test_implicit_generators() -> None:
reveal_type(x for x in await get_list()) # N: Revealed type is "typing.Generator[builtins.int, None, None]"
reveal_type(x for _ in [1] for x in await get_list()) # N: Revealed type is "typing.AsyncGenerator[builtins.int, None]"

[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]


Expand Down Expand Up @@ -641,9 +646,9 @@ def plain_host_generator() -> Generator[str, None, None]:
yield 'a'
x = 0
x = yield from plain_generator()
x = yield from plain_coroutine() # E: "yield from" can't be applied to "Coroutine[Any, Any, int]"
x = yield from plain_coroutine() # E: "yield from" can't be applied to "CoroutineType[Any, Any, int]"
x = yield from decorated_generator()
x = yield from decorated_coroutine() # E: "yield from" can't be applied to "AwaitableGenerator[Any, Any, int, Coroutine[Any, Any, int]]"
x = yield from decorated_coroutine() # E: "yield from" can't be applied to "AwaitableGenerator[Any, Any, int, CoroutineType[Any, Any, int]]"
x = yield from other_iterator()
x = yield from other_coroutine() # E: "yield from" can't be applied to "Aw"

Expand Down Expand Up @@ -721,7 +726,7 @@ async def f(x: str) -> str: ...
async def f(x):
pass

reveal_type(f) # N: Revealed type is "Overload(def (x: builtins.int) -> typing.Coroutine[Any, Any, builtins.int], def (x: builtins.str) -> typing.Coroutine[Any, Any, builtins.str])"
reveal_type(f) # N: Revealed type is "Overload(def (x: builtins.int) -> types.CoroutineType[Any, Any, builtins.int], def (x: builtins.str) -> types.CoroutineType[Any, Any, builtins.str])"
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

Expand All @@ -738,7 +743,7 @@ async def g() -> None:
forwardref: C
class C: pass

reveal_type(f) # N: Revealed type is "def () -> typing.Coroutine[Any, Any, None]"
reveal_type(f) # N: Revealed type is "def () -> types.CoroutineType[Any, Any, None]"
reveal_type(g) # N: Revealed type is "Any"
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
Expand Down Expand Up @@ -832,7 +837,7 @@ class B:
def bar() -> None:
A() # E: Value of type "A" must be used [unused-awaitable] \
# N: Are you missing an await?
foo() # E: Value of type "Coroutine[Any, Any, None]" must be used [unused-coroutine] \
foo() # E: Value of type "CoroutineType[Any, Any, None]" must be used [unused-coroutine] \
# N: Are you missing an await?
B()

Expand Down Expand Up @@ -891,12 +896,12 @@ class Custom(Generic[T]):
class Sub(Custom[T]): ...

async def test(x: Sub[D], tx: Type[Sub[D]]) -> None:
foo().x # E: "Coroutine[Any, Any, D]" has no attribute "x" \
foo().x # E: "CoroutineType[Any, Any, D]" has no attribute "x" \
# N: Maybe you forgot to use "await"?
(await foo()).x
foo().bad # E: "Coroutine[Any, Any, D]" has no attribute "bad"
foo().bad # E: "CoroutineType[Any, Any, D]" has no attribute "bad"

g(foo()) # E: Argument 1 to "g" has incompatible type "Coroutine[Any, Any, D]"; expected "C" \
g(foo()) # E: Argument 1 to "g" has incompatible type "CoroutineType[Any, Any, D]"; expected "C" \
# N: Maybe you forgot to use "await"?
g(await foo())
unknown: Awaitable[Any]
Expand Down Expand Up @@ -1073,7 +1078,7 @@ class P(Protocol):
raise BaseException

class Launcher(P):
def launch(self) -> AsyncIterator[int]: # E: Return type "AsyncIterator[int]" of "launch" incompatible with return type "Coroutine[Any, Any, AsyncIterator[int]]" in supertype "P" \
def launch(self) -> AsyncIterator[int]: # E: Return type "AsyncIterator[int]" of "launch" incompatible with return type "CoroutineType[Any, Any, AsyncIterator[int]]" in supertype "P" \
# N: Consider declaring "launch" in supertype "P" without "async" \
# N: See https://mypy.readthedocs.io/en/stable/more_types.html#asynchronous-iterators
raise BaseException
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-class-namedtuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -490,12 +490,12 @@ class XRepr(NamedTuple):
return 0

reveal_type(XMeth(1).double()) # N: Revealed type is "builtins.int"
_ = reveal_type(XMeth(1).asyncdouble()) # N: Revealed type is "typing.Coroutine[Any, Any, builtins.int]"
_ = reveal_type(XMeth(1).asyncdouble()) # N: Revealed type is "types.CoroutineType[Any, Any, builtins.int]"
reveal_type(XMeth(42).x) # N: Revealed type is "builtins.int"
reveal_type(XRepr(42).__str__()) # N: Revealed type is "builtins.str"
reveal_type(XRepr(1, 2).__sub__(XRepr(3))) # N: Revealed type is "builtins.int"
[typing fixtures/typing-async.pyi]
[builtins fixtures/tuple.pyi]
[builtins fixtures/async_await.pyi]

[case testNewNamedTupleOverloading]
from typing import NamedTuple, overload
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-errorcodes.test
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ async def asyncf(): # E: Function is missing a return type annotation [no-unty
async def asyncf2(x: int): # E: Function is missing a return type annotation [no-untyped-def]
return 0
[typing fixtures/typing-async.pyi]
[builtins fixtures/tuple.pyi]
[builtins fixtures/async_await.pyi]

[case testErrorCodeCallUntypedFunction]
# flags: --disallow-untyped-calls
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ async def g() -> NoReturn:
async def h() -> NoReturn: # E: Implicit return in function which does not return
# Purposely not evaluating coroutine
_ = f()
[builtins fixtures/dict.pyi]
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testNoWarnNoReturn]
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -3544,7 +3544,7 @@ def decorator2(f: Callable[P, None]) -> Callable[
def key2(x: int) -> None:
...

@decorator2(key2) # E: Argument 1 has incompatible type "Callable[[Arg(int, 'y')], Coroutine[Any, Any, None]]"; expected "Callable[[Arg(int, 'x')], Awaitable[None]]"
@decorator2(key2) # E: Argument 1 has incompatible type "Callable[[Arg(int, 'y')], CoroutineType[Any, Any, None]]"; expected "Callable[[Arg(int, 'x')], Awaitable[None]]"
async def foo2(y: int) -> None:
...

Expand All @@ -3555,7 +3555,7 @@ class Parent:
class Child(Parent):
method_without: Callable[[], "Child"]
method_with: Callable[[str], "Child"] # E: Incompatible types in assignment (expression has type "Callable[[str], Child]", base class "Parent" defined the type as "Callable[[Arg(str, 'param')], Parent]")
[builtins fixtures/tuple.pyi]
[builtins fixtures/async_await.pyi]

[case testDistinctFormattingUnion]
from typing import Callable, Union
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-python311.test
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async def asynciter(iterable):

async def coro() -> Generator[List[Any], None, None]:
return ([i async for i in asynciter([0,j])] for j in [3, 5])
reveal_type(coro) # N: Revealed type is "def () -> typing.Coroutine[Any, Any, typing.Generator[builtins.list[Any], None, None]]"
reveal_type(coro) # N: Revealed type is "def () -> types.CoroutineType[Any, Any, typing.Generator[builtins.list[Any], None, None]]"
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

Expand Down
5 changes: 3 additions & 2 deletions test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ reveal_type(f(1)) # N: Revealed type is "builtins.int"
async def g[T](x: T) -> T:
return reveal_type(x) # N: Revealed type is "T`-1"

reveal_type(g(1)) # E: Value of type "Coroutine[Any, Any, int]" must be used \
reveal_type(g(1)) # E: Value of type "CoroutineType[Any, Any, int]" must be used \
# N: Are you missing an await? \
# N: Revealed type is "typing.Coroutine[Any, Any, builtins.int]"
# N: Revealed type is "types.CoroutineType[Any, Any, builtins.int]"
[builtins fixtures/async_await.pyi]

[case testPEP695TypeVarBasic]
from typing import Callable
Expand Down
6 changes: 3 additions & 3 deletions test-data/unit/check-unreachable-code.test
Original file line number Diff line number Diff line change
Expand Up @@ -1300,7 +1300,7 @@ async def f_no_suppress_5() -> int:
noop() # E: Statement is unreachable

[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
[builtins fixtures/async_await.pyi]

[case testUnreachableFlagContextAsyncManagersSuppressed]
# flags: --warn-unreachable
Expand Down Expand Up @@ -1346,7 +1346,7 @@ async def f_mix() -> int: # E: Missing return statement
return 3
noop()
[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
[builtins fixtures/async_await.pyi]

[case testUnreachableFlagContextAsyncManagersAbnormal]
# flags: --warn-unreachable
Expand Down Expand Up @@ -1397,7 +1397,7 @@ async def f_malformed_2() -> int:
noop() # E: Statement is unreachable

[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
[builtins fixtures/async_await.pyi]

[case testUnreachableUntypedFunction]
# flags: --warn-unreachable
Expand Down
1 change: 1 addition & 0 deletions test-data/unit/deps-expressions.test
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ async def g() -> None:
[typing fixtures/typing-async.pyi]
[out]
<m.f> -> m.g
<types.CoroutineType> -> <m.g>, m.g

[case testStarExpr]
from typing import Iterator
Expand Down
1 change: 1 addition & 0 deletions test-data/unit/fixtures/async_await.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import types
import typing

T = typing.TypeVar('T')
Expand Down
Loading
Loading