diff --git a/aiohttp_swagger/helpers/builders.py b/aiohttp_swagger/helpers/builders.py index 5384be1..6d32b2b 100644 --- a/aiohttp_swagger/helpers/builders.py +++ b/aiohttp_swagger/helpers/builders.py @@ -41,13 +41,8 @@ def _extract_swagger_docs(end_point_doc, method="get"): def _build_doc_from_func_doc(route): out = {} - - if isclass(route.handler) and issubclass(route.handler, web.View) and route.method == METH_ANY: - method_names = { - attr for attr in dir(route.handler) - if attr.upper() in METH_ALL - } - for method_name in method_names: + if isclass(route.handler) and issubclass(route.handler, web.View): + for method_name in _get_method_names_for_handler(route): method = getattr(route.handler, method_name) if method.__doc__ is not None and "---" in method.__doc__: end_point_doc = method.__doc__.splitlines() @@ -61,6 +56,20 @@ def _build_doc_from_func_doc(route): out.update(_extract_swagger_docs(end_point_doc, method=str(route.method).lower())) return out +def _get_method_names_for_handler(route): + # Return all valid method names in handler if the method is *, + # otherwise return the specific method. + if route.method == METH_ANY: + return { + attr for attr in dir(route.handler) + if attr.upper() in METH_ALL + } + else: + return { + attr for attr in dir(route.handler) + if attr.upper() in METH_ALL and attr.upper() == route.method + } + def generate_doc_from_each_end_point( app: web.Application, diff --git a/tests/test_openapi.py b/tests/test_openapi.py index c26d975..b21bd0b 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -93,7 +93,7 @@ async def ping_partial(request): return web.Response(text="pong") -async def test_swagger_ui(test_client, loop): +async def test_swagger_ui(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) app = web.Application(loop=loop) @@ -102,7 +102,7 @@ async def test_swagger_ui(test_client, loop): ui_version=3 ) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc') assert resp1.status == 200 retrieved = await resp1.text() @@ -113,7 +113,7 @@ async def test_swagger_ui(test_client, loop): assert retrieved == loaded -async def test_swagger_file_url(test_client, loop): +async def test_swagger_file_url(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) app = web.Application(loop=loop) @@ -121,7 +121,7 @@ async def test_swagger_file_url(test_client, loop): ui_version=3, swagger_from_file=TESTS_PATH + "/data/example_swagger.yaml") - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -130,19 +130,19 @@ async def test_swagger_file_url(test_client, loop): assert 'API Title' in result['info']['title'] -async def test_partial_swagger_file(test_client, loop): +async def test_partial_swagger_file(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping-partial", ping_partial) setup_swagger(app, ui_version=3) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() assert '/ping-partial' in result['paths'] -async def test_custom_swagger(test_client, loop): +async def test_custom_swagger(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -154,7 +154,7 @@ async def test_custom_swagger(test_client, loop): api_version="1.0.0", contact="my.custom.contact@example.com") - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -162,7 +162,7 @@ async def test_custom_swagger(test_client, loop): assert 'Test Custom Title' in result['info']['title'] -async def test_swagger_home_decorator(test_client, loop): +async def test_swagger_home_decorator(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -175,7 +175,7 @@ async def test_swagger_home_decorator(test_client, loop): contact="my.custom.contact@example.com", swagger_home_decor=lambda x: x) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -183,7 +183,7 @@ async def test_swagger_home_decorator(test_client, loop): assert 'Test Custom Title' in result['info']['title'] -async def test_swagger_def_decorator(test_client, loop): +async def test_swagger_def_decorator(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -196,7 +196,7 @@ async def test_swagger_def_decorator(test_client, loop): contact="my.custom.contact@example.com", swagger_def_decor=lambda x: x) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -210,7 +210,7 @@ def swagger_info(): return yaml.full_load(open(filename).read()) -async def test_swagger_info(test_client, loop, swagger_info): +async def test_swagger_info(aiohttp_client, loop, swagger_info): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -219,7 +219,7 @@ async def test_swagger_info(test_client, loop, swagger_info): swagger_url="/api/v1/doc", swagger_info=swagger_info) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -228,11 +228,11 @@ async def test_swagger_info(test_client, loop, swagger_info): assert 'API Title' in result['info']['title'] -async def test_undocumented_fn(test_client, loop): +async def test_undocumented_fn(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/undoc_ping", undoc_ping) setup_swagger(app, ui_version=3) - client = await test_client(app) + client = await aiohttp_client(app) resp = await client.get('/undoc_ping') assert resp.status == 200 swagger_resp1 = await client.get('/api/doc/swagger.json') @@ -241,11 +241,11 @@ async def test_undocumented_fn(test_client, loop): assert not result['paths'] -async def test_wrong_method(test_client, loop): +async def test_wrong_method(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('POST', "/post_ping", ping) setup_swagger(app, ui_version=3) - client = await test_client(app) + client = await aiohttp_client(app) # GET swagger_resp1 = await client.get('/api/doc/swagger.json') assert swagger_resp1.status == 200 @@ -256,12 +256,12 @@ async def test_wrong_method(test_client, loop): assert resp.status == 405 -async def test_class_view(test_client, loop): +async def test_class_view(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('*', "/class_view", ClassView) setup_swagger(app, ui_version=3) - client = await test_client(app) + client = await aiohttp_client(app) # GET resp = await client.get('/class_view') assert resp.status == 200 @@ -294,7 +294,7 @@ async def test_class_view(test_client, loop): assert "patch" not in result['paths']["/class_view"] -async def test_data_defs(test_client, loop): +async def test_data_defs(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) file = open(TESTS_PATH + "/data/example_data_definitions.json") app = web.Application(loop=loop) @@ -302,7 +302,7 @@ async def test_data_defs(test_client, loop): setup_swagger(app, ui_version=3, definitions=json.loads(file.read())) file.close() - client = await test_client(app) + client = await aiohttp_client(app) swagger_resp1 = await client.get('/api/doc/swagger.json') assert swagger_resp1.status == 200 result = await swagger_resp1.json() @@ -311,14 +311,14 @@ async def test_data_defs(test_client, loop): assert result['components']['schemas']['User']['properties']['permissions']['items']['$ref'] is not None -async def test_sub_app(test_client, loop): +async def test_sub_app(aiohttp_client, loop): sub_app = web.Application(loop=loop) sub_app.router.add_route('*', "/class_view", ClassView) setup_swagger(sub_app, ui_version=3, api_base_url='/sub_app') app = web.Application(loop=loop) app.add_subapp(prefix='/sub_app', subapp=sub_app) - client = await test_client(app) + client = await aiohttp_client(app) # GET resp = await client.get('/sub_app/class_view') assert resp.status == 200 diff --git a/tests/test_swagger.py b/tests/test_swagger.py index 00225f1..3001fbc 100644 --- a/tests/test_swagger.py +++ b/tests/test_swagger.py @@ -93,17 +93,17 @@ async def ping_partial(request): return web.Response(text="pong") -async def test_ping(test_client, loop): +async def test_ping(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) - client = await test_client(app) + client = await aiohttp_client(app) resp = await client.get('/ping') assert resp.status == 200 text = await resp.text() assert 'pong' in text -async def test_swagger_ui(test_client, loop): +async def test_swagger_ui(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) @@ -111,7 +111,7 @@ async def test_swagger_ui(test_client, loop): setup_swagger(app, swagger_from_file=TESTS_PATH + "/data/example_swagger.yaml") - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc') assert resp1.status == 200 retrieved = await resp1.text() @@ -122,7 +122,7 @@ async def test_swagger_ui(test_client, loop): assert retrieved == loaded -async def test_swagger_ui3(test_client, loop): +async def test_swagger_ui3(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) app = web.Application(loop=loop) @@ -131,7 +131,7 @@ async def test_swagger_ui3(test_client, loop): ui_version=3 ) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc') assert resp1.status == 200 retrieved = await resp1.text() @@ -142,14 +142,14 @@ async def test_swagger_ui3(test_client, loop): assert retrieved == loaded -async def test_swagger_file_url(test_client, loop): +async def test_swagger_file_url(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) app = web.Application(loop=loop) setup_swagger(app, swagger_from_file=TESTS_PATH + "/data/example_swagger.yaml") - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -158,19 +158,19 @@ async def test_swagger_file_url(test_client, loop): assert 'API Title' in result['info']['title'] -async def test_partial_swagger_file(test_client, loop): +async def test_partial_swagger_file(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping-partial", ping_partial) setup_swagger(app) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() assert '/ping-partial' in result['paths'] -async def test_custom_swagger(test_client, loop): +async def test_custom_swagger(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -181,7 +181,7 @@ async def test_custom_swagger(test_client, loop): api_version="1.0.0", contact="my.custom.contact@example.com") - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -189,7 +189,7 @@ async def test_custom_swagger(test_client, loop): assert 'Test Custom Title' in result['info']['title'] -async def test_swagger_home_decorator(test_client, loop): +async def test_swagger_home_decorator(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -201,7 +201,7 @@ async def test_swagger_home_decorator(test_client, loop): contact="my.custom.contact@example.com", swagger_home_decor=lambda x: x) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -209,7 +209,7 @@ async def test_swagger_home_decorator(test_client, loop): assert 'Test Custom Title' in result['info']['title'] -async def test_swagger_def_decorator(test_client, loop): +async def test_swagger_def_decorator(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -221,7 +221,7 @@ async def test_swagger_def_decorator(test_client, loop): contact="my.custom.contact@example.com", swagger_def_decor=lambda x: x) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -235,7 +235,7 @@ def swagger_info(): return yaml.full_load(open(filename).read()) -async def test_swagger_info(test_client, loop, swagger_info): +async def test_swagger_info(aiohttp_client, loop, swagger_info): app = web.Application(loop=loop) app.router.add_route('GET', "/ping", ping) description = "Test Custom Swagger" @@ -243,7 +243,7 @@ async def test_swagger_info(test_client, loop, swagger_info): swagger_url="/api/v1/doc", swagger_info=swagger_info) - client = await test_client(app) + client = await aiohttp_client(app) resp1 = await client.get('/api/v1/doc/swagger.json') assert resp1.status == 200 result = await resp1.json() @@ -252,11 +252,11 @@ async def test_swagger_info(test_client, loop, swagger_info): assert 'API Title' in result['info']['title'] -async def test_undocumented_fn(test_client, loop): +async def test_undocumented_fn(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('GET', "/undoc_ping", undoc_ping) setup_swagger(app) - client = await test_client(app) + client = await aiohttp_client(app) resp = await client.get('/undoc_ping') assert resp.status == 200 swagger_resp1 = await client.get('/api/doc/swagger.json') @@ -265,11 +265,11 @@ async def test_undocumented_fn(test_client, loop): assert not result['paths'] -async def test_wrong_method(test_client, loop): +async def test_wrong_method(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('POST', "/post_ping", ping) setup_swagger(app) - client = await test_client(app) + client = await aiohttp_client(app) # GET swagger_resp1 = await client.get('/api/doc/swagger.json') assert swagger_resp1.status == 200 @@ -279,13 +279,36 @@ async def test_wrong_method(test_client, loop): resp = await client.get('/post_ping') assert resp.status == 405 +async def test_class_view_single_method(aiohttp_client, loop): + app = web.Application(loop=loop) + app.router.add_route('GET', "/class_view", ClassView) + setup_swagger(app) + + client = await aiohttp_client(app) + # GET + resp = await client.get('/class_view') + assert resp.status == 200 + text = await resp.text() + assert 'OK' in text + swagger_resp1 = await client.get('/api/doc/swagger.json') + assert swagger_resp1.status == 200 + result = await swagger_resp1.json() + assert "/class_view" in result['paths'] + assert "get" in result['paths']["/class_view"] + + # Not registered POST + resp = await client.post('/class_view') + assert resp.status == 405 + result = await swagger_resp1.json() + assert "post" not in result['paths']["/class_view"] + -async def test_class_view(test_client, loop): +async def test_class_view_multiple_methods(aiohttp_client, loop): app = web.Application(loop=loop) app.router.add_route('*', "/class_view", ClassView) setup_swagger(app) - client = await test_client(app) + client = await aiohttp_client(app) # GET resp = await client.get('/class_view') assert resp.status == 200 @@ -318,7 +341,7 @@ async def test_class_view(test_client, loop): assert "patch" not in result['paths']["/class_view"] -async def test_data_defs(test_client, loop): +async def test_data_defs(aiohttp_client, loop): TESTS_PATH = abspath(join(dirname(__file__))) file = open(TESTS_PATH + "/data/example_data_definitions.json") app = web.Application(loop=loop) @@ -326,7 +349,7 @@ async def test_data_defs(test_client, loop): setup_swagger(app, definitions=json.loads(file.read())) file.close() - client = await test_client(app) + client = await aiohttp_client(app) swagger_resp1 = await client.get('/api/doc/swagger.json') assert swagger_resp1.status == 200 result = await swagger_resp1.json() @@ -335,14 +358,14 @@ async def test_data_defs(test_client, loop): assert result['definitions']['User']['properties']['permissions']['items']['$ref'] is not None -async def test_sub_app(test_client, loop): +async def test_sub_app(aiohttp_client, loop): sub_app = web.Application(loop=loop) sub_app.router.add_route('*', "/class_view", ClassView) setup_swagger(sub_app, api_base_url='/sub_app') app = web.Application(loop=loop) app.add_subapp(prefix='/sub_app', subapp=sub_app) - client = await test_client(app) + client = await aiohttp_client(app) # GET resp = await client.get('/sub_app/class_view') assert resp.status == 200