API: Added auto generated API documentation at /api/documentation
to implement this generator in every Path you want to document add the following decorator: @auto.doc()
This commit is contained in:
parent
252ecbb40e
commit
278a39710a
11 changed files with 338 additions and 0 deletions
|
@ -10,6 +10,8 @@ from flask import Flask, request, render_template, redirect, abort
|
||||||
# from User import User
|
# from User import User
|
||||||
from flask.ext.github import GitHub
|
from flask.ext.github import GitHub
|
||||||
from flask.ext.cors import CORS, cross_origin
|
from flask.ext.cors import CORS, cross_origin
|
||||||
|
from flask.ext.autodoc import Autodoc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ app.config['GITHUB_CLIENT_SECRET'] = githubKeys.getSecret()
|
||||||
|
|
||||||
github = GitHub(app)
|
github = GitHub(app)
|
||||||
cross = CORS(app)
|
cross = CORS(app)
|
||||||
|
auto = Autodoc(app)
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
|
@ -31,6 +34,10 @@ def page_not_found(e):
|
||||||
def wellcomePage():
|
def wellcomePage():
|
||||||
return app.send_static_file('index.html')
|
return app.send_static_file('index.html')
|
||||||
|
|
||||||
|
@app.route('/api/documentation')
|
||||||
|
def documentation():
|
||||||
|
return auto.html()
|
||||||
|
|
||||||
@app.route('/home')
|
@app.route('/home')
|
||||||
def returnHome():
|
def returnHome():
|
||||||
try:
|
try:
|
||||||
|
@ -41,7 +48,13 @@ def returnHome():
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/getUserByToken/<string:token>', methods=["GET"])
|
@app.route('/api/getUserByToken/<string:token>', methods=["GET"])
|
||||||
|
@auto.doc()
|
||||||
def getUserByToken(token):
|
def getUserByToken(token):
|
||||||
|
'''
|
||||||
|
param: String - token: users se-Token
|
||||||
|
return: JSON object of the user
|
||||||
|
if no valid seToken, return message: No User Found
|
||||||
|
'''
|
||||||
query = User.all()
|
query = User.all()
|
||||||
query.filter("seToken = ", token)
|
query.filter("seToken = ", token)
|
||||||
|
|
||||||
|
|
92
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/PKG-INFO
Normal file
92
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/PKG-INFO
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
Metadata-Version: 1.1
|
||||||
|
Name: Flask-Autodoc
|
||||||
|
Version: 0.1.1
|
||||||
|
Summary: Documentation generator for flask
|
||||||
|
Home-page: http://github.com/acoomans/flask-autodoc
|
||||||
|
Author: Arnaud Coomans
|
||||||
|
Author-email: arnaud.coomans@gmail.com
|
||||||
|
License: MIT
|
||||||
|
Description: Flask-Autodoc
|
||||||
|
=============
|
||||||
|
|
||||||
|
Flask Autodoc is a Flask extension that automatically creates documentation for your endpoints based on the routes,
|
||||||
|
function arguments and docstring.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
To install Flask-Autodoc:
|
||||||
|
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Start using Flask-Autodoc by importing it and initializing it:
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
from flask.ext.autodoc import Autodoc
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
auto = Autodoc(app)
|
||||||
|
|
||||||
|
by default, Flask-Autodoc will only document the routes you explicitly tell him to with the _doc_ decorator,
|
||||||
|
like this:
|
||||||
|
|
||||||
|
@app.route('/user/<int:id>')
|
||||||
|
@auto.doc
|
||||||
|
def show_user(id):
|
||||||
|
"""This returns a user with a given id."""
|
||||||
|
return user_from_database(id)
|
||||||
|
|
||||||
|
to generate the documentation from an endpoint, use the _html()_ method:
|
||||||
|
|
||||||
|
@app.route('/documentation')
|
||||||
|
def documentation():
|
||||||
|
return auto.html()
|
||||||
|
|
||||||
|
if you to access the documentation without it being rendered in html:
|
||||||
|
|
||||||
|
@app.route('/documentation')
|
||||||
|
def documentation():
|
||||||
|
return auto.generate()
|
||||||
|
|
||||||
|
the documentation will then be returned as a list of rules, where each rule is a dictionary containing:
|
||||||
|
|
||||||
|
- methods: the set of allowed methods (ie ['GET', 'POST'])
|
||||||
|
- rule: relative url (ie '/user/<int:id>')
|
||||||
|
- endpoint: function name (ie 'show_user')
|
||||||
|
- doc: docstring of the function
|
||||||
|
- args: function arguments
|
||||||
|
- defaults: defaults values for the arguments
|
||||||
|
|
||||||
|
## Groups
|
||||||
|
|
||||||
|
You may want to group endpoints together, to have different documentation sets. With this you can for example, only
|
||||||
|
show some endpoints to third party developer and have full documentation for your own.
|
||||||
|
|
||||||
|
to assign an endpoint to a group, pass the name of the group as argument of the _doc_ decorator:
|
||||||
|
|
||||||
|
@app.route('/user/<int:id>')
|
||||||
|
@auto.doc("public")
|
||||||
|
def show_user(id):
|
||||||
|
|
||||||
|
to assign an endpoint to multiple groups, pass a list of group names as the _groups_ argument to _doc_:
|
||||||
|
|
||||||
|
@app.route('/user/<int:id>')
|
||||||
|
@auto.doc(groups=["public","private"])
|
||||||
|
def show_user(id):
|
||||||
|
|
||||||
|
to generate the documentation for a specific group, pass the name of the group to the _generate_ or _html_ methods:
|
||||||
|
|
||||||
|
auto.generate("public")
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
auto.html("public")
|
||||||
|
Platform: any
|
||||||
|
Classifier: Environment :: Web Environment
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: MIT License
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||||
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
13
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/SOURCES.txt
Normal file
13
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/SOURCES.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
MANIFEST.in
|
||||||
|
README
|
||||||
|
setup.cfg
|
||||||
|
setup.py
|
||||||
|
Flask_Autodoc.egg-info/PKG-INFO
|
||||||
|
Flask_Autodoc.egg-info/SOURCES.txt
|
||||||
|
Flask_Autodoc.egg-info/dependency_links.txt
|
||||||
|
Flask_Autodoc.egg-info/not-zip-safe
|
||||||
|
Flask_Autodoc.egg-info/requires.txt
|
||||||
|
Flask_Autodoc.egg-info/top_level.txt
|
||||||
|
flask_autodoc/__init__.py
|
||||||
|
flask_autodoc/autodoc.py
|
||||||
|
flask_autodoc/templates/autodoc_default.html
|
|
@ -0,0 +1 @@
|
||||||
|
|
12
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/installed-files.txt
Normal file
12
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/installed-files.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
../flask_autodoc/autodoc.py
|
||||||
|
../flask_autodoc/__init__.py
|
||||||
|
../flask_autodoc/templates/autodoc_default.html
|
||||||
|
../flask_autodoc/autodoc.pyc
|
||||||
|
../flask_autodoc/__init__.pyc
|
||||||
|
./
|
||||||
|
top_level.txt
|
||||||
|
SOURCES.txt
|
||||||
|
requires.txt
|
||||||
|
PKG-INFO
|
||||||
|
not-zip-safe
|
||||||
|
dependency_links.txt
|
1
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/not-zip-safe
Normal file
1
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/not-zip-safe
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
1
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/requires.txt
Normal file
1
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/requires.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Flask
|
1
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/top_level.txt
Normal file
1
lib/Flask_Autodoc-0.1.1-py2.7.egg-info/top_level.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
flask_autodoc
|
2
lib/flask_autodoc/__init__.py
Normal file
2
lib/flask_autodoc/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__author__ = 'arnaud'
|
||||||
|
from autodoc import Autodoc
|
126
lib/flask_autodoc/autodoc.py
Normal file
126
lib/flask_autodoc/autodoc.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from collections import defaultdict
|
||||||
|
from flask import current_app, render_template, render_template_string
|
||||||
|
from jinja2 import evalcontextfilter
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from flask import _app_ctx_stack as stack
|
||||||
|
except ImportError:
|
||||||
|
from flask import _request_ctx_stack as stack
|
||||||
|
|
||||||
|
|
||||||
|
class Autodoc(object):
|
||||||
|
|
||||||
|
def __init__(self, app=None):
|
||||||
|
self.app = app
|
||||||
|
self.groups = defaultdict(set)
|
||||||
|
if app is not None:
|
||||||
|
self.init_app(app)
|
||||||
|
|
||||||
|
def init_app(self, app):
|
||||||
|
if hasattr(app, 'teardown_appcontext'):
|
||||||
|
app.teardown_appcontext(self.teardown)
|
||||||
|
else:
|
||||||
|
app.teardown_request(self.teardown)
|
||||||
|
self.add_custom_template_filters(app)
|
||||||
|
|
||||||
|
def teardown(self, exception):
|
||||||
|
ctx = stack.top
|
||||||
|
|
||||||
|
def add_custom_template_filters(self, app):
|
||||||
|
"""Add custom filters to jinja2 templating engine"""
|
||||||
|
self.add_custom_nl2br_filters(app)
|
||||||
|
|
||||||
|
def add_custom_nl2br_filters(self, app):
|
||||||
|
"""Add a custom filter nl2br to jinja2
|
||||||
|
Replaces all newline to <BR>
|
||||||
|
"""
|
||||||
|
_paragraph_re = re.compile(r'(?:\r\n|\r|\n){3,}')
|
||||||
|
@app.template_filter()
|
||||||
|
@evalcontextfilter
|
||||||
|
def nl2br(eval_ctx, value):
|
||||||
|
result = u'\n\n'.join(u'%s' % p.replace('\n', '<br>\n') for p in _paragraph_re.split(value))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def doc(self, group=None, aa=None, groups=None):
|
||||||
|
"""Decorator to add flask route to autodoc for automatic documentation\
|
||||||
|
|
||||||
|
Any route decorated with this method will be added to the list of routes to be documented by the generate() or
|
||||||
|
html() methods.
|
||||||
|
|
||||||
|
By default, the route is added to the 'all' group.
|
||||||
|
By specifying group or groups argument, the route can be added to one or multiple other groups as well, besides
|
||||||
|
the 'all' group.
|
||||||
|
"""
|
||||||
|
def decorator(f):
|
||||||
|
if groups:
|
||||||
|
groupset = set(groups)
|
||||||
|
else:
|
||||||
|
groupset = set()
|
||||||
|
if group:
|
||||||
|
groupset.add(group)
|
||||||
|
groupset.add("all")
|
||||||
|
for g in groupset:
|
||||||
|
self.groups[g].add(f)
|
||||||
|
return f
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
def generate(self, group="all", groups=[], sort=None):
|
||||||
|
"""Returns a list of dict describing the routes specified by the doc() method
|
||||||
|
|
||||||
|
Each dict contains:
|
||||||
|
- methods: the set of allowed methods (ie ['GET', 'POST'])
|
||||||
|
- rule: relative url (ie '/user/<int:id>')
|
||||||
|
- endpoint: function name (ie 'show_user')
|
||||||
|
- doc: docstring of the function
|
||||||
|
- args: function arguments
|
||||||
|
- defaults: defaults values for the arguments
|
||||||
|
|
||||||
|
By specifying the group or groups arguments, only routes belonging to those groups will be returned.
|
||||||
|
|
||||||
|
Routes are sorted alphabetically based on the rule.
|
||||||
|
"""
|
||||||
|
links = []
|
||||||
|
for rule in current_app.url_map.iter_rules():
|
||||||
|
|
||||||
|
if rule.endpoint == 'static':
|
||||||
|
continue
|
||||||
|
|
||||||
|
func = current_app.view_functions[rule.endpoint]
|
||||||
|
|
||||||
|
if (groups and [True for g in groups if func in self.groups[g]]) or \
|
||||||
|
(not groups and func in self.groups[group]):
|
||||||
|
links.append(
|
||||||
|
dict(
|
||||||
|
methods = rule.methods,
|
||||||
|
rule = "%s" % rule,
|
||||||
|
endpoint = rule.endpoint,
|
||||||
|
docstring = func.__doc__,
|
||||||
|
args = list(func.func_code.co_varnames),
|
||||||
|
defaults = rule.defaults
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if sort:
|
||||||
|
return sort(links)
|
||||||
|
else:
|
||||||
|
return sorted(links, cmp=lambda x,y: cmp(x['rule'], y['rule']))
|
||||||
|
|
||||||
|
def html(self, template=None, group="all", groups=None, **context):
|
||||||
|
"""Returns an html string of the routes specified by the doc() method
|
||||||
|
|
||||||
|
A template can be specified. A list of routes is available under the 'autodoc' value (refer to the documentation
|
||||||
|
for the generate() for a description of available values). If no template is specified, a default template is
|
||||||
|
used.
|
||||||
|
|
||||||
|
By specifying the group or groups arguments, only routes belonging to those groups will be returned.
|
||||||
|
"""
|
||||||
|
if template:
|
||||||
|
return render_template(template, autodoc=self.generate(group), **context)
|
||||||
|
else:
|
||||||
|
filename = os.path.dirname(__file__)+"/templates/autodoc_default.html"
|
||||||
|
with open(filename) as file:
|
||||||
|
content = file.read()
|
||||||
|
with current_app.app_context():
|
||||||
|
return render_template_string(content, autodoc=self.generate(group=group, groups=groups), **context)
|
76
lib/flask_autodoc/templates/autodoc_default.html
Normal file
76
lib/flask_autodoc/templates/autodoc_default.html
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
{% if title is defined -%}
|
||||||
|
{{title}}
|
||||||
|
{% else -%}
|
||||||
|
Documentation
|
||||||
|
{% endif -%}
|
||||||
|
</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mapping {
|
||||||
|
margin: 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.methods:before { content: "Methods: "; }
|
||||||
|
ul.methods li {
|
||||||
|
display: inline;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
ul.methods li:after { content: ","; }
|
||||||
|
ul.methods li:last-child:after { content: ""; }
|
||||||
|
|
||||||
|
ul.arguments:before { content: "Arguments: "; }
|
||||||
|
ul.arguments li {
|
||||||
|
display: inline;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
ul.arguments .argument { font-style:italic }
|
||||||
|
ul.arguments .default:not(:empty):before { content: "("; }
|
||||||
|
ul.arguments .default:not(:empty):after { content: ")"; }
|
||||||
|
ul.arguments li:after { content: ","; }
|
||||||
|
ul.arguments li:last-child:after { content: ""; }
|
||||||
|
|
||||||
|
.docstring:before { content: "Description: "; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>
|
||||||
|
{% if title is defined -%}
|
||||||
|
{{title}}
|
||||||
|
{% else -%}
|
||||||
|
Documentation
|
||||||
|
{% endif -%}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{% for doc in autodoc %}
|
||||||
|
<div class="mapping">
|
||||||
|
<a id="rule-{{doc.rule|urlencode}}" class="rule"><h2>{{doc.rule|escape}}</h2></a>
|
||||||
|
<ul class="methods">
|
||||||
|
{% for method in doc.methods -%}
|
||||||
|
<li class="method">{{method}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<ul class="arguments">
|
||||||
|
{% for arg in doc.args %}
|
||||||
|
<li>
|
||||||
|
<span class="argument">{{arg}}</span>
|
||||||
|
<span class="default">{{doc.defaults[arg]}}</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<p class="docstring">{{doc.docstring|urlize|nl2br}}</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue