diff options
Diffstat (limited to '_exts/httpdomain/autohttp/bottle.py')
-rw-r--r-- | _exts/httpdomain/autohttp/bottle.py | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/_exts/httpdomain/autohttp/bottle.py b/_exts/httpdomain/autohttp/bottle.py new file mode 100644 index 0000000..d8c1859 --- /dev/null +++ b/_exts/httpdomain/autohttp/bottle.py | |||
@@ -0,0 +1,114 @@ | |||
1 | """ | ||
2 | sphinxcontrib.autohttp.bottle | ||
3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
4 | |||
5 | The sphinx.ext.autodoc-style HTTP API reference builder (from Bottle) | ||
6 | for sphinxcontrib.httpdomain. | ||
7 | |||
8 | :copyright: Copyright 2012 by Jameel Al-Aziz | ||
9 | :license: BSD, see LICENSE for details. | ||
10 | |||
11 | """ | ||
12 | |||
13 | import re | ||
14 | import six | ||
15 | |||
16 | from docutils import nodes | ||
17 | from docutils.parsers.rst import directives | ||
18 | from docutils.statemachine import ViewList | ||
19 | |||
20 | from sphinx.util import force_decode | ||
21 | from sphinx.util.compat import Directive | ||
22 | from sphinx.util.nodes import nested_parse_with_titles | ||
23 | from sphinx.util.docstrings import prepare_docstring | ||
24 | from sphinx.pycode import ModuleAnalyzer | ||
25 | |||
26 | from sphinxcontrib import httpdomain | ||
27 | from sphinxcontrib.autohttp.common import http_directive, import_object | ||
28 | |||
29 | |||
30 | def translate_bottle_rule(app, rule): | ||
31 | buf = six.StringIO() | ||
32 | if hasattr(app.router, "parse_rule"): | ||
33 | iterator = app.router.parse_rule(rule) # bottle 0.11 | ||
34 | else: | ||
35 | iterator = app.router._itertokens(rule) # bottle 0.12 | ||
36 | for name, filter, conf in iterator: | ||
37 | if filter: | ||
38 | buf.write('(') | ||
39 | buf.write(name) | ||
40 | if (filter != app.router.default_filter and filter != 'default')\ | ||
41 | or conf: | ||
42 | buf.write(':') | ||
43 | buf.write(filter) | ||
44 | if conf: | ||
45 | buf.write(':') | ||
46 | buf.write(conf) | ||
47 | buf.write(')') | ||
48 | else: | ||
49 | buf.write(name) | ||
50 | return buf.getvalue() | ||
51 | |||
52 | |||
53 | def get_routes(app): | ||
54 | for route in app.routes: | ||
55 | path = translate_bottle_rule(app, route.rule) | ||
56 | yield route.method, path, route | ||
57 | |||
58 | |||
59 | class AutobottleDirective(Directive): | ||
60 | |||
61 | has_content = True | ||
62 | required_arguments = 1 | ||
63 | option_spec = {'endpoints': directives.unchanged, | ||
64 | 'undoc-endpoints': directives.unchanged, | ||
65 | 'include-empty-docstring': directives.unchanged} | ||
66 | |||
67 | @property | ||
68 | def endpoints(self): | ||
69 | endpoints = self.options.get('endpoints', None) | ||
70 | if not endpoints: | ||
71 | return None | ||
72 | return frozenset(re.split(r'\s*,\s*', endpoints)) | ||
73 | |||
74 | @property | ||
75 | def undoc_endpoints(self): | ||
76 | undoc_endpoints = self.options.get('undoc-endpoints', None) | ||
77 | if not undoc_endpoints: | ||
78 | return frozenset() | ||
79 | return frozenset(re.split(r'\s*,\s*', undoc_endpoints)) | ||
80 | |||
81 | def make_rst(self): | ||
82 | app = import_object(self.arguments[0]) | ||
83 | for method, path, target in get_routes(app): | ||
84 | endpoint = target.name or target.callback.__name__ | ||
85 | if self.endpoints and endpoint not in self.endpoints: | ||
86 | continue | ||
87 | if endpoint in self.undoc_endpoints: | ||
88 | continue | ||
89 | view = target.callback | ||
90 | docstring = view.__doc__ or '' | ||
91 | if not isinstance(docstring, six.text_type): | ||
92 | analyzer = ModuleAnalyzer.for_module(view.__module__) | ||
93 | docstring = force_decode(docstring, analyzer.encoding) | ||
94 | if not docstring and 'include-empty-docstring' not in self.options: | ||
95 | continue | ||
96 | docstring = prepare_docstring(docstring) | ||
97 | for line in http_directive(method, path, docstring): | ||
98 | yield line | ||
99 | |||
100 | def run(self): | ||
101 | node = nodes.section() | ||
102 | node.document = self.state.document | ||
103 | result = ViewList() | ||
104 | for line in self.make_rst(): | ||
105 | result.append(line, '<autobottle>') | ||
106 | nested_parse_with_titles(self.state, result, node) | ||
107 | return node.children | ||
108 | |||
109 | |||
110 | def setup(app): | ||
111 | if 'http' not in app.domains: | ||
112 | httpdomain.setup(app) | ||
113 | app.add_directive('autobottle', AutobottleDirective) | ||
114 | |||