Skip to content

Commit

Permalink
Fix #186: Automatically force aiohttp.web handlers to coroutines
Browse files Browse the repository at this point in the history
  • Loading branch information
asvetlov committed Dec 7, 2014
1 parent e8309c7 commit 5a63708
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 17 deletions.
15 changes: 9 additions & 6 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ CHANGES
0.12.0 (Unreleased)
-------------------

- Rename Request.POST() function to Request.post()
- Automatically force aiohttp.web handlers to coroutines in
`UrlDispatcher.add_route()` #186

- Rename `Request.POST()` function to `Request.post()`

- Added POST attribute

Expand All @@ -14,15 +17,15 @@ CHANGES

- Exceptions refactoring

- Do not unquote path in aiohttp.web.Request
- Do not unquote query string in `aiohttp.web.Request`

- Fix concurrent access to payload in RequestHandle.handle_request()
- Fix concurrent access to payload in `RequestHandle.handle_request()`

- Add access logging to aiohttp.web
- Add access logging to `aiohttp.web`

- Gunicorn worker for aiohttp.web
- Gunicorn worker for `aiohttp.web`

- Removed deprecated AsyncGunicornWorker
- Removed deprecated `AsyncGunicornWorker`


0.11.0 (11-29-2014)
Expand Down
7 changes: 3 additions & 4 deletions aiohttp/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,8 @@ def _register_endpoint(self, route):
def add_route(self, method, path, handler, *, name=None):
assert path.startswith('/')
assert callable(handler), handler
if not asyncio.iscoroutinefunction(handler):
handler = asyncio.coroutine(handler)
method = method.upper()
assert method in self.METHODS, method
parts = []
Expand Down Expand Up @@ -1168,10 +1170,7 @@ def handle_request(self, message, payload):
request._match_info = match_info
handler = match_info.handler

resp = handler(request)
if (asyncio.iscoroutine(resp) or
isinstance(resp, asyncio.Future)):
resp = yield from resp
resp = yield from handler(request)
if not isinstance(resp, StreamResponse):
raise RuntimeError(
("Handler should return response instance, got {!r}")
Expand Down
3 changes: 3 additions & 0 deletions docs/web.rst
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,9 @@ Router is any object that implements :class:`AbstractRouter` interface.
*variable rule* like ``'/a/{var}'`` (see
:ref:`handling variable pathes<aiohttp-web-variable-handler>`)

Pay attention please: *handler* is converted to coroutine internally when
it is a regular function.

:param str path: route path

:param callable handler: route handler
Expand Down
14 changes: 7 additions & 7 deletions tests/test_urldispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def make_request(self, method, path):
return req

def test_add_route_root(self):
handler = lambda req: Response(req)
handler = asyncio.coroutine(lambda req: Response(req))
self.router.add_route('GET', '/', handler)
req = self.make_request('GET', '/')
info = self.loop.run_until_complete(self.router.resolve(req))
Expand All @@ -41,7 +41,7 @@ def test_add_route_root(self):
self.assertIsNone(info.route.name)

def test_add_route_simple(self):
handler = lambda req: Response(req)
handler = asyncio.coroutine(lambda req: Response(req))
self.router.add_route('GET', '/handler/to/path', handler)
req = self.make_request('GET', '/handler/to/path')
info = self.loop.run_until_complete(self.router.resolve(req))
Expand All @@ -51,7 +51,7 @@ def test_add_route_simple(self):
self.assertIsNone(info.route.name)

def test_add_with_matchdict(self):
handler = lambda req: Response(req)
handler = asyncio.coroutine(lambda req: Response(req))
self.router.add_route('GET', '/handler/{to}', handler)
req = self.make_request('GET', '/handler/tail')
info = self.loop.run_until_complete(self.router.resolve(req))
Expand All @@ -70,7 +70,7 @@ def test_add_with_name(self):
self.assertEqual('name', info.route.name)

def test_add_with_tailing_slash(self):
handler = lambda req: Response(req)
handler = asyncio.coroutine(lambda req: Response(req))
self.router.add_route('GET', '/handler/to/path/', handler)
req = self.make_request('GET', '/handler/to/path/')
info = self.loop.run_until_complete(self.router.resolve(req))
Expand Down Expand Up @@ -103,7 +103,7 @@ def test_add_url_invalid5(self):
self.router.add_route('post', '/post"{id}', lambda: None)

def test_add_url_escaping(self):
handler = lambda req: Response(req)
handler = asyncio.coroutine(lambda req: Response(req))
self.router.add_route('GET', '/+$', handler)

req = self.make_request('GET', '/+$')
Expand All @@ -112,8 +112,8 @@ def test_add_url_escaping(self):
self.assertIs(handler, info.handler)

def test_match_second_result_in_table(self):
handler1 = lambda req: Response(req)
handler2 = lambda req: Response(req)
handler1 = asyncio.coroutine(lambda req: Response(req))
handler2 = asyncio.coroutine(lambda req: Response(req))
self.router.add_route('GET', '/h1', handler1)
self.router.add_route('POST', '/h2', handler2)
req = self.make_request('POST', '/h2')
Expand Down

0 comments on commit 5a63708

Please sign in to comment.