app/django/contrib/admindocs/utils.py
changeset 323 ff1a9aa48cfd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/contrib/admindocs/utils.py	Tue Oct 14 16:00:59 2008 +0000
@@ -0,0 +1,103 @@
+"Misc. utility functions/classes for admin documentation generator."
+
+import re
+from email.Parser import HeaderParser
+from email.Errors import HeaderParseError
+from django.utils.safestring import mark_safe
+try:
+    import docutils.core
+    import docutils.nodes
+    import docutils.parsers.rst.roles
+except ImportError:
+    docutils_is_available = False
+else:
+    docutils_is_available = True
+
+def trim_docstring(docstring):
+    """
+    Uniformly trims leading/trailing whitespace from docstrings.
+
+    Based on http://www.python.org/peps/pep-0257.html#handling-docstring-indentation
+    """
+    if not docstring or not docstring.strip():
+        return ''
+    # Convert tabs to spaces and split into lines
+    lines = docstring.expandtabs().splitlines()
+    indent = min([len(line) - len(line.lstrip()) for line in lines if line.lstrip()])
+    trimmed = [lines[0].lstrip()] + [line[indent:].rstrip() for line in lines[1:]]
+    return "\n".join(trimmed).strip()
+
+def parse_docstring(docstring):
+    """
+    Parse out the parts of a docstring.  Returns (title, body, metadata).
+    """
+    docstring = trim_docstring(docstring)
+    parts = re.split(r'\n{2,}', docstring)
+    title = parts[0]
+    if len(parts) == 1:
+        body = ''
+        metadata = {}
+    else:
+        parser = HeaderParser()
+        try:
+            metadata = parser.parsestr(parts[-1])
+        except HeaderParseError:
+            metadata = {}
+            body = "\n\n".join(parts[1:])
+        else:
+            metadata = dict(metadata.items())
+            if metadata:
+                body = "\n\n".join(parts[1:-1])
+            else:
+                body = "\n\n".join(parts[1:])
+    return title, body, metadata
+
+def parse_rst(text, default_reference_context, thing_being_parsed=None, link_base='../..'):
+    """
+    Convert the string from reST to an XHTML fragment.
+    """
+    overrides = {
+        'doctitle_xform' : True,
+        'inital_header_level' : 3,
+        "default_reference_context" : default_reference_context,
+        "link_base" : link_base,
+    }
+    if thing_being_parsed:
+        thing_being_parsed = "<%s>" % thing_being_parsed
+    parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
+                destination_path=None, writer_name='html',
+                settings_overrides=overrides)
+    return mark_safe(parts['fragment'])
+
+#
+# reST roles
+#
+ROLES = {
+    'model'    : '%s/models/%s/',
+    'view'     : '%s/views/%s/',
+    'template' : '%s/templates/%s/',
+    'filter'   : '%s/filters/#%s',
+    'tag'      : '%s/tags/#%s',
+}
+
+def create_reference_role(rolename, urlbase):
+    def _role(name, rawtext, text, lineno, inliner, options=None, content=None):
+        if options is None: options = {}
+        if content is None: content = []
+        node = docutils.nodes.reference(rawtext, text, refuri=(urlbase % (inliner.document.settings.link_base, text.lower())), **options)
+        return [node], []
+    docutils.parsers.rst.roles.register_canonical_role(rolename, _role)
+
+def default_reference_role(name, rawtext, text, lineno, inliner, options=None, content=None):
+    if options is None: options = {}
+    if content is None: content = []
+    context = inliner.document.settings.default_reference_context
+    node = docutils.nodes.reference(rawtext, text, refuri=(ROLES[context] % (inliner.document.settings.link_base, text.lower())), **options)
+    return [node], []
+
+if docutils_is_available:
+    docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role)
+    docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE = 'cmsreference'
+
+    for name, urlbase in ROLES.items():
+        create_reference_role(name, urlbase)