Skip to content

Add an endpoint for retrieving docs in JSON form. #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
14e7f95
Update README.
jwg4 May 15, 2018
a733eeb
Change autodoc to selfdoc, in module names and everywhere else.
jwg4 May 15, 2018
67bbbe7
Update in one more place.
jwg4 May 15, 2018
f0477a4
Pin the requirements to an old version of Flask.
jwg4 May 15, 2018
b51a080
Merge pull request #2 from jwg4/selfdoc
jwg4 May 15, 2018
1da61c2
Remove requirements, specify flask versions in matrix.
jwg4 May 15, 2018
b309ea4
Install latest flask but allow to fail.
jwg4 May 15, 2018
6f0d6dc
Specify the actual latest version that we want. (latest doesnt work)
jwg4 May 15, 2018
6537bcb
Replace import.
jwg4 May 16, 2018
a3f14ea
Change another import.
jwg4 May 16, 2018
38e9fd7
Change another import.
jwg4 May 16, 2018
a00b16f
Change another import.
jwg4 May 16, 2018
8d304e6
Change another import.
jwg4 May 16, 2018
b07dfc8
Don't allow failures for latest flask anymore.
jwg4 May 16, 2018
f3635e4
Raise an error with a useful message if the app is not setup.
jwg4 May 24, 2017
ca087fb
Correct name of package.
jwg4 May 16, 2018
6a6f70d
Change the import in the example code.
jwg4 May 16, 2018
92d7104
Do deployment.
jwg4 May 16, 2018
25b3892
Turn off email notifications.
jwg4 May 17, 2018
624a94d
Add flake8 to the script
jwg4 May 17, 2018
405a892
Remove flake8 - keep master build passing.
jwg4 May 17, 2018
bf6d1f5
Add flake8 to job.
jwg4 May 17, 2018
48bf0ef
Don't run flake8 on example code.
jwg4 May 17, 2018
91c9f79
Ignore the unneeded import error.
jwg4 May 17, 2018
3813c4b
fix/ignore some flake8 stuff
jwg4 May 17, 2018
c2060a1
Add a condition on line length.
jwg4 May 17, 2018
0a256da
spacing/other flake8
jwg4 May 17, 2018
1865822
Correct line number for test.
jwg4 May 17, 2018
fa744d7
Update README.md
jwg4 May 17, 2018
f6c1e51
Change name of travis task in README.
jwg4 May 18, 2018
aedc99c
Add maintainer details.
jwg4 May 18, 2018
0c9daff
Add a prerelease version number.
jwg4 May 16, 2018
405b04e
Bump the prerelease version.
jwg4 May 16, 2018
f7c452b
Bump version to 1.0.
jwg4 May 19, 2018
f7f3fae
Add the new pypi.org server to the travis deployment config.
jwg4 May 19, 2018
2102a95
Make this the first release candidate.
jwg4 May 19, 2018
aeefbc7
Version 1.0.1.
jwg4 May 19, 2018
0e797d3
Remove auto-deploy code.
jwg4 May 19, 2018
e6631df
Version 1.0.2
jwg4 May 19, 2018
9fbf6df
Stub for json method.
jwg4 May 21, 2017
0bf2d9a
Add a test for HTML retrieval.
jwg4 May 21, 2017
5de17d8
Add a test for json retrieval.
jwg4 May 21, 2017
7b9ef7f
Make this test a bit harder.
jwg4 May 21, 2017
4aa2975
Add something for each documented endpoint.
jwg4 May 24, 2017
0407653
Send back some actual info about the endpoint.
jwg4 May 24, 2017
eeed4ce
Decode bytes from HTTP into a string.
jwg4 May 25, 2017
5b0661f
Correct import.
jwg4 May 19, 2018
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
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"
env:
- FLASK=0.12
- FLASK=1.0
- FLASK=1.0.2
install:
- pip install -r requirements.txt
- pip install Flask==${FLASK}
- pip install flake8
script:
- python -m unittest discover
- flake8 --exclude=examples --max-line-length=100
notifications:
email: false

3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "${workspaceFolder}\\venv\\Scripts\\python.exe"
}
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
include README.md
include flask_autodoc/templates/autodoc_default.html
include flask_selfdoc/templates/autodoc_default.html
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
Flask-Autodoc
Flask-Selfdoc
=============

Flask-Autodoc is a Flask extension that automatically creates documentation for your endpoints based on the routes, function arguments and docstrings.
Flask-Selfdoc is a Flask extension that automatically creates documentation for your endpoints based on the routes, function arguments and docstrings. It was forked from Flask-Autodoc, written by Arnaud Coomans, and is completely compatible as a replacement for that extension.

[![Build](https://api.travis-ci.org/acoomans/flask-autodoc.png)](https://travis-ci.org/acoomans/flask-autodoc)
[![Pypi version](http://img.shields.io/pypi/v/flask-autodoc.svg)](https://pypi.python.org/pypi/Flask-Autodoc)
[![Pypi license](http://img.shields.io/pypi/l/flask-autodoc.svg)](https://pypi.python.org/pypi/Flask-Autodoc)
[![Build](https://api.travis-ci.org/jwg4/flask-selfdoc.png)](https://travis-ci.org/jwg4/flask-selfdoc)
[![Pypi version](http://img.shields.io/pypi/v/flask-selfdoc.svg)](https://pypi.python.org/pypi/Flask-Selfdoc)
[![Pypi license](http://img.shields.io/pypi/l/flask-selfdoc.svg)](https://pypi.python.org/pypi/Flask-Selfdoc)
![Python 2](http://img.shields.io/badge/python-2-blue.svg)
![Python 3](http://img.shields.io/badge/python-3-blue.svg)


## Requirements

Flask-Autodoc is compatible with Python versions 2 and 3; and it depends only on Flask.
Flask-Selfdoc is compatible with Python versions 2 and 3; and it depends only on Flask.

## Install

To install Flask-Autodoc, run pip:
To install Flask-Selfdoc, run pip:

pip install flask-autodoc
pip install flask-selfdoc

or clone this directory and run setup:

python setup.py install

## Usage

Start using Flask-Autodoc by importing it and initializing it:
Start using Flask-Selfdoc by importing it and initializing it:

from flask import Flask
from flask.ext.autodoc import Autodoc
from flask_selfdoc import Autodoc

app = Flask(__name__)
auto = Autodoc(app)

by default, Flask-Autodoc will only document the routes explicitly decorated with _doc_:
by default, Flask-Selfdoc will only document the routes explicitly decorated with _doc_:

@app.route('/user/<int:id>')
@auto.doc()
Expand Down Expand Up @@ -127,4 +127,4 @@ and connect to [/doc/public](http://127.0.0.1:5000/doc/public) and [/doc/private

![screenshots](screenshots/screenshot00.png)

![screenshots](screenshots/screenshot01.png)
![screenshots](screenshots/screenshot01.png)
2 changes: 1 addition & 1 deletion examples/custom/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from json import dumps

from flask import Flask, redirect, request
from flask.ext.autodoc import Autodoc
from flask_selfdoc import Autodoc


app = Flask(__name__)
Expand Down
2 changes: 1 addition & 1 deletion examples/factory/blog/doc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from flask import Blueprint
from flask.ext.autodoc import Autodoc
from flask_selfdoc import Autodoc


doc = Blueprint('doc', __name__, url_prefix='/doc')
Expand Down
2 changes: 1 addition & 1 deletion examples/simple/blog.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from json import dumps

from flask import Flask, redirect, request
from flask.ext.autodoc import Autodoc
from flask_selfdoc import Autodoc


app = Flask(__name__)
Expand Down
3 changes: 0 additions & 3 deletions flask_autodoc/__init__.py

This file was deleted.

3 changes: 3 additions & 0 deletions flask_selfdoc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__author__ = 'arnaud'

from flask_selfdoc.autodoc import Autodoc # noqa: F401
34 changes: 31 additions & 3 deletions flask_autodoc/autodoc.py → flask_selfdoc/autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys
import inspect

from flask import current_app, render_template, render_template_string
from flask import current_app, render_template, render_template_string, jsonify
from jinja2 import evalcontextfilter


Expand All @@ -28,7 +28,8 @@ def __init__(self, app=None):
self.func_groups = defaultdict(set)
self.func_props = defaultdict()
self.immutable_props = ['rule', 'endpoint']
self.default_props = ['methods', 'docstring',
self.default_props = [
'methods', 'docstring',
'args', 'defaults', 'location'] + self.immutable_props
self.func_locations = defaultdict(dict)
if app is not None:
Expand All @@ -42,7 +43,7 @@ def init_app(self, app):
self.add_custom_template_filters(app)

def teardown(self, exception):
ctx = stack.top
ctx = stack.top # noqa: F841

def add_custom_template_filters(self, app):
"""Add custom filters to jinja2 templating engine"""
Expand Down Expand Up @@ -176,6 +177,8 @@ def html(self, groups='all', template=None, **context):
By specifying the group or groups arguments, only routes belonging to
those groups will be returned.
"""
if not self.app:
raise RuntimeError("Autodoc was not initialized with the Flask app.")
context['autodoc'] = context['autodoc'] if 'autodoc' in context \
else self.generate(groups=groups)
context['defaults'] = context['defaults'] if 'defaults' in context \
Expand All @@ -192,3 +195,28 @@ def html(self, groups='all', template=None, **context):
content = file.read()
with current_app.app_context():
return render_template_string(content, **context)

def json(self, groups='all'):
"""Return a json object with documentation for all the routes specified
by the doc() method.

By specifiying the groups argument, only routes belonging to those groups
will be returned.
"""
autodoc = self.generate(groups=groups)

def endpoint_info(doc):
args = doc['args']
if args == ['None']:
args = []
return {
"args": [(arg, doc['defaults'][arg]) for arg in args],
"docstring": doc['docstring'],
"methods": sorted(list(doc['methods'])),
"rule": doc['rule']
}
data = {
'endpoints':
[endpoint_info(doc) for doc in autodoc]
}
return jsonify(data)
1 change: 0 additions & 1 deletion requirements.txt

This file was deleted.

19 changes: 10 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
Flask-Autodoc
Flask-Selfdoc
-------------

Flask autodoc automatically creates an online documentation for your flask app.
Flask selfdoc automatically creates an online documentation for your flask app.
"""
from setuptools import setup

Expand All @@ -13,19 +13,20 @@ def readme():


setup(
name='Flask-Autodoc',
version='0.1.2',
url='http://github.com/acoomans/flask-autodoc',
name='Flask-Selfdoc',
version='1.0.2',
url='http://github.com/jwg4/flask-selfdoc',
license='MIT',
author='Arnaud Coomans',
author_email='[email protected]',
maintainer='Jack Grahl',
maintainer_email='[email protected]',
description='Documentation generator for flask',
long_description=readme(),
# py_modules=['flask_autodoc'],
# if you would be using a package instead use packages instead
# of py_modules:
packages=['flask_autodoc'],
package_data={'flask_autodoc': ['templates/autodoc_default.html']},
packages=['flask_selfdoc'],
package_data={'flask_selfdoc': ['templates/autodoc_default.html']},
zip_safe=False,
include_package_data=True,
platforms='any',
Expand All @@ -41,5 +42,5 @@ def readme():
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Topic :: Software Development :: Libraries :: Python Modules'
],
test_suite='tests.test_autodoc',
test_suite='tests',
)
11 changes: 6 additions & 5 deletions tests/test_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import os

from flask import Flask
from flask.ext.autodoc import Autodoc
from flask_selfdoc import Autodoc


class TestAutodoc(unittest.TestCase):
Expand Down Expand Up @@ -157,13 +157,14 @@ def testCustomParams(self):
@self.app.route('/needsargs', methods=['GET'])
@self.autodoc.doc('needs_getargs', getargs={
'a': 'A Value',
'b': 'B Value'
'b': 'B Value'
})
def getit():
return 'I need specific GET parameters.'

@self.app.route('/noargs')
@self.autodoc.doc(groups=['needs_json', 'noargs'],
@self.autodoc.doc(
groups=['needs_json', 'noargs'],
expected_type='application/json')
def needjson():
return 'I do not need any parameters, but am picky about types.'
Expand Down Expand Up @@ -259,7 +260,8 @@ def ab(param1, param2):
self.assertIn('Returns arguments', doc)

def testLocation(self):
line_no = inspect.stack()[0][2] + 2 # the doc() line
line_no = inspect.stack()[0][2] + 3 # the doc() line

@self.app.route('/location')
@self.autodoc.doc()
def location():
Expand Down Expand Up @@ -298,4 +300,3 @@ def redecorate():
self.assertTrue(1 == len(self.autodoc.generate('group1')))
self.assertTrue(1 == len(self.autodoc.generate('group2')))
self.assertFalse(1 == len(self.autodoc.generate('group3')))

13 changes: 13 additions & 0 deletions tests/test_error_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import unittest

from flask import Flask
from flask_selfdoc import Autodoc


class TestErrorHandling(unittest.TestCase):
def test_app_not_initialized(self):
app = Flask(__name__)
app.debug = True
autodoc = Autodoc()
with app.app_context():
self.assertRaises(RuntimeError, lambda: autodoc.html())
48 changes: 48 additions & 0 deletions tests/test_flask_get.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import json
import unittest

from flask import Flask
from flask_selfdoc import Autodoc


class TestAutodocWithFlask(unittest.TestCase):
def setUp(self):
self.app = Flask(__name__)
self.autodoc = Autodoc(self.app)

@self.app.route('/')
@self.autodoc.doc()
def index():
"""Returns a hello world message"""
return 'Hello World!'

self.client = self.app.test_client()

def test_html(self):
@self.app.route('/docs')
def html_docs():
return self.autodoc.html()

response = self.client.get('/docs')
self.assertEqual(response.status_code, 200)

def test_json(self):
@self.app.route('/docs')
def json_docs():
return self.autodoc.json()

response = self.client.get('/docs')
self.assertEqual(response.status_code, 200)

data = json.loads(response.data.decode('utf-8'))
self.assertIn('endpoints', data)
self.assertEqual(len(data['endpoints']), 1)

endpoint = data['endpoints'][0]
expected = {
"args": [],
"docstring": "Returns a hello world message",
"methods": ["GET", "HEAD", "OPTIONS"],
"rule": "/"
}
self.assertEqual(endpoint, expected)