Reputation: 3699
Consider the following code:
from aiohttp_mako import template
def authorize():
def wrapper(func):
@asyncio.coroutine
@functools.wraps(func)
def wrapped(*args):
allowed = # Some auth stuff
if not allowed:
return HTTPUnauthorized()
return func()
return wrapped
return wrapper
@authorize()
@template('admin.mak')
async def admin(request):
return dict(ok=True)
I expect authorize()
' wrapper
to get template
decorator as its func
so I can return the Response
it generates in my authorize
decorator. But authorize()
' wrapper
takes the admin()
coroutine as the func
and it ends up with
File "/Users/etemin/virtualenvs/onlinelux/lib/python3.5/site-packages/aiohttp/web.py", line 306, in _handle
resp = yield from handler(request)
File "/Users/etemin/virtualenvs/onlinelux/lib/python3.5/site-packages/aiohttp_session/__init__.py", line 134, in middleware
raise RuntimeError("Expect response, not {!r}", type(response))
RuntimeError: ('Expect response, not {!r}', <class 'generator'>)
Cause it tries to return the coroutine. How should I make it to return the template
decorator?
Upvotes: 2
Views: 1606
Reputation: 583
This is what worked for me.
Inspired from @aiohttp_csrf.csrf_protect.
from functools import wraps
from aiohttp import web
def is_authorized(request):
# Write logic to validate request
return True
def authorize(handler=None): # When python module having view was imported, it expected to have this.
def wrapper(handler):
@wraps(handler)
async def wrapped(*args, **kwargs):
request = args[-1]
if isinstance(request, web.View):
# Should also work for Class-Based Views
request = request.request
try:
is_authorized(request)
except Exception as ex:
# request not authorized. Write logic to handle it accordingly
print('Request not authorized: ', repr(ex))
raise ex
response = await handler(*args, **kwargs)
return response
return wrapped
if handler is None:
return wrapper
return wrapper(handler)
Somewhere in your view:
@authorize()
@template('admin.mak')
async def admin(request):
return dict(ok=True)
Upvotes: 0
Reputation: 1121644
You have wrapped a co-routine, so you need to await that co-routine (yield from it):
def authorize():
def wrapper(func):
@asyncio.coroutine
@functools.wraps(func)
def wrapped(*args):
allowed = # Some auth stuff
if not allowed:
return HTTPUnauthorized()
return yield from func()
return wrapped
return wrapper
Since you are already using the async
/await
syntax, I'd just use that here too and not use @asyncio.coroutine
:
def authorize():
async def wrapper(func):
@functools.wraps(func)
async def wrapped(*args):
allowed = # Some auth stuff
if not allowed:
return HTTPUnauthorized()
return await func()
return wrapped
return wrapper
Note that I awaited on func()
there, and returned the result.
Upvotes: 4