Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
Version dev
===========

- Added support to exclude handlers from generated swagger document.

Version 1.0.15
==============
- Fixes a bug in setup.py where the distribution exports the package tests along with the actual library.
- Latest js-yaml fixes security issue related to https://www.npmjs.com/advisories/813
- Added logic that checks whether the route.method is * or contains a single method. When the latter is the case only the method that is specified will be added to the Swagger UI.
Expand Down
4 changes: 2 additions & 2 deletions aiohttp_swagger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from aiohttp import web

from .helpers import (generate_doc_from_each_end_point,
load_doc_from_yaml_file, swagger_path)
load_doc_from_yaml_file, swagger_ignore, swagger_path)

try:
import ujson as json
Expand Down Expand Up @@ -108,4 +108,4 @@ def setup_swagger(app: web.Application,
)


__all__ = ("setup_swagger", "swagger_path")
__all__ = ("setup_swagger", "swagger_path", "swagger_ignore")
6 changes: 6 additions & 0 deletions aiohttp_swagger/helpers/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ def _build_doc_from_func_doc(route):
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 getattr(method, "swagger_ignore", False):
continue
if method.__doc__ is not None and "---" in method.__doc__:
end_point_doc = method.__doc__.splitlines()
out.update(_extract_swagger_docs(end_point_doc, method=method_name))
Expand Down Expand Up @@ -132,6 +134,10 @@ def nesteddict2yaml(d, indent=10, result=""):

end_point_doc = None

if getattr(route.handler, "swagger_ignore", False):
# Handlers can be ignored from documentation
continue

# If route has a external link to doc, we use it, not function doc
if getattr(route.handler, "swagger_file", False):
try:
Expand Down
6 changes: 6 additions & 0 deletions aiohttp_swagger/helpers/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ def __init__(self, swagger_file):
def __call__(self, f):
f.swagger_file = self.swagger_file
return f


def swagger_ignore(handler):
"""Mark handler as ignored from swagger docs"""
handler.swagger_ignore = True
return handler
24 changes: 24 additions & 0 deletions doc/source/customizing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,27 @@ Swagger validation
api_base_url='/sub_app_prefix',
swagger_validator_url='//online.swagger.io/validator'
)

Ignore path
+++++++++++

:samp:`aiohttp-swagger` ignores handlers that have an attribute `swagger_ignore` with value `True`. A helper method
`swagger_ignore`, that can be used as decorator, is available.


.. code-block:: python

from aiohttp import web
from aiohttp_swagger import *

@swagger_ignore
async def ping(request):
return web.Response(text="pong")

app = web.Application()

app.router.add_route('GET', "/ping", ping)

setup_swagger(app)

web.run_app(app, host="127.0.0.1")
45 changes: 45 additions & 0 deletions tests/test_openapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import json

import aiohttp_swagger
import pytest
import yaml
from os.path import join, dirname, abspath
Expand Down Expand Up @@ -93,6 +95,30 @@ async def ping_partial(request):
return web.Response(text="pong")


@swagger_ignore
async def ignore(request):
return web.Response(text="OK")
ignore.__doc__ = ping.__doc__


class IgnoreView(ClassView):

@swagger_ignore
async def get(self):
return await super().get()
get.__doc__ = ClassView.get.__doc__

@swagger_ignore
async def patch(self):
return await super().patch()
patch.__doc__ = ClassView.patch.__doc__

@swagger_ignore
async def post(self):
return await super().post()
post.__doc__ = ClassView.post.__doc__


async def test_swagger_ui(aiohttp_client, loop):
TESTS_PATH = abspath(join(dirname(__file__)))

Expand Down Expand Up @@ -241,6 +267,25 @@ async def test_undocumented_fn(aiohttp_client, loop):
assert not result['paths']


async def test_ignored_fn(aiohttp_client, loop):
app = web.Application(loop=loop)
app.router.add_route('GET', "/ignore", ignore)
assert ignore.swagger_ignore is True
app.router.add_route('*', "/ignore_view", IgnoreView)
assert IgnoreView.get.swagger_ignore is True

setup_swagger(app, ui_version=3)
client = await aiohttp_client(app)
for path in ("/ignore", "/ignore_view"):
resp = await client.get(path)
assert resp.status == 200

swagger_resp1 = await client.get('/api/doc/swagger.json')
assert swagger_resp1.status == 200
result = await swagger_resp1.json()
assert not result['paths']


async def test_wrong_method(aiohttp_client, loop):
app = web.Application(loop=loop)
app.router.add_route('POST', "/post_ping", ping)
Expand Down
43 changes: 43 additions & 0 deletions tests/test_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,30 @@ async def ping_partial(request):
return web.Response(text="pong")


@swagger_ignore
async def ignore(request):
return web.Response(text="OK")
ignore.__doc__ = ping.__doc__


class IgnoreView(ClassView):

@swagger_ignore
async def get(self):
return await super().get()
get.__doc__ = ClassView.get.__doc__

@swagger_ignore
async def patch(self):
return await super().patch()
patch.__doc__ = ClassView.patch.__doc__

@swagger_ignore
async def post(self):
return await super().post()
post.__doc__ = ClassView.post.__doc__


async def test_ping(aiohttp_client, loop):
app = web.Application(loop=loop)
app.router.add_route('GET', "/ping", ping)
Expand Down Expand Up @@ -265,6 +289,25 @@ async def test_undocumented_fn(aiohttp_client, loop):
assert not result['paths']


async def test_ignored_fn(aiohttp_client, loop):
app = web.Application(loop=loop)
app.router.add_route('GET', "/ignore", ignore)
assert ignore.swagger_ignore is True
app.router.add_route('*', "/ignore_view", IgnoreView)
assert IgnoreView.get.swagger_ignore is True

setup_swagger(app, ui_version=3)
client = await aiohttp_client(app)
for path in ("/ignore", "/ignore_view"):
resp = await client.get(path)
assert resp.status == 200

swagger_resp1 = await client.get('/api/doc/swagger.json')
assert swagger_resp1.status == 200
result = await swagger_resp1.json()
assert not result['paths']


async def test_wrong_method(aiohttp_client, loop):
app = web.Application(loop=loop)
app.router.add_route('POST', "/post_ping", ping)
Expand Down