-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
add TypeGuard to coroutines.iscoroutine #6105
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
add TypeGuard to coroutines.iscoroutine #6105
Conversation
This comment has been minimized.
This comment has been minimized.
e99357f
to
e651582
Compare
This comment has been minimized.
This comment has been minimized.
e651582
to
e0f3194
Compare
This comment has been minimized.
This comment has been minimized.
34226dd
to
d79e080
Compare
This comment has been minimized.
This comment has been minimized.
63b8dd7
to
667b6b6
Compare
This comment has been minimized.
This comment has been minimized.
667b6b6
to
d32644a
Compare
Would it be possible if I could get some Hacktoberfest brownie points? |
This comment has been minimized.
This comment has been minimized.
3 similar comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
make CoroutineType extend Coroutine
stdlib/asyncio/coroutines.pyi
Outdated
|
||
_F = TypeVar("_F", bound=Callable[..., Any]) | ||
|
||
def coroutine(func: _F) -> _F: ... | ||
def iscoroutinefunction(func: object) -> bool: ... | ||
def iscoroutine(obj: object) -> bool: ... | ||
def iscoroutine(obj: object) -> TypeGuard[types.GeneratorType[Any, Any, Any] | Coroutine[Any, Any, Any]]: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we should try just returning TypeGuard[Coroutine[Any, Any, Any]]
here. This will hopefully resolve the primer problems. Generator-based coroutines are deprecated/not supported anymore anyway, but if we were to supported them, we'd need to use collections.abc.Generator[Any, Any, Any]
, instead of GeneratorType
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe GeneratorType
is correct here, as the actual implementation uses GeneratorType
to do the check.
from asyncio import iscoroutine
from collections.abc import Generator
class MyGenerator(Generator):
def send(self, __value):
pass
def throw(self, __typ, __val = ..., __tb = ...):
pass
def foo(): yield 1
print(iscoroutine(MyGenerator())) # False
print(iscoroutine(foo())) # True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entire use case of asyncio.iscoroutine
compared to inspect.iscoroutine
is that it checks for generators. so mistyping it to please primer sounds like the wrong way to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two options here, per our recommendations to avoid union return types: Use just Coroutine
or keep returning bool
. In this case, considering the deprecation of generator coroutines, using TypeGuard[Coroutine]
seems like the better option. Primer output actually proves that using a union return type is not serving our users well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get what you're saying, but I think given the close relationship between asyncio.iscoroutine
and inspect.iscoroutine
, where the latter checks for just async
coroutines and the former checks for all types, I think it would be a mistake to type this as just Coroutine
, I think it would lead to confusing edge cases where generator style coroutines aren't expected and the developer should have been using inspect.iscoroutine
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double actually, I think it should narrow to GeneratorType
, because of:
from asyncio import iscoroutine, run
def do_something1(x: object):
if iscoroutine(x):
x.cr_await
async def do_something2(x: object):
if iscoroutine(x):
await x
do_something1(_ for _ in ())
run(do_something2(_ for _ in ()))
This has nothing at all to do with using deprecated @coroutine
s and is just generic code that will now have runtime errors but no type errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although if you ask me the implementation of iscoroutine
should be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a note, in encode/httpx#2269 where we have this kind of usage:
response = func_maybe_async()
if asyncio.iscoroutine(response):
response = await response
We had to narrow down to TypeGuard[Coroutine]
ourselves because on py3.7 mypy
would raise an error due to Generator
not being awaitable.
It turns out that mypy
types the result of coroutine functions defined as @asyncio.coroutine()
as AwaitableGenerator
which mypy is OK to await
. Running with check_untyped_defs = True
:
import asyncio
@asyncio.coroutine
def wait():
yield from asyncio.sleep(1)
async def main():
coro = wait()
reveal_type(coro) # AwaitableGenerator[Any, Any, Any, Any]
await coro # OK
So it's actually impossible to get a coroutine that would be a Generator
at runtime (generators can't be await
-ed).
So maybe the correct pre-3.8 annotation would have been Union[AwaitableGenerator, Coroutine]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, raised it here #8114
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's here #8104
d32644a
to
b14b764
Compare
This comment has been minimized.
This comment has been minimized.
71d8f5b
to
a0e3499
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
Diff from mypy_primer, showing the effect of this PR on open source code: core (https://github.com/home-assistant/core.git)
+ homeassistant/helpers/service.py:703: error: unused "type: ignore" comment
aiohttp (https://github.com/aio-libs/aiohttp.git)
+ aiohttp/web.py:307: error: unused "type: ignore" comment
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
No description provided.