diff options
Diffstat (limited to 'doc/sphinx/_exts/httpdomain/autohttp/tornado.py')
-rw-r--r-- | doc/sphinx/_exts/httpdomain/autohttp/tornado.py | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/doc/sphinx/_exts/httpdomain/autohttp/tornado.py b/doc/sphinx/_exts/httpdomain/autohttp/tornado.py new file mode 100644 index 0000000..9a514fe --- /dev/null +++ b/doc/sphinx/_exts/httpdomain/autohttp/tornado.py | |||
@@ -0,0 +1,128 @@ | |||
1 | """ | ||
2 | sphinxcontrib.autohttp.tornado | ||
3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
4 | |||
5 | The sphinx.ext.autodoc-style HTTP API reference builder (from Tornado) | ||
6 | for sphinxcontrib.httpdomain. | ||
7 | |||
8 | :copyright: Copyright 2013 by Rodrigo Machado | ||
9 | :license: BSD, see LICENSE for details. | ||
10 | |||
11 | """ | ||
12 | |||
13 | import inspect | ||
14 | import re | ||
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_tornado_rule(app, rule): | ||
32 | buf = six.StringIO() | ||
33 | for name, filter, conf in app.router.parse_rule(rule): | ||
34 | if filter: | ||
35 | buf.write('(') | ||
36 | buf.write(name) | ||
37 | if filter != app.router.default_filter or conf: | ||
38 | buf.write(':') | ||
39 | buf.write(filter) | ||
40 | if conf: | ||
41 | buf.write(':') | ||
42 | buf.write(conf) | ||
43 | buf.write(')') | ||
44 | else: | ||
45 | buf.write(name) | ||
46 | return buf.getvalue() | ||
47 | |||
48 | |||
49 | def get_routes(app): | ||
50 | for spec in app.handlers[0][1]: | ||
51 | handler = spec.handler_class | ||
52 | doc_methods = list(handler.SUPPORTED_METHODS) | ||
53 | if 'HEAD' in doc_methods: | ||
54 | doc_methods.remove('HEAD') | ||
55 | if 'OPTIONS' in doc_methods: | ||
56 | doc_methods.remove('OPTIONS') | ||
57 | |||
58 | for method in doc_methods: | ||
59 | maybe_method = getattr(handler, method.lower(), None) | ||
60 | if (inspect.isfunction(maybe_method) or | ||
61 | inspect.ismethod(maybe_method)): | ||
62 | yield method.lower(), spec.regex.pattern, handler | ||
63 | |||
64 | |||
65 | def normalize_path(path): | ||
66 | if path.endswith('$'): | ||
67 | path = path[:-1] | ||
68 | return path | ||
69 | |||
70 | |||
71 | class AutoTornadoDirective(Directive): | ||
72 | |||
73 | has_content = True | ||
74 | required_arguments = 1 | ||
75 | option_spec = {'endpoints': directives.unchanged, | ||
76 | 'undoc-endpoints': directives.unchanged, | ||
77 | 'include-empty-docstring': directives.unchanged} | ||
78 | |||
79 | @property | ||
80 | def endpoints(self): | ||
81 | endpoints = self.options.get('endpoints', None) | ||
82 | if not endpoints: | ||
83 | return None | ||
84 | return frozenset(re.split(r'\s*,\s*', endpoints)) | ||
85 | |||
86 | @property | ||
87 | def undoc_endpoints(self): | ||
88 | undoc_endpoints = self.options.get('undoc-endpoints', None) | ||
89 | if not undoc_endpoints: | ||
90 | return frozenset() | ||
91 | return frozenset(re.split(r'\s*,\s*', undoc_endpoints)) | ||
92 | |||
93 | def make_rst(self): | ||
94 | app = import_object(self.arguments[0]) | ||
95 | for method, path, handler in get_routes(app): | ||
96 | class_name = handler.__name__ | ||
97 | method_name = getattr(handler, method).__name__ | ||
98 | endpoint = '.'.join((class_name, method_name)) | ||
99 | |||
100 | if self.endpoints and endpoint not in self.endpoints: | ||
101 | continue | ||
102 | if endpoint in self.undoc_endpoints: | ||
103 | continue | ||
104 | |||
105 | docstring = getattr(handler, method).__doc__ or '' | ||
106 | #if not isinstance(docstring, unicode): | ||
107 | # analyzer = ModuleAnalyzer.for_module(view.__module__) | ||
108 | # docstring = force_decode(docstring, analyzer.encoding) | ||
109 | if not docstring and 'include-empty-docstring' not in self.options: | ||
110 | continue | ||
111 | docstring = prepare_docstring(docstring) | ||
112 | for line in http_directive(method, normalize_path(path), docstring): | ||
113 | yield line | ||
114 | |||
115 | def run(self): | ||
116 | node = nodes.section() | ||
117 | node.document = self.state.document | ||
118 | result = ViewList() | ||
119 | for line in self.make_rst(): | ||
120 | result.append(line, '<autotornado>') | ||
121 | nested_parse_with_titles(self.state, result, node) | ||
122 | return node.children | ||
123 | |||
124 | |||
125 | def setup(app): | ||
126 | if 'http' not in app.domains: | ||
127 | httpdomain.setup(app) | ||
128 | app.add_directive('autotornado', AutoTornadoDirective) | ||