diff options
Diffstat (limited to 'doc/sphinx/_exts/httpdomain/autohttp/flask_base.py')
-rw-r--r-- | doc/sphinx/_exts/httpdomain/autohttp/flask_base.py | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/doc/sphinx/_exts/httpdomain/autohttp/flask_base.py b/doc/sphinx/_exts/httpdomain/autohttp/flask_base.py new file mode 100644 index 0000000..50454fe --- /dev/null +++ b/doc/sphinx/_exts/httpdomain/autohttp/flask_base.py | |||
@@ -0,0 +1,215 @@ | |||
1 | """ | ||
2 | sphinxcontrib.autohttp.flask | ||
3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
4 | |||
5 | The sphinx.ext.autodoc-style HTTP API reference builder (from Flask) | ||
6 | for sphinxcontrib.httpdomain. | ||
7 | |||
8 | :copyright: Copyright 2011 by Hong Minhee | ||
9 | :license: BSD, see LICENSE for details. | ||
10 | |||
11 | """ | ||
12 | |||
13 | import re | ||
14 | import itertools | ||
15 | import six | ||
16 | |||
17 | from docutils import nodes | ||
18 | from docutils.parsers.rst import directives | ||
19 | from docutils.statemachine import ViewList | ||
20 | |||
21 | from sphinx.util import force_decode | ||
22 | from sphinx.util.compat import Directive | ||
23 | from sphinx.util.nodes import nested_parse_with_titles | ||
24 | from sphinx.util.docstrings import prepare_docstring | ||
25 | from sphinx.pycode import ModuleAnalyzer | ||
26 | |||
27 | from sphinxcontrib import httpdomain | ||
28 | from sphinxcontrib.autohttp.common import http_directive, import_object | ||
29 | |||
30 | |||
31 | def translate_werkzeug_rule(rule): | ||
32 | from werkzeug.routing import parse_rule | ||
33 | buf = six.StringIO() | ||
34 | for conv, arg, var in parse_rule(rule): | ||
35 | if conv: | ||
36 | buf.write('(') | ||
37 | if conv != 'default': | ||
38 | buf.write(conv) | ||
39 | buf.write(':') | ||
40 | buf.write(var) | ||
41 | buf.write(')') | ||
42 | else: | ||
43 | buf.write(var) | ||
44 | return buf.getvalue() | ||
45 | |||
46 | |||
47 | def get_routes(app, endpoint=None, order=None): | ||
48 | endpoints = [] | ||
49 | for rule in app.url_map.iter_rules(endpoint): | ||
50 | url_with_endpoint = ( | ||
51 | six.text_type(next(app.url_map.iter_rules(rule.endpoint))), | ||
52 | rule.endpoint | ||
53 | ) | ||
54 | if url_with_endpoint not in endpoints: | ||
55 | endpoints.append(url_with_endpoint) | ||
56 | if order == 'path': | ||
57 | endpoints.sort() | ||
58 | endpoints = [e for _, e in endpoints] | ||
59 | for endpoint in endpoints: | ||
60 | methodrules = {} | ||
61 | for rule in app.url_map.iter_rules(endpoint): | ||
62 | methods = rule.methods.difference(['OPTIONS', 'HEAD']) | ||
63 | path = translate_werkzeug_rule(rule.rule) | ||
64 | for method in methods: | ||
65 | if method in methodrules: | ||
66 | methodrules[method].append(path) | ||
67 | else: | ||
68 | methodrules[method] = [path] | ||
69 | for method, paths in methodrules.items(): | ||
70 | yield method, paths, endpoint | ||
71 | |||
72 | |||
73 | def quickref_directive(method, path, content): | ||
74 | rcomp = re.compile("^\s*.. :quickref:\s*(?P<quick>.*)$") | ||
75 | method = method.lower().strip() | ||
76 | if isinstance(content, six.string_types): | ||
77 | content = content.splitlines() | ||
78 | description="" | ||
79 | name="" | ||
80 | ref = path.replace("<","(").replace(">",")").replace("/","-").replace(":","-") | ||
81 | for line in content: | ||
82 | qref = rcomp.match(line) | ||
83 | if qref: | ||
84 | quickref = qref.group("quick") | ||
85 | parts = quickref.split(";",1) | ||
86 | if len(parts)>1: | ||
87 | name = parts[0] | ||
88 | description= parts[1] | ||
89 | else: | ||
90 | description= quickref | ||
91 | break | ||
92 | |||
93 | row ={} | ||
94 | row['name'] = name | ||
95 | row['operation'] = ' - `%s %s <#%s-%s>`_' % (method.upper(), path, method.lower(), ref) | ||
96 | row['description'] = description | ||
97 | |||
98 | return row | ||
99 | |||
100 | class AutoflaskBase(Directive): | ||
101 | |||
102 | has_content = True | ||
103 | required_arguments = 1 | ||
104 | option_spec = {'endpoints': directives.unchanged, | ||
105 | 'blueprints': directives.unchanged, | ||
106 | 'modules': directives.unchanged, | ||
107 | 'order': directives.unchanged, | ||
108 | 'undoc-endpoints': directives.unchanged, | ||
109 | 'undoc-blueprints': directives.unchanged, | ||
110 | 'undoc-modules': directives.unchanged, | ||
111 | 'undoc-static': directives.unchanged, | ||
112 | 'include-empty-docstring': directives.unchanged} | ||
113 | |||
114 | @property | ||
115 | def endpoints(self): | ||
116 | endpoints = self.options.get('endpoints', None) | ||
117 | if not endpoints: | ||
118 | return None | ||
119 | return re.split(r'\s*,\s*', endpoints) | ||
120 | |||
121 | @property | ||
122 | def undoc_endpoints(self): | ||
123 | undoc_endpoints = self.options.get('undoc-endpoints', None) | ||
124 | if not undoc_endpoints: | ||
125 | return frozenset() | ||
126 | return frozenset(re.split(r'\s*,\s*', undoc_endpoints)) | ||
127 | |||
128 | @property | ||
129 | def blueprints(self): | ||
130 | blueprints = self.options.get('blueprints', None) | ||
131 | if not blueprints: | ||
132 | return None | ||
133 | return frozenset(re.split(r'\s*,\s*', blueprints)) | ||
134 | |||
135 | @property | ||
136 | def undoc_blueprints(self): | ||
137 | undoc_blueprints = self.options.get('undoc-blueprints', None) | ||
138 | if not undoc_blueprints: | ||
139 | return frozenset() | ||
140 | return frozenset(re.split(r'\s*,\s*', undoc_blueprints)) | ||
141 | |||
142 | @property | ||
143 | def modules(self): | ||
144 | modules = self.options.get('modules', None) | ||
145 | if not modules: | ||
146 | return frozenset() | ||
147 | return frozenset(re.split(r'\s*,\s*', modules)) | ||
148 | |||
149 | @property | ||
150 | def undoc_modules(self): | ||
151 | undoc_modules = self.options.get('undoc-modules', None) | ||
152 | if not undoc_modules: | ||
153 | return frozenset() | ||
154 | return frozenset(re.split(r'\s*,\s*', undoc_modules)) | ||
155 | |||
156 | @property | ||
157 | def order(self): | ||
158 | order = self.options.get('order', None) | ||
159 | if order not in (None, 'path'): | ||
160 | raise ValueError('Invalid value for :order:') | ||
161 | return order | ||
162 | |||
163 | def make_rst(self, qref=False): | ||
164 | app = import_object(self.arguments[0]) | ||
165 | if self.endpoints: | ||
166 | routes = itertools.chain(*[get_routes(app, endpoint, self.order) | ||
167 | for endpoint in self.endpoints]) | ||
168 | else: | ||
169 | routes = get_routes(app, order=self.order) | ||
170 | for method, paths, endpoint in routes: | ||
171 | try: | ||
172 | blueprint, _, endpoint_internal = endpoint.rpartition('.') | ||
173 | if self.blueprints and blueprint not in self.blueprints: | ||
174 | continue | ||
175 | if blueprint in self.undoc_blueprints: | ||
176 | continue | ||
177 | except ValueError: | ||
178 | pass # endpoint is not within a blueprint | ||
179 | |||
180 | if endpoint in self.undoc_endpoints: | ||
181 | continue | ||
182 | try: | ||
183 | static_url_path = app.static_url_path # Flask 0.7 or higher | ||
184 | except AttributeError: | ||
185 | static_url_path = app.static_path # Flask 0.6 or under | ||
186 | if ('undoc-static' in self.options and endpoint == 'static' and | ||
187 | static_url_path + '/(path:filename)' in paths): | ||
188 | continue | ||
189 | view = app.view_functions[endpoint] | ||
190 | |||
191 | if self.modules and view.__module__ not in self.modules: | ||
192 | continue | ||
193 | |||
194 | if self.undoc_modules and view.__module__ in self.modules: | ||
195 | continue | ||
196 | |||
197 | docstring = view.__doc__ or '' | ||
198 | if hasattr(view, 'view_class'): | ||
199 | meth_func = getattr(view.view_class, method.lower(), None) | ||
200 | if meth_func and meth_func.__doc__: | ||
201 | docstring = meth_func.__doc__ | ||
202 | if not isinstance(docstring, six.text_type): | ||
203 | analyzer = ModuleAnalyzer.for_module(view.__module__) | ||
204 | docstring = force_decode(docstring, analyzer.encoding) | ||
205 | |||
206 | if not docstring and 'include-empty-docstring' not in self.options: | ||
207 | continue | ||
208 | docstring = prepare_docstring(docstring) | ||
209 | if qref == True: | ||
210 | for path in paths: | ||
211 | row = quickref_directive(method, path, docstring) | ||
212 | yield row | ||
213 | else: | ||
214 | for line in http_directive(method, paths, docstring): | ||
215 | yield line | ||