summaryrefslogtreecommitdiffstats
path: root/webapp/django/contrib/admindocs/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/contrib/admindocs/utils.py')
-rw-r--r--webapp/django/contrib/admindocs/utils.py103
1 files changed, 103 insertions, 0 deletions
diff --git a/webapp/django/contrib/admindocs/utils.py b/webapp/django/contrib/admindocs/utils.py
new file mode 100644
index 0000000000..4a45a622b2
--- /dev/null
+++ b/webapp/django/contrib/admindocs/utils.py
@@ -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)