From cb42a4e4fa0718340f945400cd287dd32f12f6f1 Mon Sep 17 00:00:00 2001 From: Adrian Chaves Date: Mon, 5 Jun 2017 17:15:55 +0200 Subject: [PATCH] Use functools.wraps when wrapping synchronous handlers --- CHANGES.rst | 3 ++- CONTRIBUTORS.txt | 1 + aiohttp/web_urldispatcher.py | 2 ++ tests/test_web_urldispatcher.py | 24 ++++++++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 0a90be2162b..0de015d9cdc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,7 +6,8 @@ Changes - Add doc for add_head, update doc for add_get. #1944 -- +- Retain method attributes (e.g. :code:`__doc__`) when registering synchronous + handlers for resources. #1953 - diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index b4daae584f1..29eb599723b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -2,6 +2,7 @@ Contributors ------------ A. Jesse Jiryu Davis Adam Mills +Adrián Chaves Alec Hanefeld Alejandro Gómez Aleksandr Danshyn diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index f85322ea3ea..910f346e2c8 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -7,6 +7,7 @@ import re import warnings from collections.abc import Container, Iterable, Sized +from functools import wraps from pathlib import Path from types import MappingProxyType @@ -106,6 +107,7 @@ def __init__(self, method, handler, *, issubclass(handler, AbstractView)): pass else: + @wraps(handler) @asyncio.coroutine def handler_wrapper(*args, **kwargs): result = old_handler(*args, **kwargs) diff --git a/tests/test_web_urldispatcher.py b/tests/test_web_urldispatcher.py index 6a37a7155ae..041ae512a82 100644 --- a/tests/test_web_urldispatcher.py +++ b/tests/test_web_urldispatcher.py @@ -180,6 +180,30 @@ def handler(_): assert r.status == 200 +@asyncio.coroutine +def test_handler_metadata_persistence(): + """ + Tests accessing metadata of a handler after registering it on the app + router. + """ + app = web.Application() + + async def async_handler(_): + """Doc""" + return web.Response() + + def sync_handler(_): + """Doc""" + return web.Response() + + app.router.add_get('/async', async_handler) + app.router.add_get('/sync', sync_handler) + + for resource in app.router.resources(): + for route in resource: + assert route.handler.__doc__ == 'Doc' + + @asyncio.coroutine def test_unauthorized_folder_access(tmp_dir_path, loop, test_client): """