Typing: Document how to type hint for an async function used as a callback

Created on 7 May 2017  路  9Comments  路  Source: python/typing

I have (roughly) the following code:

async def foo(x: int): pass
callback = foo  # What does this type to?

The problem is I don't know what to type callback to. It isn't a Callable as mypy says that "Function does not return a value" when I call await callback(42). It isn't an AsyncIterable, AsyncIterator, or an AsyncGenerator as it simply isn't. It isn't a Coroutine as mypy says that they can't be called.

So am I missing something on how to type this, or does there need to be an AsyncCallable added to typing?

to do

Most helpful comment

I think you can use Callable[[int], Awaitable[None]].

All 9 comments

I think you can use Callable[[int], Awaitable[None]].

Yes, in general case it should be like this:

async def bar(x: int) -> str:
    return str(x)

cbar: Callable[[int], Awaitable[str]] = bar

So that in your case it should probably be:

async def foo(x: int): pass
callback: Callable[[int], Awaitable[None]] = foo

Also note that without an explicit return annotation for foo mypy infers Callable[[int], Awaitable[Any]], according to PEP 484 all missing annotations are treated as Any.

What are the exact steps to get Function does not return a value error? Are you using --strict-optional, a similar (spurious) error was reported recently in mypy, it can be quite misleading.

I've changed the title of this issue to make a documentation thing so that an example in the Callable docs and show how to do this.

@ilevkivskyi As for triggering the error, if I type hint the callback as Callable[[Any], None] it causes that error message.

From a newbie's point of view, it seems like Coroutine was added as a short-hand way to declare this (eg https://github.com/python/typing/issues/251) but I can't figure out how to use it in Python 3.6. Maybe I need 3.7.

I don't think 3.7 makes a difference here, and you more likely want Awaitable instead of Coroutine. What issues are you running into?

Maybe a better question is: is Coroutine documented somewhere with an example? I will use Callable[[int], Awaitable[None]] but I do not understand the generic Coroutine and it merely bugs me, nothing more. I can ignore it. Thank you.

Not sure, but there are very few contexts where you'd actually need it. To declare an async callback, you would use Awaitable like in Ivan's and my messages further up in this thread.

I see the return value of an async function is now Coroutine instead of Awaitable. At any rate, this explains why Callable should be used instead of Coroutine. https://github.com/python/mypy/commit/6519eb6fb314d4a3dfbdd12e9269271a2bdc2f66

Callable[[int], Awaitable[None]] is as well satisfied by any def without async keyword which returns asyncio Future, Task or coroutine object. Type Coroutine specifies awaitables which support send() and throw() methods and the complete type is Coroutine[send_type, throw_type, return_type], each parameter is covariant.

Coroutine[Any, Any, None] is the inferred type which is returned by your async def taking int and returning None when executed without await.

Future/Task means you allow to schedule/execute tasks before a callback function starts or returns. Unlike when returning coroutine object which is scheduled at the code line where you await async def. If Future/Task should be disallowed then the type of the callback would have to be Callable[[int], Coroutine[Any, Any, None]]. It still supports plain def which returns coroutine object but it should not matter.

And a closing note because of the similarity, Generator[send_type, throw_type, return_type] is an unrelated type to Coroutine[send_type, throw_type, return_type] hence they are not allowed as a callback nor async functions defined via @asyncio.coroutine annotation.

Welcome to simplicity of typing:)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LiraNuna picture LiraNuna  路  7Comments

saulshanabrook picture saulshanabrook  路  6Comments

JelleZijlstra picture JelleZijlstra  路  6Comments

matthiaskramm picture matthiaskramm  路  6Comments

scherrey picture scherrey  路  3Comments