Proper RequestHandler for async usage

Skip to first unread message

Shane Spencer

Nov 25, 2020, 2:53:46 AM11/25/20
to Python Tornado
So here's my hack.. I don't like it.  It performs the task in a very ugly way.   Any suggestions on how to make a RequestHandler decorator that can wrap both sync and async functions and call an async defined function and gather the return value?

import functools

from typing import Awaitable, Callable, Optional

from tornado.web import HTTPError, RequestHandler

from something import somethingelse

def do_async_stuff_decorator(
    method: Callable[..., Optional[Awaitable[None]]]
) -> Callable[..., Optional[Awaitable[None]]]:
    async def wrapper(  # type: ignore
        self: RequestHandler, *args, **kwargs
    ) -> Optional[Awaitable[None]]:

        self.thing = await somethingelse()

        result = await method(self, *args, **kwargs)  # type: ignore

        return result

    return wrapper

Rajdeep Rath

Nov 25, 2020, 3:04:43 AM11/25/20
Looks interesting! What are you trying to achieve?

You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
To view this discussion on the web visit

Shane Spencer

Nov 25, 2020, 2:13:58 PM11/25/20
to Python Tornado
My use case here will be to validate roles for authorization to resources by way of async database fetches.

Ben Darnell

Nov 27, 2020, 11:54:05 AM11/27/20
to Tornado Mailing List
So something like the tornado.web.authenticated decorator with the ability to call async methods? You may want to look for old threads on "async get_current_user" for related discussions.

Personally, I no longer recommend decorators for this kind of thing. They're tricky to write and there's not much advantage to be able to say

    def get(self):

instead of

    async def get(self):
        await self.check_authentication()

It's true that if it's a line of code in the body of the method it's not easy to audit that all your handlers perform authentication correctly, but a decorator that could go on one or more of several methods isn't much better. (What I'd really like is something that could go in the URL routing table so that the authentication status of all your handlers would be visible in one place, but the Application/RequestHandler interface isn't really set up for that).

Anyway, if you want to use a decorator, my advice would be to have it consume the `Optional` aspect of the returned method's awaitable status:

    def decorator(f: Callable[..., Optional[Awaitable[None]]) -> Callable[..., Awaitable[None]]:
        async def wrapper(self, *args, **kwargs) -> None:
            self.thing = await somethingelse()
            result = f(*args, **kwargs)
            if result is not None:
                await result
        return wrapper

Note that your example doesn't type check (or maybe mypy isn't smart enough to understand this) because `async def wrapper` adds another level of Awaitable: the decorated function has type signature `Callable[..., Awaitable[Optional[Awaitable[None]]]]`, which is probably not what you want (and it's not compatible with the RequestHandler.get interface because nothing will await that inner awaitable).


Shane Spencer

Nov 28, 2020, 2:30:38 PM11/28/20
to Python Tornado
Thanks, I think I’m going to forgo with decorators as well since I need to use some complex arguments now.  I'll just await and raise as needed.

Rajdeep Rath

Nov 30, 2020, 3:45:56 AM11/30/20
Am very new to tornado, but i will share something i had tried (and worked) some time ago. not sure if it is helpful.



# Do something

Reply all
Reply to author
0 new messages