"""Provides the ``ifconfig`` directive. The ``ifconfig`` directive enables writing documentation that is included depending on configuration variables. Usage:: .. ifconfig:: releaselevel in ('alpha', 'beta', 'rc') This stuff is only included in the built docs for unstable versions. The argument for ``ifconfig`` is a plain Python expression, evaluated in the namespace of the project configuration (that is, all variables from ``conf.py`` are available.) """ from __future__ import annotations from typing import TYPE_CHECKING, Any from docutils import nodes import sphinx from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import nested_parse_with_titles if TYPE_CHECKING: from docutils.nodes import Node from sphinx.application import Sphinx from sphinx.util.typing import OptionSpec class ifconfig(nodes.Element): pass class IfConfig(SphinxDirective): has_content = True required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True option_spec: OptionSpec = {} def run(self) -> list[Node]: node = ifconfig() node.document = self.state.document self.set_source_info(node) node['expr'] = self.arguments[0] nested_parse_with_titles(self.state, self.content, node, self.content_offset) return [node] def process_ifconfig_nodes(app: Sphinx, doctree: nodes.document, docname: str) -> None: ns = {confval.name: confval.value for confval in app.config} ns.update(app.config.__dict__.copy()) ns['builder'] = app.builder.name for node in list(doctree.findall(ifconfig)): try: res = eval(node['expr'], ns) # NoQA: PGH001 except Exception as err: # handle exceptions in a clean fashion from traceback import format_exception_only msg = ''.join(format_exception_only(err.__class__, err)) newnode = doctree.reporter.error('Exception occurred in ' 'ifconfig expression: \n%s' % msg, base_node=node) node.replace_self(newnode) else: if not res: node.replace_self([]) else: node.replace_self(node.children) def setup(app: Sphinx) -> dict[str, Any]: app.add_node(ifconfig) app.add_directive('ifconfig', IfConfig) app.connect('doctree-resolved', process_ifconfig_nodes) return {'version': sphinx.__display_version__, 'parallel_read_safe': True}