def apply(self): sphinx = import_sphinx() env = self.document.settings.env for node in self.document.traverse(docutils.nodes.reference): base, suffix, fragment = _local_file_from_reference(node, self.document) if not base: continue for s in env.config.source_suffix: if suffix.lower() == s.lower(): target = base if fragment: target_ext = suffix + fragment reftype = 'ref' else: target_ext = '' reftype = 'doc' break else: continue # Not a link to a potential Sphinx source file target_docname = nbconvert.filters.posix_path(os.path.normpath( os.path.join(os.path.dirname(env.docname), target))) if target_docname in env.found_docs: reftarget = '/' + target_docname + target_ext if reftype == 'ref': reftarget = reftarget.lower() linktext = node.astext() xref = sphinx.addnodes.pending_xref( reftype=reftype, reftarget=reftarget, refdomain='std', refwarn=True, refexplicit=True, refdoc=env.docname) xref += docutils.nodes.Text(linktext, linktext) node.replace_self(xref)
def setup(app): # type: (Sphinx) -> dict """Initialize Sphinx extension. """ # delayed import of sphinx sphinx = import_sphinx() try: transforms = app.registry.get_transforms() except AttributeError: # Sphinx < 1.7 from sphinx.io import SphinxStandaloneReader transforms = SphinxStandaloneReader.transforms def add_transform(transform, post=False): if transform not in transforms: if post: app.add_post_transform(transform) else: app.add_transform(transform) # BibGlossary functionality app.connect("builder-inited", bibproc.init_bibgloss_cache) app.connect("doctree-resolved", bibproc.process_citations) app.connect("doctree-resolved", bibproc.process_citation_references) app.connect("env-purge-doc", bibproc.purge_bibgloss_cache) # app.connect("env-updated", bibproc.check_duplicate_labels) app.add_config_value("bibgloss_convert_latex", True, rebuild="html") app.add_config_value("bibgloss_default_style", "list", rebuild="html") app.add_directive("bibglossary", BibGlossaryDirective) # Note: because docutils.parsers.rst.roles.role(role_name) # applies role_name.lower(), you can't have unique gls and Gls roles app.add_role("gls", GLSRole()) app.add_role("glsc", GLSCapitalRole()) app.add_role("glspl", GLSPluralRole()) app.add_role("glscpl", GLSPluralCapitalRole()) app.add_node(BibGlossaryNode, override=True) add_transform(BibGlossaryTransform) # these patches have been fixed (by me!) upstream if sphinx.version_info < (2, ): add_transform(OverrideCitationReferences) add_transform(HandleMissingCitesTransform, post=True) # Parallel read is not safe at the moment: in the current design, # the document that contains references must be read last for all # references to be resolved. parallel_read_safe = False return { "version": __version__, "parallel_read_safe": parallel_read_safe, "parallel_write_safe": True, "env_version": 1, }
def associate_single_extension(app, extension, suffix='jupyter_notebook', called_from_setup=False, config_value=None): # type: (Sphinx, str) -> None """ associate a file extension with the NBParser Notes ----- The Ugly hack to modify source_suffix and source_parsers. Once https://github.com/sphinx-doc/sphinx/pull/2209 is merged it won't be necessary. See also https://github.com/sphinx-doc/sphinx/issues/2162. """ if not isinstance(extension, string_types): raise AssertionError("extension is not a string: {}".format(extension)) if not extension.startswith("."): raise AssertionError( "extension should start with a '.': {}".format(extension)) sphinx = import_sphinx() try: # Available since Sphinx 1.8: app.add_source_suffix(extension, suffix) except AttributeError: if not called_from_setup: # too late to set up, see # https://github.com/sphinx-doc/sphinx/issues/2162#issuecomment-169193107 raise sphinx.errors.ExtensionError( "Using sphinx<1.8, {0} cannot be used.\n" "Instead use: source_parsers = " "{{'{1}': 'ipypublish.ipysphinx.parser.NBParser'}} " "in conf.py".format(config_value, extension)) source_suffix = app.config._raw_config.get('source_suffix', ['.rst']) if isinstance(source_suffix, sphinx.config.string_types): source_suffix = [source_suffix] if extension not in source_suffix: source_suffix.append(extension) app.config._raw_config['source_suffix'] = source_suffix source_parsers = app.config._raw_config.get('source_parsers', {}) if (extension not in source_parsers and extension[1:] not in source_parsers): source_parsers[extension] = NBParser app.config._raw_config['source_parsers'] = source_parsers sphinx.util.logging.getLogger('nbparser').info( "ipypublish: associated {} with NBParser".format(extension))
def associate_single_extension(app, extension, suffix="jupyter_notebook"): # type: (Sphinx, str) -> None """Associate a file extension with the NBParser.""" if not isinstance(extension, six.string_types): raise AssertionError("extension is not a string: {}".format(extension)) if not extension.startswith("."): raise AssertionError( "extension should start with a '.': {}".format(extension)) sphinx = import_sphinx() app.add_source_suffix(extension, suffix) sphinx.util.logging.getLogger("nbparser").info( "ipypublish: associated {} with NBParser".format(extension), color="green")
def apply(self): sphinx = import_sphinx() env = self.document.settings.env file_ext = os.path.splitext(env.doc2path(env.docname))[1] for sig in self.document.traverse(sphinx.addnodes.desc_signature): try: title = sig["ids"][0] except IndexError: # Object has same name as another, so skip it continue link_id = title.replace(" ", "-") sig["ids"] = [link_id] label = "/" + env.docname + file_ext + "#" + link_id label = label.lower() env.domaindata["std"]["labels"][label] = (env.docname, link_id, title) env.domaindata["std"]["anonlabels"][label] = (env.docname, link_id)
def add_ipywidgets_js_path(app, env): """Insert the ipywidgets javascript url, to pages created from notebooks containing widgets.""" if not (getattr(env, "ipysphinx_widgets", set()) or app.config.ipysphinx_always_add_jsurls): return sphinx = import_sphinx() widgets_path = None if app.config.ipysphinx_widgets_jsurl is None: try: from ipywidgets.embed import DEFAULT_EMBED_REQUIREJS_URL except ImportError: logger = sphinx.util.logging.getLogger(__name__) logger.warning( "ipysphinx_widgets_jsurl not given and ipywidgets module unavailable" ) else: widgets_path = DEFAULT_EMBED_REQUIREJS_URL else: widgets_path = app.config.ipysphinx_widgets_jsurl if widgets_path is not None: app.add_js_file(widgets_path, **app.config.ipysphinx_widgetsjs_options)
def __init__(self, *args, **kwargs): self.app = None self.config = None self.env = None try: sphinx = import_sphinx() class NotebookError(sphinx.errors.SphinxError): """Error during notebook parsing.""" category = 'Notebook error' self.error_nb = NotebookError self.error_config = sphinx.errors.ConfigError self.logger = sphinx.util.logging.getLogger('nbparser') except (ImportError, AttributeError): self.error_nb = IOError self.error_config = TypeError self.logger = logging.getLogger('nbparser') super(NBParser, self).__init__(*args, **kwargs)
def setup(app): # type: (Sphinx) -> dict """Initialize Sphinx extension. Notes ----- TODO better latex output but not really interested in this as it would be duplication of effort, and if much better todo ipynb -> tex, rather than ipynb -> rst -> tex TODO handling of svg in latex ipypublish sets latex to output svg rather than pdf, so we don't have to split output into '.. only html/latex', which is an issue its something with a label (duplication error), however, this requires sphinx.ext.imgconverter to work """ # delayed import of sphinx sphinx = import_sphinx() try: transforms = app.registry.get_transforms() except AttributeError: # Sphinx < 1.7 from sphinx.io import SphinxStandaloneReader transforms = SphinxStandaloneReader.transforms def add_transform(transform, post=False): if transform not in transforms: if post: app.add_post_transform(transform) else: app.add_transform(transform) try: # Available since Sphinx 1.8: app.add_source_parser(NBParser) except TypeError: # Available since Sphinx 1.4: app.add_source_parser('jupyter_notebook', NBParser) associate_single_extension(app, '.ipynb', called_from_setup=True) # config for export config app.add_config_value('ipysphinx_export_config', 'sphinx_ipypublish_all.ext', rebuild='env') # config for contolling conversion process # where to dump internal images, etc of the notebook app.add_config_value('ipysphinx_folder_suffix', '_nbfiles', rebuild='env') # whether to raise error if nb_name.rst already exists app.add_config_value('ipysphinx_overwrite_existing', False, rebuild='env') # additional folders containing conversion files app.add_config_value('ipysphinx_config_folders', (), rebuild='env') # config for cell prompts app.add_config_value('ipysphinx_show_prompts', False, rebuild='env') app.add_config_value('ipysphinx_input_prompt', '[{count}]:', rebuild='env') app.add_config_value('ipysphinx_output_prompt', '[{count}]:', rebuild='env') # config for cell toggling app.add_config_value('ipysphinx_input_toggle', False, rebuild='env') app.add_config_value('ipysphinx_output_toggle', False, rebuild='env') # config for html css app.add_config_value('ipysphinx_responsive_width', '540px', rebuild='html') app.add_config_value('ipysphinx_prompt_width', None, rebuild='html') # setup html style app.connect('builder-inited', set_css_prompts) app.connect('html-page-context', html_add_css) # add javascript app.connect('html-page-context', html_add_javascript) # config for additions to the output rst (per file) # these strings are processed by the exporters jinja template app.add_config_value('ipysphinx_prolog', None, rebuild='env') app.add_config_value('ipysphinx_epilog', None, rebuild='env') # map additional file extensions to pre-converters # NB: jupytext is already a default for .Rmd app.add_config_value('ipysphinx_preconverters', {}, rebuild='env') app.connect('builder-inited', associate_extensions) # add the main directives app.add_directive('nbinput', NbInput) app.add_directive('nboutput', NbOutput) app.add_directive('nbinfo', NbInfo) app.add_directive('nbwarning', NbWarning) app.add_directive('nbinput-toggle-all', NBInputToggle) app.add_directive('nboutput-toggle-all', NBOutputToggle) # add docutils nodes and visit/depart wraps app.add_node( CodeAreaNode, html=(lambda self, node: None, depart_codearea_html), # latex=( # lambda self, node: self.pushbody([]), # used in depart # lambda self, node: None, # ) ) app.add_node( FancyOutputNode, html=( lambda self, node: None, lambda self, node: None, ), # latex=( # lambda self, node: None, # lambda self, node: None, # ) ) app.add_node( AdmonitionNode, html=(visit_admonition_html, lambda self, node: self.body.append('</div>\n')), # latex=( # lambda self, node: # self.body.append( # '\n\\begin{{sphinxadmonition}}{{{class}}}' # '{{}}\\unskip'.format(node['classes'][1])), # lambda self, node: # self.body.append('\\end{sphinxadmonition}\n') # ) ) # add transformations add_transform(CreateSectionLabels) add_transform(CreateDomainObjectLabels) add_transform(RewriteLocalLinks) # Work-around until https://github.com/sphinx-doc/sphinx/pull/5504 is done: mathjax_config = app.config._raw_config.setdefault('mathjax_config', {}) mathjax_config.setdefault( 'tex2jax', { 'inlineMath': [['$', '$'], ['\\(', '\\)']], 'processEscapes': True, 'ignoreClass': 'document', 'processClass': 'math|output_area', }) # Make docutils' "code" directive (generated by markdown2rst/pandoc) # behave like Sphinx's "code-block", # see https://github.com/sphinx-doc/sphinx/issues/2155: rst.directives.register_directive('code', sphinx.directives.code.CodeBlock) return { 'version': __version__, 'parallel_read_safe': True, 'parallel_write_safe': True, 'env_version': 1, }
def _create_nbcell_nodes(directive): """Create nodes for an input or output notebook cell.""" sphinx = import_sphinx() language = 'none' prompt = '' fancy_output = False execution_count = directive.options.get('execution-count') config = directive.state.document.settings.env.config if isinstance(directive, NbInput): outer_classes = ['nbinput'] if 'no-output' in directive.options: outer_classes.append('nblast') inner_classes = ['input_area'] if directive.arguments: language = directive.arguments[0] prompt_template = config.ipysphinx_input_prompt if not execution_count: execution_count = ' ' elif isinstance(directive, NbOutput): outer_classes = ['nboutput'] if 'more-to-come' not in directive.options: outer_classes.append('nblast') inner_classes = ['output_area'] # 'class' can be 'stderr' inner_classes.append(directive.options.get('class', '')) prompt_template = config.ipysphinx_output_prompt if directive.arguments and directive.arguments[0] in ['rst', 'ansi']: fancy_output = True else: raise AssertionError("directive should be NbInput or NbOutput") outer_node = docutils.nodes.container(classes=outer_classes) # add prompts if config.ipysphinx_show_prompts and execution_count: prompt = prompt_template.format(count=execution_count) prompt_node = docutils.nodes.literal_block(prompt, prompt, language='none', classes=['prompt']) elif config.ipysphinx_show_prompts: prompt = '' prompt_node = docutils.nodes.container(classes=['prompt', 'empty']) if config.ipysphinx_show_prompts: # NB: Prompts are added manually in LaTeX output outer_node += sphinx.addnodes.only('', prompt_node, expr='html') if fancy_output: inner_node = docutils.nodes.container(classes=inner_classes) sphinx.util.nodes.nested_parse_with_titles(directive.state, directive.content, inner_node) outtype = directive.arguments[0] if outtype == 'rst': outer_node += FancyOutputNode('', inner_node, prompt=prompt) elif outtype == 'ansi': outer_node += inner_node else: raise AssertionError( "`.. nboutput:: type` should be 'rst' or 'ansi', " "not: {}".format(outtype)) else: text = '\n'.join(directive.content.data) inner_node = docutils.nodes.literal_block(text, text, language=language, classes=inner_classes) codearea_node = CodeAreaNode('', inner_node, prompt=prompt) # create a literal text block (e.g. with the code-block directive), # that starts or ends with a blank line # (see http://stackoverflow.com/q/34050044/) for attr in 'empty-lines-before', 'empty-lines-after': value = directive.options.get(attr, 0) if value: codearea_node[attr] = value # add caption and label, see: if directive.options.get("caption", False): caption = directive.options.get("caption") wrapper = container_wrapper(directive, inner_node, caption, inner_classes) # add label directive.add_name(wrapper) outer_node += wrapper else: outer_node += codearea_node return [outer_node]
def run_postprocess(self, stream, mimetype, filepath, resources): # check sphinx is available and the correct version try: import_sphinx() except ImportError as err: self.handle_error(err.msg, ImportError) self.logger.info("Creating Sphinx files") titlepage = {} if "titlepage" in resources.get("ipub", {}): titlepage = resources["ipub"]["titlepage"] # includes ['author', 'email', 'supervisors', 'title', 'subtitle', # 'tagline', 'institution', 'logo'] # create a conf.py kwargs = {} if not self.conf_kwargs else self.conf_kwargs kwargs["ipysphinx_show_prompts"] = self.show_prompts kwargs["ipysphinx_input_prompt"] = self.prompt_style kwargs["ipysphinx_output_prompt"] = self.prompt_style if "author" in titlepage: kwargs["author"] = titlepage["author"] if "tagline" in titlepage: kwargs["description"] = titlepage["tagline"] if "email" in titlepage: kwargs["email"] = titlepage["email"] conf_str = make_conf(overwrite=self.override_defaults, **kwargs) conf_path = filepath.parent.joinpath("conf.py") with conf_path.open("w", encoding="utf8") as f: f.write(u(conf_str)) # create an index.rst toc_files = [filepath.name] toc_depth = 3 title = None prolog = [] epilog = [] if "author" in titlepage: prolog.append(".. sectionauthor:: {0}".format(titlepage["author"])) prolog.append("") if "title" in titlepage: title = titlepage["title"] if "tagline" in titlepage: prolog.append(titlepage["tagline"]) if "institution" in titlepage: for inst in titlepage["institution"]: epilog.append("| " + inst) epilog.append("") epilog.append('Created by IPyPublish (version {})'.format(__version__)) toc = resources.get("ipub", {}).get("toc", {}) if hasattr(toc, "get") and "depth" in toc: toc_depth = toc["depth"] index_str = make_index(toc_files, toc_depth=toc_depth, header=title, toc_numbered=self.numbered, prolog="\n".join(prolog), epilog="\n".join(epilog)) index_path = filepath.parent.joinpath("index.rst") with index_path.open("w", encoding="utf8") as f: f.write(u(index_str)) # clear any existing build build_dir = filepath.parent.joinpath('build/html') if build_dir.exists(): # >> rm -r build/html shutil.rmtree(str(build_dir)) build_dir.mkdir(parents=True) # run sphinx exec_path = find_executable('sphinx-build') args = [exec_path, "-b", "html"] if self.nitpick: args.append("-n") args.extend( [str(filepath.parent.absolute()), str(build_dir.absolute())]) self.logger.info("running: " + " ".join(args)) # this way overrides the logging # sphinx_build = find_entry_point("sphinx-build", "console_scripts", # self.logger, "sphinx") def log_process_output(pipe): for line in iter(pipe.readline, b''): self.logger.info('{}'.format(line.decode("utf-8").strip())) process = Popen(args, stdout=PIPE, stderr=STDOUT) with process.stdout: log_process_output(process.stdout) exitcode = process.wait() # 0 means success if exitcode: self.logger.warn( "sphinx-build exited with code: {}".format(exitcode)) if self.open_in_browser and not exitcode: # get entry path entry_path = filepath.parent.joinpath('build/html') entry_path = entry_path.joinpath( os.path.splitext(filepath.name)[0] + '.html') if entry_path.exists(): # 2 opens the url in a new tab webbrowser.open(entry_path.as_uri(), new=2) else: self.handle_error("can't find {0} to open".format(entry_path), IOError) return stream, filepath, resources
def _create_nbcell_nodes(directive): """Create nodes for an input or output notebook cell.""" sphinx = import_sphinx() language = "none" prompt = "" fancy_output = False execution_count = directive.options.get("execution-count") config = directive.state.document.settings.env.config if isinstance(directive, NbInput): outer_classes = ["nbinput"] if "no-output" in directive.options: outer_classes.append("nblast") inner_classes = ["input_area"] if directive.arguments: language = directive.arguments[0] prompt_template = config.ipysphinx_input_prompt if not execution_count: execution_count = " " elif isinstance(directive, NbOutput): outer_classes = ["nboutput"] if "more-to-come" not in directive.options: outer_classes.append("nblast") inner_classes = ["output_area"] # 'class' can be 'stderr' inner_classes.append(directive.options.get("class", "")) prompt_template = config.ipysphinx_output_prompt if directive.arguments and directive.arguments[0] in ["rst", "ansi"]: fancy_output = True else: raise AssertionError("directive should be NbInput or NbOutput") outer_node = docutils.nodes.container(classes=outer_classes) # add prompts if config.ipysphinx_show_prompts and execution_count: prompt = prompt_template.format(count=execution_count) prompt_node = docutils.nodes.literal_block(prompt, prompt, language="none", classes=["prompt"]) elif config.ipysphinx_show_prompts: prompt = "" prompt_node = docutils.nodes.container(classes=["prompt", "empty"]) if config.ipysphinx_show_prompts: # NB: Prompts are added manually in LaTeX output outer_node += sphinx.addnodes.only("", prompt_node, expr="html") if fancy_output: inner_node = docutils.nodes.container(classes=inner_classes) sphinx.util.nodes.nested_parse_with_titles(directive.state, directive.content, inner_node) outtype = directive.arguments[0] if outtype == "rst": outer_node += FancyOutputNode("", inner_node, prompt=prompt) elif outtype == "ansi": outer_node += inner_node else: raise AssertionError( "`.. nboutput:: type` should be 'rst' or 'ansi', " "not: {}".format(outtype)) else: text = "\n".join(directive.content.data) inner_node = docutils.nodes.literal_block(text, text, language=language, classes=inner_classes) codearea_node = CodeAreaNode("", inner_node, prompt=prompt) # create a literal text block (e.g. with the code-block directive), # that starts or ends with a blank line # (see http://stackoverflow.com/q/34050044/) for attr in "empty-lines-before", "empty-lines-after": value = directive.options.get(attr, 0) if value: codearea_node[attr] = value # add caption and label, see: if directive.options.get("caption", False): caption = directive.options.get("caption") wrapper = container_wrapper(directive, inner_node, caption, inner_classes) # add label directive.add_name(wrapper) outer_node += wrapper else: outer_node += codearea_node if isinstance(directive, NbInput) and (config.ipysphinx_input_toggle or "add-toggle" in directive.options): directive.state.document["ipysphinx_include_js"] = True outer_node += sphinx.addnodes.only( "", docutils.nodes.container(classes=["toggle-nbinput", "empty"]), expr="html", ) if isinstance(directive, NbOutput) and (config.ipysphinx_output_toggle or "add-toggle" in directive.options): directive.state.document["ipysphinx_include_js"] = True outer_node += sphinx.addnodes.only( "", docutils.nodes.container(classes=["toggle-nboutput", "empty"]), expr="html", ) return [outer_node]
def setup(app): # type: (Sphinx) -> dict """Initialize Sphinx extension. Notes ----- TODO better latex output but not really interested in this as it would be duplication of effort, and if much better todo ipynb -> tex, rather than ipynb -> rst -> tex TODO handling of svg in latex ipypublish sets latex to output svg rather than pdf, so we don't have to split output into '.. only html/latex', which is an issue its something with a label (duplication error), however, this requires sphinx.ext.imgconverter to work """ # delayed import of sphinx sphinx = import_sphinx() transforms = app.registry.get_transforms() def add_transform(transform, post=False): if transform not in transforms: if post: app.add_post_transform(transform) else: app.add_transform(transform) app.add_source_parser(NBParser) associate_single_extension(app, ".ipynb") # config for export config app.add_config_value("ipysphinx_export_config", "sphinx_ipypublish_all.ext", rebuild="env") # config for contolling conversion process # where to dump internal images, etc of the notebook app.add_config_value("ipysphinx_folder_suffix", "_nbfiles", rebuild="env") # whether to raise error if nb_name.rst already exists app.add_config_value("ipysphinx_overwrite_existing", False, rebuild="env") # additional folders containing conversion files app.add_config_value("ipysphinx_config_folders", (), rebuild="env") # config for cell prompts app.add_config_value("ipysphinx_show_prompts", False, rebuild="env") app.add_config_value("ipysphinx_input_prompt", "[{count}]:", rebuild="env") app.add_config_value("ipysphinx_output_prompt", "[{count}]:", rebuild="env") # config for cell toggling app.add_config_value("ipysphinx_input_toggle", False, rebuild="env") app.add_config_value("ipysphinx_output_toggle", False, rebuild="env") # config for html css app.add_config_value("ipysphinx_responsive_width", "540px", rebuild="html") app.add_config_value("ipysphinx_prompt_width", None, rebuild="html") # setup html style app.connect("config-inited", set_css_prompts) app.connect("html-page-context", html_add_css) # add javascript app.connect("html-page-context", html_add_javascript) # config for displaying ipywidgets app.add_config_value("ipysphinx_always_add_jsurls", False, rebuild="html") app.add_config_value("ipysphinx_require_jsurl", None, rebuild="html") app.add_config_value("ipysphinx_requirejs_options", None, rebuild="html") app.connect("env-updated", add_require_js_path) app.add_config_value("ipysphinx_widgets_jsurl", None, rebuild="html") app.add_config_value("ipysphinx_widgetsjs_options", {}, rebuild="html") app.connect("env-updated", add_ipywidgets_js_path) app.connect("env-purge-doc", discard_document_variables) # config for additions to the output rst (per file) # these strings are processed by the exporters jinja template app.add_config_value("ipysphinx_prolog", None, rebuild="env") app.add_config_value("ipysphinx_epilog", None, rebuild="env") # map additional file extensions to pre-converters # NB: jupytext is already a default for .Rmd app.add_config_value("ipysphinx_preconverters", {}, rebuild="env") app.connect("config-inited", associate_extensions) # add the main directives app.add_directive("nbinput", NbInput) app.add_directive("nboutput", NbOutput) app.add_directive("nbinfo", NbInfo) app.add_directive("nbwarning", NbWarning) app.add_directive("nbinput-toggle-all", NBInputToggle) app.add_directive("nboutput-toggle-all", NBOutputToggle) # add docutils nodes and visit/depart wraps app.add_node( CodeAreaNode, html=(lambda self, node: None, depart_codearea_html), # latex=( # lambda self, node: self.pushbody([]), # used in depart # lambda self, node: None, # ) ) app.add_node( FancyOutputNode, html=(lambda self, node: None, lambda self, node: None), # latex=( # lambda self, node: None, # lambda self, node: None, # ) ) app.add_node( AdmonitionNode, html=(visit_admonition_html, lambda self, node: self.body.append("</div>\n")), # latex=( # lambda self, node: # self.body.append( # '\n\\begin{{sphinxadmonition}}{{{class}}}' # '{{}}\\unskip'.format(node['classes'][1])), # lambda self, node: # self.body.append('\\end{sphinxadmonition}\n') # ) ) # add transformations add_transform(CreateSectionLabels) add_transform(CreateDomainObjectLabels) add_transform(RewriteLocalLinks) # Work-around until https://github.com/sphinx-doc/sphinx/pull/5504 is done: mathjax_config = app.config._raw_config.setdefault("mathjax_config", {}) mathjax_config.setdefault( "tex2jax", { "inlineMath": [["$", "$"], ["\\(", "\\)"]], "processEscapes": True, "ignoreClass": "document", "processClass": "math|output_area", }, ) # Make docutils' "code" directive (generated by markdown2rst/pandoc) # behave like Sphinx's "code-block", # see https://github.com/sphinx-doc/sphinx/issues/2155: rst.directives.register_directive("code", sphinx.directives.code.CodeBlock) return { "version": __version__, "parallel_read_safe": True, "parallel_write_safe": True, "env_version": 1, }