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