1 "Misc. utility functions/classes for admin documentation generator."
4 from email
.Parser
import HeaderParser
5 from email
.Errors
import HeaderParseError
9 import docutils
.parsers
.rst
.roles
11 docutils_is_available
= False
13 docutils_is_available
= True
15 def trim_docstring(docstring
):
17 Uniformly trims leading/trailing whitespace from docstrings.
19 Based on http://www.python.org/peps/pep-0257.html#handling-docstring-indentation
21 if not docstring
or not docstring
.strip():
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
):
31 Parse out the parts of a docstring. Returns (title, body, metadata).
33 docstring
= trim_docstring(docstring
)
34 parts
= re
.split(r
'\n{2,}', docstring
)
40 parser
= HeaderParser()
42 metadata
= parser
.parsestr(parts
[-1])
43 except HeaderParseError
:
45 body
= "\n\n".join(parts
[1:])
47 metadata
= dict(metadata
.items())
49 body
= "\n\n".join(parts
[1:-1])
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
='../..'):
56 Convert the string from reST to an XHTML fragment.
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']
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
)
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
)
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
)