taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

bottle.py (3640B)


      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