Add repo related concepts to documentation (#1004)

* add repo, channel, repodata, subdir, tarball concepts
refactor detailed ops to use mermaid js
remove install svg

* fix code quality
add flake8 exception for mermaid, incompatible check vs isort
This commit is contained in:
Adrien Delsalle 2021-06-15 13:06:35 +02:00 committed by GitHub
parent 72a3d4efeb
commit 98e8b611a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 818 additions and 13 deletions

View File

@ -1,4 +1,4 @@
[flake8]
max-line-length=88
extend-ignore=E203,D104,D100,I004
exclude=test/*
exclude=test/*,docs/source/tools/*

View File

@ -20,11 +20,29 @@ The ``install`` operation is using a ``package specification`` to add/install ad
The workflow for that operation is:
- computing :ref:`configuration<configuration>`
- fetching/downloading packages index from repositor(y)(ies)
- solving
- fetching/downloading packages tarballs
- extracting packages
- :ref:`linking<linking>` packages
.. mermaid::
:align: center
.. image:: install.svg
%%{init: {'themeVariables':{'edgeLabelBackground':'white'}}}%%
graph TD
style start fill:#00000000,stroke:#00000000,color:#00000000;
config[Compute configuration fa:fa-link]
fetch_index[Fetch repositories index fa:fa-unlink]
solve[Solving fa:fa-unlink]
fetch_pkgs[Fetch packages fa:fa-unlink]
extract[Extract tarballs fa:fa-unlink]
link[Link fa:fa-link]
stop([Stop])
start-->|User spec|config;
config-->fetch_index;
fetch_index-->solve;
solve-->fetch_pkgs;
fetch_pkgs-->extract;
extract-->link;
link-->stop;
click config href "../user_guide/configuration.html"
click link href "./more_concepts.html#linking"
See also: :ref:`package tarball<tarball>`

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -11,6 +11,72 @@ Overview
While not necessary to understand the basic usage, those ``advanced concepts`` are fundamental to understand Mamba in details.
.. _repo:
Packages repository
-------------------
| A packages repository, also called ``repo``, is a generic way to describe a storage location for software packages.
In the Mamba's context, it may points to a packages server, a :ref:`channel<channel>` or a :ref:`subdir<subdir>`.
.. _channel:
Channel
-------
| A ``channel`` is an independant and isolated :ref:`repo<repo>` structure that is used to classify and administrate more easily a packages server.
.. note::
A packages server may host one or multiple ``channels``.
.. _subdir:
Subdir
------
| A ``subdir`` is a :ref:`channel<channel>` subdirectory specific to a given operating system/platform pair.
Mamba is a general purpose, langage agnostic package manager. The ``subdir`` structure is a convenient way to provide and access packages depending on the targeted os and platform.
Typically ``linux-64``, ``osx-arm64`` or ``win-64`` but not limited to those ones.
A ``subdir`` provides the packages tarballs alongside a :ref:`packages index<repodata>` including additional metadata.
.. note::
In most cases, both ``noarch`` and ``<os>-<platform>`` subdirs are used for an operation requiring data from the :ref:`repo<repo>`
.. _repodata:
Packages index
--------------
| A repository package index is a file containing metadata about all the packages tarballs served by a :ref:`repo<repo>`.
.. note::
Those metadata include license, file size, checksums, etc.
In Mamba, it is more often called a ``repodata`` in reference to the index filename ``repodata.json``.
A ``repodata`` is specific to a :ref:`channel subdirectory<subdir>`.
.. _tarball:
Package tarball
---------------
| A tarball is a single archive file, compressed or not, that expands to multiples files/directories. It is typically a ``zip`` file or so.
In the case of Mamba, 2 ``conda`` formats are used as package tarball:
- ``tar.bz2`` is the historical formats: a ``tar`` file/ball that has been compressed using ``bzip2`` algorithm
- ``conda`` more recent format that allows faster access to packages metadata
.. _linking:
Linking

View File

@ -11,7 +11,9 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
import sys
from pathlib import Path
# sys.path.insert(0, os.path.abspath('.'))
@ -27,10 +29,13 @@ release = "0.5.2"
# -- General configuration ---------------------------------------------------
# Load local extensions (e.g. mermaid)
sys.path.insert(0, str(Path.cwd().resolve() / "tools"))
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ["myst_parser"]
extensions = ["mermaid", "mermaid_inheritance", "myst_parser"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

View File

@ -0,0 +1,3 @@
.mermaid svg {
max-width: 800px;
}

View File

@ -0,0 +1,412 @@
"""
sphinx-mermaid
~~~~~~~~~~~~~~~
https://github.com/mgaitan/sphinxcontrib-mermaid
Modified for the purpose of CoSApp by the CoSApp team
https://gitlab.com/cosapp/cosapp
Allow mermaid diagramas to be included in Sphinx-generated
documents inline.
:copyright: Copyright 2016 by Martín Gaitán and others, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import codecs
import os
import posixpath
from hashlib import sha1
from subprocess import PIPE, Popen
from tempfile import _get_default_tempdir
import sphinx
from docutils import nodes
from docutils.parsers.rst import Directive, directives
from docutils.statemachine import ViewList
from six import text_type
from sphinx.application import Sphinx
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.util import logging
from sphinx.util.fileutil import copy_asset
from sphinx.util.i18n import search_image_for_language
from sphinx.util.osutil import ENOENT, ensuredir
logger = logging.getLogger(__name__)
class MermaidError(SphinxError):
category = "Mermaid error"
class mermaid(nodes.General, nodes.Inline, nodes.Element):
pass
def figure_wrapper(directive, node, caption):
figure_node = nodes.figure("", node)
if "align" in node:
figure_node["align"] = node.attributes.pop("align")
parsed = nodes.Element()
directive.state.nested_parse(
ViewList([caption], source=""), directive.content_offset, parsed
)
caption_node = nodes.caption(parsed[0].rawsource, "", *parsed[0].children)
caption_node.source = parsed[0].source
caption_node.line = parsed[0].line
figure_node += caption_node
return figure_node
def align_spec(argument):
return directives.choice(argument, ("left", "center", "right"))
class Mermaid(Directive):
"""
Directive to insert arbitrary Mermaid markup.
"""
has_content = True
required_arguments = 0
optional_arguments = 1
final_argument_whitespace = False
option_spec = {
"alt": directives.unchanged,
"align": align_spec,
"caption": directives.unchanged,
}
def get_mm_code(self):
if self.arguments:
# try to load mermaid code from an external file
document = self.state.document
if self.content:
return [
document.reporter.warning(
"Mermaid directive cannot have both content and "
"a filename argument",
line=self.lineno,
)
]
env = self.state.document.settings.env
argument = search_image_for_language(self.arguments[0], env)
rel_filename, filename = env.relfn2path(argument)
env.note_dependency(rel_filename)
try:
with codecs.open(filename, "r", "utf-8") as fp:
mmcode = fp.read()
except (IOError, OSError): # noqa
return [
document.reporter.warning(
"External Mermaid file %r not found or reading "
"it failed" % filename,
line=self.lineno,
)
]
else:
# inline mermaid code
mmcode = "\n".join(self.content)
if not mmcode.strip():
return [
self.state_machine.reporter.warning(
'Ignoring "mermaid" directive without content.',
line=self.lineno,
)
]
return mmcode
def run(self):
node = mermaid()
node["code"] = self.get_mm_code()
node["options"] = {}
if "alt" in self.options:
node["alt"] = self.options["alt"]
if "align" in self.options:
node["align"] = self.options["align"]
if "inline" in self.options:
node["inline"] = True
caption = self.options.get("caption")
if caption:
node = figure_wrapper(self, node, caption)
return [node]
def render_mm(self, code, options, fmt, prefix="mermaid"):
"""Render mermaid code into a PNG or PDF output file."""
if fmt == "raw":
fmt = "png"
mermaid_cmd = self.builder.config.mermaid_cmd
hashkey = (
code + str(options) + str(self.builder.config.mermaid_sequence_config)
).encode("utf-8")
basename = "%s-%s" % (prefix, sha1(hashkey).hexdigest())
fname = "%s.%s" % (basename, fmt)
relfn = posixpath.join(self.builder.imgpath, fname)
outdir = os.path.join(self.builder.outdir, self.builder.imagedir)
outfn = os.path.join(outdir, fname)
tmpfn = os.path.join(_get_default_tempdir(), basename)
if os.path.isfile(outfn):
return relfn, outfn
ensuredir(os.path.dirname(outfn))
# mermaid expects UTF-8 by default
if isinstance(code, text_type):
code = code.encode("utf-8")
with open(tmpfn, "wb") as t:
t.write(code)
mm_args = [mermaid_cmd, "-i", tmpfn, "-o", outfn]
mm_args.extend(self.builder.config.mermaid_params)
if self.builder.config.mermaid_sequence_config:
mm_args.extend("--configFile", self.builder.config.mermaid_sequence_config)
try:
p = Popen(mm_args, stdout=PIPE, stdin=PIPE, stderr=PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning(
"command %r cannot be run (needed for mermaid "
"output), check the mermaid_cmd setting" % mermaid_cmd
)
return None, None
stdout, stderr = p.communicate(code)
if self.builder.config.mermaid_verbose:
logger.info(stdout)
if p.returncode != 0:
raise MermaidError(
"Mermaid exited with error:\n[stderr]\n%s\n"
"[stdout]\n%s" % (stderr, stdout)
)
if not os.path.isfile(outfn):
raise MermaidError(
"Mermaid did not produce an output file:\n[stderr]\n%s\n"
"[stdout]\n%s" % (stderr, stdout)
)
return relfn, outfn
def _render_mm_html_raw(
self, node, code, options, prefix="mermaid", imgcls=None, alt=None
):
if "align" in node:
tag_template = """<div align="{align}" class="mermaid align-{align}">
{code}
</div>
"""
else:
tag_template = """<div class="mermaid">
{code}
</div>"""
self.body.append(
tag_template.format(align=node.get("align"), code=self.encode(code))
)
raise nodes.SkipNode
def render_mm_html(self, node, code, options, prefix="mermaid", imgcls=None, alt=None):
fmt = self.builder.config.mermaid_output_format
if fmt == "raw":
return _render_mm_html_raw(
self, node, code, options, prefix="mermaid", imgcls=None, alt=None
)
try:
if fmt not in ("png", "svg"):
raise MermaidError(
"mermaid_output_format must be one of 'raw', 'png', "
"'svg', but is %r" % fmt
)
fname, outfn = render_mm(self, code, options, fmt, prefix)
except MermaidError as exc:
logger.warning("mermaid code %r: " % code + str(exc))
raise nodes.SkipNode
if fname is None:
self.body.append(self.encode(code))
else:
if alt is None:
alt = node.get("alt", self.encode(code).strip())
imgcss = imgcls and 'class="%s"' % imgcls or ""
if fmt == "svg":
svgtag = """<object data="%s" type="image/svg+xml">
<p class="warning">%s</p></object>\n""" % (
fname,
alt,
)
self.body.append(svgtag)
else:
if "align" in node:
self.body.append(
'<div align="%s" class="align-%s">' % (node["align"], node["align"])
)
self.body.append('<img src="%s" alt="%s" %s/>\n' % (fname, alt, imgcss))
if "align" in node:
self.body.append("</div>\n")
raise nodes.SkipNode
def html_visit_mermaid(self, node):
render_mm_html(self, node, node["code"], node["options"])
def render_mm_latex(self, node, code, options, prefix="mermaid"):
try:
fname, outfn = render_mm(self, code, options, "pdf", prefix)
except MermaidError as exc:
logger.warning("mm code %r: " % code + str(exc))
raise nodes.SkipNode
if self.builder.config.mermaid_pdfcrop != "":
mm_args = [self.builder.config.mermaid_pdfcrop, outfn]
try:
p = Popen(mm_args, stdout=PIPE, stdin=PIPE, stderr=PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning(
"command %r cannot be run (needed to crop pdf), \
check the mermaid_cmd setting"
% self.builder.config.mermaid_pdfcrop
)
return None, None
stdout, stderr = p.communicate()
if self.builder.config.mermaid_verbose:
logger.info(stdout)
if p.returncode != 0:
raise MermaidError(
"PdfCrop exited with error:\n[stderr]\n%s\n"
"[stdout]\n%s" % (stderr, stdout)
)
if not os.path.isfile(outfn):
raise MermaidError(
"PdfCrop did not produce an output file:\n[stderr]\n%s\n"
"[stdout]\n%s" % (stderr, stdout)
)
fname = "{filename[0]}-crop{filename[1]}".format(
filename=os.path.splitext(fname)
)
is_inline = self.is_inline(node)
if is_inline:
para_separator = ""
else:
para_separator = "\n"
if fname is not None:
post = None
if not is_inline and "align" in node:
if node["align"] == "left":
self.body.append("{")
post = "\\hspace*{\\fill}}"
elif node["align"] == "right":
self.body.append("{\\hspace*{\\fill}")
post = "}"
self.body.append(
"%s\\sphinxincludegraphics{%s}%s" % (para_separator, fname, para_separator)
)
if post:
self.body.append(post)
raise nodes.SkipNode
def latex_visit_mermaid(self, node):
render_mm_latex(self, node, node["code"], node["options"])
def render_mm_texinfo(self, node, code, options, prefix="mermaid"):
try:
fname, outfn = render_mm(self, code, options, "png", prefix)
except MermaidError as exc:
logger.warning("mm code %r: " % code + str(exc))
raise nodes.SkipNode
if fname is not None:
self.body.append("@image{%s,,,[mermaid],png}\n" % fname[:-4])
raise nodes.SkipNode
def texinfo_visit_mermaid(self, node):
render_mm_texinfo(self, node, node["code"], node["options"])
def text_visit_mermaid(self, node):
if "alt" in node.attributes:
self.add_text(_("[graph: %s]") % node["alt"])
else:
self.add_text(_("[graph]"))
raise nodes.SkipNode
def man_visit_mermaid(self, node):
if "alt" in node.attributes:
self.body.append(_("[graph: %s]") % node["alt"])
else:
self.body.append(_("[graph]"))
raise nodes.SkipNode
def config_inited(app, config):
version = config.mermaid_version
mermaid_js_url = "https://unpkg.com/mermaid@{}/dist/mermaid.min.js".format(version)
app.add_js_file(mermaid_js_url)
app.add_js_file(
None,
body='mermaid.initialize({startOnLoad:true, theme:"neutral", securityLevel="loose", \
sequenceConfig: {mirrorActors: false}});',
)
app.add_css_file("mermaid.css")
def on_build_finished(app: Sphinx, exc: Exception) -> None:
if exc is None:
src = os.path.join(os.path.dirname(__file__), "mermaid.css")
dst = os.path.join(app.outdir, "_static")
copy_asset(src, dst)
def setup(app):
app.add_node(
mermaid,
html=(html_visit_mermaid, None),
latex=(latex_visit_mermaid, None),
texinfo=(texinfo_visit_mermaid, None),
text=(text_visit_mermaid, None),
man=(man_visit_mermaid, None),
)
app.add_directive("mermaid", Mermaid)
#
app.add_config_value("mermaid_cmd", "mmdc", "html")
app.add_config_value("mermaid_pdfcrop", "", "html")
app.add_config_value("mermaid_output_format", "raw", "html")
app.add_config_value("mermaid_params", list(), "html")
app.add_config_value("mermaid_verbose", False, "html")
app.add_config_value("mermaid_sequence_config", False, "html")
app.add_config_value("mermaid_version", "8.10.2", "html")
app.connect("config-inited", config_inited)
app.connect("build-finished", on_build_finished)
return {"version": sphinx.__display_version__, "parallel_read_safe": True}

View File

@ -0,0 +1,304 @@
r"""
mermaid_inheritance
~~~~~~~~~~~~~~~~~~~
Modified by the CoSApp team from sphinx.ext.inheritance_diagram
https://gitlab.com/cosapp/cosapp
Defines a docutils directive for inserting inheritance diagrams.
Provide the directive with one or more classes or modules (separated
by whitespace). For modules, all of the classes in that module will
be used.
Example::
Given the following classes:
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
class E(B): pass
.. inheritance-diagram: D E
Produces a graph like the following:
A
/ \
B C
/ \ /
E D
The graph is inserted as a PNG+image map into HTML and a PDF in
LaTeX.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, Iterable, List, cast
import sphinx
from docutils import nodes
from docutils.nodes import Node
from docutils.parsers.rst import directives
from mermaid import render_mm_html, render_mm_latex, render_mm_texinfo
from sphinx import addnodes
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment
from sphinx.ext.inheritance_diagram import (
InheritanceDiagram,
InheritanceException,
InheritanceGraph,
figure_wrapper,
get_graph_hash,
inheritance_diagram,
skip,
)
from sphinx.writers.html import HTMLTranslator
from sphinx.writers.latex import LaTeXTranslator
from sphinx.writers.texinfo import TexinfoTranslator
class MermaidGraph(InheritanceGraph):
"""
Given a list of classes, determines the set of classes that they inherit
from all the way to the root "object", and then is able to generate a
mermaid graph from them.
"""
# These are the default attrs
default_graph_attrs = {}
# 'rankdir': 'LR',
# 'size': '"8.0, 12.0"',
# 'bgcolor': 'transparent',
# }
default_node_attrs = {}
# 'shape': 'box',
# 'fontsize': 10,
# 'height': 0.25,
# 'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, '
# 'Arial, Helvetica, sans"',
# 'style': '"setlinewidth(0.5),filled"',
# 'fillcolor': 'white',
# }
default_edge_attrs = {}
# 'arrowsize': 0.5,
# 'style': '"setlinewidth(0.5)"',
# }
def _format_node_attrs(self, attrs: Dict) -> str:
# return ','.join(['%s=%s' % x for x in sorted(attrs.items())])
return ""
def _format_graph_attrs(self, attrs: Dict) -> str:
# return ''.join(['%s=%s;\n' % x for x in sorted(attrs.items())])
return ""
def generate_dot(
self,
name: str,
urls: Dict = {}, # noqa
env: BuildEnvironment = None,
graph_attrs: Dict = {}, # noqa
node_attrs: Dict = {}, # noqa
edge_attrs: Dict = {}, # noqa
) -> str:
"""Generate a mermaid graph from the classes that were passed in
to __init__.
*name* is the name of the graph.
*urls* is a dictionary mapping class names to HTTP URLs.
*graph_attrs*, *node_attrs*, *edge_attrs* are dictionaries containing
key/value pairs to pass on as graphviz properties.
"""
# g_attrs = self.default_graph_attrs.copy()
# n_attrs = self.default_node_attrs.copy()
# e_attrs = self.default_edge_attrs.copy()
# g_attrs.update(graph_attrs)
# n_attrs.update(node_attrs)
# e_attrs.update(edge_attrs)
# if env:
# g_attrs.update(env.config.inheritance_graph_attrs)
# n_attrs.update(env.config.inheritance_node_attrs)
# e_attrs.update(env.config.inheritance_edge_attrs)
res = [] # type: List[str]
res.append("classDiagram\n")
for name, fullname, bases, tooltip in sorted(self.class_info):
# Write the node
res.append(" class {!s}\n".format(name))
if fullname in urls:
res.append(
' link {!s} "./{!s}" {!s}\n'.format(
name, urls[fullname], tooltip or '"{}"'.format(name)
)
)
# Write the edges
for base_name in bases:
res.append(" {!s} <|-- {!s}\n".format(base_name, name))
return "".join(res)
class mermaid_inheritance(inheritance_diagram):
"""
A docutils node to use as a placeholder for the inheritance diagram.
"""
pass
class MermaidDiagram(InheritanceDiagram):
"""
Run when the mermaid_inheritance directive is first encountered.
"""
has_content = False
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {
"parts": int,
"private-bases": directives.flag,
"caption": directives.unchanged,
"top-classes": directives.unchanged_required,
}
def run(self) -> List[Node]:
node = mermaid_inheritance()
node.document = self.state.document
class_names = self.arguments[0].split()
class_role = self.env.get_domain("py").role("class")
# Store the original content for use as a hash
node["parts"] = self.options.get("parts", 0)
node["content"] = ", ".join(class_names)
node["top-classes"] = []
for cls in self.options.get("top-classes", "").split(","):
cls = cls.strip()
if cls:
node["top-classes"].append(cls)
# Create a graph starting with the list of classes
try:
graph = MermaidGraph(
class_names,
self.env.ref_context.get("py:module"),
parts=node["parts"],
private_bases="private-bases" in self.options,
aliases=self.config.inheritance_alias,
top_classes=node["top-classes"],
)
except InheritanceException as err:
return [node.document.reporter.warning(err, line=self.lineno)]
# Create xref nodes for each target of the graph's image map and
# add them to the doc tree so that Sphinx can resolve the
# references to real URLs later. These nodes will eventually be
# removed from the doctree after we're done with them.
for name in graph.get_all_class_names():
refnodes, x = class_role( # type: ignore
"class", ":class:`%s`" % name, name, 0, self.state
) # type: ignore
node.extend(refnodes)
# Store the graph object so we can use it to generate the
# dot file later
node["graph"] = graph
if "caption" not in self.options:
self.add_name(node)
return [node]
else:
figure = figure_wrapper(self, node, self.options["caption"])
self.add_name(figure)
return [figure]
def html_visit_mermaid_inheritance(
self: HTMLTranslator, node: inheritance_diagram
) -> None:
"""
Output the graph for HTML. This will insert a PNG with clickable
image map.
"""
graph = node["graph"]
graph_hash = get_graph_hash(node)
name = "inheritance%s" % graph_hash
# Create a mapping from fully-qualified class names to URLs.
mermaid_output_format = self.builder.env.config.mermaid_output_format.upper()
current_filename = self.builder.current_docname + self.builder.out_suffix
urls = {}
pending_xrefs = cast(Iterable[addnodes.pending_xref], node)
for child in pending_xrefs:
if child.get("refuri") is not None:
if mermaid_output_format == "SVG":
urls[child["reftitle"]] = "../" + child.get("refuri")
else:
urls[child["reftitle"]] = child.get("refuri")
elif child.get("refid") is not None:
if mermaid_output_format == "SVG":
urls[child["reftitle"]] = (
"../" + current_filename + "#" + child.get("refid")
)
else:
urls[child["reftitle"]] = "#" + child.get("refid")
dotcode = graph.generate_dot(name, urls, env=self.builder.env)
render_mm_html(
self,
node,
dotcode,
{},
"inheritance",
"inheritance",
alt="Inheritance diagram of " + node["content"],
)
raise nodes.SkipNode
def latex_visit_mermaid_inheritance(
self: LaTeXTranslator, node: inheritance_diagram
) -> None:
"""
Output the graph for LaTeX. This will insert a PDF.
"""
graph = node["graph"]
graph_hash = get_graph_hash(node)
name = "inheritance%s" % graph_hash
dotcode = graph.generate_dot(name, env=self.builder.env,)
# graph_attrs={'size': '"6.0,6.0"'})
render_mm_latex(self, node, dotcode, {}, "inheritance")
raise nodes.SkipNode
def texinfo_visit_mermaid_inheritance(
self: TexinfoTranslator, node: inheritance_diagram
) -> None:
"""
Output the graph for Texinfo. This will insert a PNG.
"""
graph = node["graph"]
graph_hash = get_graph_hash(node)
name = "inheritance%s" % graph_hash
dotcode = graph.generate_dot(name, env=self.builder.env,)
# graph_attrs={'size': '"6.0,6.0"'})
render_mm_texinfo(self, node, dotcode, {}, "inheritance")
raise nodes.SkipNode
def setup(app: Sphinx) -> Dict[str, Any]:
app.setup_extension("mermaid")
app.add_node(
mermaid_inheritance,
latex=(latex_visit_mermaid_inheritance, None),
html=(html_visit_mermaid_inheritance, None),
text=(skip, None),
man=(skip, None),
texinfo=(texinfo_visit_mermaid_inheritance, None),
)
app.add_directive("mermaid-inheritance", MermaidDiagram)
# app.add_config_value('mermaid_inheritance_graph_attrs', {}, False)
# app.add_config_value('mermaid_inheritance_node_attrs', {}, False)
# app.add_config_value('mermaid_inheritance_edge_attrs', {}, False)
app.add_config_value("inheritance_alias", {}, False)
return {"version": sphinx.__display_version__, "parallel_read_safe": True}