PageRenderTime 203ms CodeModel.GetById 111ms app.highlight 11ms RepoModel.GetById 79ms app.codeStats 0ms

/django/contrib/admindocs/utils.py

https://code.google.com/p/mango-py/
Python | 105 lines | 94 code | 6 blank | 5 comment | 11 complexity | 83b4c20b2731439cd37b3bf13202db7f MD5 | raw file
  1"Misc. utility functions/classes for admin documentation generator."
  2
  3import re
  4from email.Parser import HeaderParser
  5from email.Errors import HeaderParseError
  6from django.utils.safestring import mark_safe
  7from django.core.urlresolvers import reverse
  8from django.utils.encoding import smart_str
  9try:
 10    import docutils.core
 11    import docutils.nodes
 12    import docutils.parsers.rst.roles
 13except ImportError:
 14    docutils_is_available = False
 15else:
 16    docutils_is_available = True
 17
 18def trim_docstring(docstring):
 19    """
 20    Uniformly trims leading/trailing whitespace from docstrings.
 21
 22    Based on http://www.python.org/peps/pep-0257.html#handling-docstring-indentation
 23    """
 24    if not docstring or not docstring.strip():
 25        return ''
 26    # Convert tabs to spaces and split into lines
 27    lines = docstring.expandtabs().splitlines()
 28    indent = min([len(line) - len(line.lstrip()) for line in lines if line.lstrip()])
 29    trimmed = [lines[0].lstrip()] + [line[indent:].rstrip() for line in lines[1:]]
 30    return "\n".join(trimmed).strip()
 31
 32def parse_docstring(docstring):
 33    """
 34    Parse out the parts of a docstring.  Returns (title, body, metadata).
 35    """
 36    docstring = trim_docstring(docstring)
 37    parts = re.split(r'\n{2,}', docstring)
 38    title = parts[0]
 39    if len(parts) == 1:
 40        body = ''
 41        metadata = {}
 42    else:
 43        parser = HeaderParser()
 44        try:
 45            metadata = parser.parsestr(parts[-1])
 46        except HeaderParseError:
 47            metadata = {}
 48            body = "\n\n".join(parts[1:])
 49        else:
 50            metadata = dict(metadata.items())
 51            if metadata:
 52                body = "\n\n".join(parts[1:-1])
 53            else:
 54                body = "\n\n".join(parts[1:])
 55    return title, body, metadata
 56
 57def parse_rst(text, default_reference_context, thing_being_parsed=None):
 58    """
 59    Convert the string from reST to an XHTML fragment.
 60    """
 61    overrides = {
 62        'doctitle_xform' : True,
 63        'inital_header_level' : 3,
 64        "default_reference_context" : default_reference_context,
 65        "link_base" : reverse('django-admindocs-docroot').rstrip('/')
 66    }
 67    if thing_being_parsed:
 68        thing_being_parsed = smart_str("<%s>" % thing_being_parsed)
 69    parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
 70                destination_path=None, writer_name='html',
 71                settings_overrides=overrides)
 72    return mark_safe(parts['fragment'])
 73
 74#
 75# reST roles
 76#
 77ROLES = {
 78    'model'    : '%s/models/%s/',
 79    'view'     : '%s/views/%s/',
 80    'template' : '%s/templates/%s/',
 81    'filter'   : '%s/filters/#%s',
 82    'tag'      : '%s/tags/#%s',
 83}
 84
 85def create_reference_role(rolename, urlbase):
 86    def _role(name, rawtext, text, lineno, inliner, options=None, content=None):
 87        if options is None: options = {}
 88        if content is None: content = []
 89        node = docutils.nodes.reference(rawtext, text, refuri=(urlbase % (inliner.document.settings.link_base, text.lower())), **options)
 90        return [node], []
 91    docutils.parsers.rst.roles.register_canonical_role(rolename, _role)
 92
 93def default_reference_role(name, rawtext, text, lineno, inliner, options=None, content=None):
 94    if options is None: options = {}
 95    if content is None: content = []
 96    context = inliner.document.settings.default_reference_context
 97    node = docutils.nodes.reference(rawtext, text, refuri=(ROLES[context] % (inliner.document.settings.link_base, text.lower())), **options)
 98    return [node], []
 99
100if docutils_is_available:
101    docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role)
102    docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE = 'cmsreference'
103
104    for name, urlbase in ROLES.items():
105        create_reference_role(name, urlbase)