3 This module is a Sphinx Extension for the Belle~II Software:
5 * add a domain "b2" for modules and variables.
6 Modules can be documented using the ``.. b2:module::` directive and variables
7 using the ``.. b2:variable::` directive. They can be cross referenced with
8 :b2:mod: and :b2:var: respectively
9 * add an index for basf2 modules
10 * add a directive to automatically document basf2 modules similar to autodoc
14 :modules: EventInfoSetter, EventInfoPrinter
16 :regex-filter: Event.*
18 * add directive to automatically document basf2 variables
31 from docutils
import nodes
32 from sphinx.util.nodes
import nested_parse_with_titles
33 from docutils.parsers.rst
import directives, Directive, roles
34 from docutils.statemachine
import StringList
35 from basf2domain
import Basf2Domain
36 from basf2
import list_available_modules, register_module
37 from sphinx.domains.std
import StandardDomain
41 """Shortcut function to parse a reStructuredText fragment into docutils nodes"""
42 node = nodes.container()
44 node.document = state.document
45 if isinstance(content, str):
46 content = content.splitlines()
47 if not isinstance(content, StringList):
48 content = StringList(content)
49 nested_parse_with_titles(state, content, node)
54 """Directive to Render Docstring as Docutils nodes.
55 This is useful as standard reStructuredText does not parse Google
56 Docstrings but we support it in docstrings for python functions, modules
57 and variables. So to show example docstrings in the documentation we don't
58 want to write the example in Google Docstring and keep that synchronous
59 with a reStructuredText version
63 "lines": directives.unchanged
67 """Just pass on the content to the autodoc-process-docstring event and
68 then parse the resulting reStructuredText."""
69 env = self.state.document.settings.env
70 content = list(self.content)
72 start_index, end_index = [int(e)
for e
in self.options.get(
"lines",
None).split(
",")]
73 content = content[start_index:end_index]
78 content = textwrap.dedent(
"\n".join(content)).splitlines()
80 env.app.emit(
'autodoc-process-docstring',
"docstring",
None,
None,
None, content)
87 "library": directives.unchanged,
88 "modules": directives.unchanged,
89 "package": directives.unchanged,
90 "no-parameters": directives.flag,
91 "noindex": directives.flag,
92 "regex-filter": directives.unchanged,
93 "io-plots": directives.flag,
96 def show_module(self, module, library):
97 description = module.description().splitlines()
101 env = self.state.document.settings.env
102 env.app.emit(
'autodoc-process-docstring',
"b2:module", module.name(), module,
None, description)
103 description += [
"",
"",
104 ":Package: %s" % module.package(),
105 ":Library: %s" % os.path.basename(library),
108 if "no-parameters" not in self.options:
111 for p
in module.available_params():
112 dest = required_params
if p.forceInSteering
else optional_params
113 default =
"" if p.forceInSteering
else ", default={default!r}".format(default=p.default)
114 param_desc = p.description.splitlines()
117 env.app.emit(
'autodoc-process-docstring',
'b2:module:param', module.name() +
'.' + p.name, p,
None, param_desc)
118 param_desc = textwrap.indent(
"\n".join(param_desc), 8 *
" ").splitlines()
119 dest += [
" * **{name}** *({type}{default})*".format(name=p.name, type=p.type, default=default)]
123 description += [
":Required Parameters:",
" "] + required_params
125 description += [
":Parameters:",
" "] + optional_params
127 if "io-plots" in self.options:
128 image =
"build/ioplots/%s.png" % module.name()
129 if os.path.exists(image):
130 description += [
":IO diagram:",
" ",
" .. image:: /%s" % image]
132 content = [
".. b2:module:: {module}".format(module=module.name())] + self.
noindex + [
" "]
133 content += [
" " + e
for e
in description]
137 all_modules = list_available_modules().items()
140 if "modules" in self.options:
141 modules = [e.strip()
for e
in self.options[
"modules"].split(
",")]
142 all_modules = [e
for e
in all_modules
if e[0]
in modules]
145 if "regex-filter" in self.options:
146 re_filter = re.compile(self.options[
"regex-filter"])
147 all_modules = [e
for e
in all_modules
if re_filter.match(e[0])
is not None]
151 if "library" in self.options:
152 lib = self.options[
"library"].strip()
153 all_modules = [e
for e
in all_modules
if os.path.basenam(e[1]) == lib]
156 self.
noindex = [
" :noindex:"]
if "noindex" in self.options
else []
162 for name, library
in sorted(all_modules):
163 module = register_module(name)
165 if "package" in self.options
and module.package() != self.options[
"package"]:
177 "group": directives.unchanged,
178 "variables": directives.unchanged,
179 "regex-filter": directives.unchanged,
180 "description-regex-filter": directives.unchanged,
181 "noindex": directives.flag,
185 from ROOT
import Belle2
187 self.
noindex = [
" :noindex:"]
if "noindex" in self.options
else []
191 desc_regex_filter =
None
192 if "variables" in self.options:
193 explicit_list = [e.strip()
for e
in self.options[
"variables"].split(
",")]
194 if "regex-filter" in self.options:
195 regex_filter = re.compile(self.options[
"regex-filter"])
196 if "description-regex-filter" in self.options:
197 desc_regex_filter = re.compile(self.options[
"description-regex-filter"])
199 for var
in manager.getVariables():
200 if "group" in self.options
and self.options[
"group"] != var.group:
202 if explicit_list
and var.name
not in explicit_list:
204 if regex_filter
and not regex_filter.match(var.name):
206 if desc_regex_filter
and not desc_regex_filter.match(var.description):
208 all_variables.append(var)
211 env = self.state.document.settings.env
212 for var
in sorted(all_variables, key=
lambda x: x.name):
217 if ":noindex:" in var.description:
218 index = [
" :noindex:"]
219 var.description = var.description.replace(
":noindex:",
"")
221 docstring = var.description.splitlines()
225 env.app.emit(
'autodoc-process-docstring',
"b2:variable", var.name, var,
None, docstring)
227 description = [f
".. b2:variable:: {var.name}"] + index + [
""]
228 description += [
" " + e
for e
in docstring]
229 if "group" not in self.options:
230 description += [
"", f
" :Group: {var.group}"]
238 """Provide Link to Stash Repository, see https://mg.pov.lt/blog/sphinx-edit-on-github.html
240 this goes in conjunction with
241 site_scons/sphinx/_sphinxtemplates/sourcelink.html and adds a link to our
242 git repository instead to the local source link
245 if templatename !=
'page.html' or not doctree:
248 path = os.path.relpath(doctree.get(
'source'), app.builder.srcdir)
249 repository = app.config.basf2_repository
253 commit = app.config.basf2_commitid
254 context[
"source_url"] = f
"{repository}/browse/{path}"
256 context[
"source_url"] +=
"?at=" + commit
259 def jira_issue_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
260 jira_url = inliner.document.settings.env.app.config.basf2_jira
262 return [nodes.literal(rawtext, text=text, language=
None)], []
264 url = f
"{jira_url}/browse/{text}"
265 return [nodes.reference(rawtext, text=text, refuri=url)], []
270 basf2.logging.log_level = basf2.LogLevel.WARNING
272 app.add_config_value(
"basf2_repository",
"",
True)
273 app.add_config_value(
"basf2_commitid",
"",
True)
274 app.add_config_value(
"basf2_jira",
"",
True)
275 app.add_domain(Basf2Domain)
276 app.add_directive(
"b2-modules", ModuleListDirective)
277 app.add_directive(
"b2-variables", VariableListDirective)
278 app.add_directive(
"docstring", RenderDocstring)
279 app.add_role(
"issue", jira_issue_role)
280 app.connect(
'html-page-context', html_page_context)
283 StandardDomain.initial_data[
"labels"][
"b2-modindex"] = (
"b2-modindex",
"",
"Basf2 Module Index")
284 StandardDomain.initial_data[
"labels"][
"b2-varindex"] = (
"b2-varindex",
"",
"Basf2 Variable Index")
285 StandardDomain.initial_data[
"anonlabels"][
"b2-modindex"] = (
"b2-modindex",
"")
286 StandardDomain.initial_data[
"anonlabels"][
"b2-varindex"] = (
"b2-varindex",
"")
287 return {
'version': 0.2}