Skip to content
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

Shorthand for async function #663

Open
retnikt opened this issue Aug 2, 2019 · 8 comments
Open

Shorthand for async function #663

retnikt opened this issue Aug 2, 2019 · 8 comments
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@retnikt
Copy link

retnikt commented Aug 2, 2019

Following on from #424, it would be nice to have something like AsyncFunction[[Args], ReturnType] instead of Callable[[Args], Coroutine[ReturnType]].

@ilevkivskyi
Copy link
Member

TBH, I don't think this is a big win in terms of readability or number of keystrokes. I think however we can keep this open to see if anyone else is interested in such "shorthand", since implementing this is pretty easy.

@retnikt
Copy link
Author

retnikt commented Sep 14, 2019

If this does ever get approved, it should be noted that GeneratorFunction could be useful too.

@lig
Copy link

lig commented Nov 26, 2019

I would like to provide a simple sample that literally cries for a shorthand.

This is a sample from aiohttp.web docs https://docs.aiohttp.org/en/stable/web_advanced.html#middleware-factory which when annotated looks like this:

import typing

from aiohttp import web


def middleware_factory(
    text: str
) -> typing.Callable[
    [web.Request, typing.Callable[[web.Request], typing.Awaitable[web.Response]]],
    typing.Awaitable[web.Response],
]:
    @web.middleware
    async def sample_middleware(
        request: web.Request,
        handler: typing.Callable[[web.Request], typing.Awaitable[web.Response]],
    ) -> web.Response:
        resp = await handler(request)
        resp.text = (resp.text if resp.text is not None else '') + text
        return resp

    return sample_middleware

The shorthand would probably remove only typing.Awaitable things but it looks like the code will look quite a bit more understandable.

@rmorshea
Copy link

rmorshea commented Jan 13, 2020

I think an additional readability benefit beyond character count is that the async vs not-async distinction is front-loaded in the spec. Currently you must look at the end of the Callable declaration to know whether it's an async function. Consider the following type specs:

F1 = Callable[[Dict[str, Any], str, Any], Iterable[str]]
F2 = Callable[[Dict[str, Any], str, Any], Awaitable[str]]

When I read this, by the time I get through the parameter spec my brain is telling me that F1 and F2 are really similar and can be called the same way, even though I have to read one step further to learn that the return value indicates that the latter must be awaited. IMO we should front load this information so that the difference is much more obvious:

F1 = Callable[[Dict[str, Any], str, Any], Iterable[str]]
F2 = AsyncCallable[[Dict[str, Any], str, Any], str]

@JukkaL
Copy link
Contributor

JukkaL commented Jan 14, 2020

To get a better idea of how big the impact might be, it would be interesting to see some statistics about how frequently this could be used in some non-trivial real-world async codebase. For example, if there are two instances in a 5000-line codebase where this would help, the benefit would be pretty marginal, but if there are 50 instances, this could be a big potential win.

@retnikt
Copy link
Author

retnikt commented Jan 21, 2020

Example Codebase: Starlette

$ find starlette/ -name '*.py' | xargs wc -l
[...]
 10151 total
$ grep -re 'Callable\[.*Awaitable.*\]' starlette/ | wc -l
6

6 instances in a 10k line codebase, so perhaps not a massive priority, but I see no reason not to add it?

@reillysiemens
Copy link

Example Codebase: Faust

$ find faust/ -name '*.py' | xargs wc -l
[...]
  62709 total
$ grep -re 'Callable\[.*Awaitable.*\]' faust/ | wc -l
26

26 instances in a 62k line codebase, so like @retnikt said, perhaps not a massive priority.

That said, @rmorshea's argument really speaks to me. Even if AsyncCallable[[Args], ReturnType] is just a shorthand for Callable[[Args], Awaitable[ReturnType]] I think there are some major readability benefits. I'd personally prefer to write the former if possible.

Unless I'm mistaken there may already be some prior art in the form of names like AsyncIterable, AsyncContextManager, AsyncGenerator and friends.

@lig
Copy link

lig commented Mar 28, 2020

The question is how often there is # type: ignore in such a place as its almost impossible to guess this correctly or write directly from one's memory.

@srittau srittau added the topic: feature Discussions about new features for Python's type annotations label Nov 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

7 participants