mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Enable automatic formatting for `sphinx/ext/inheritance_diagram.py
`
This commit is contained in:
parent
7b9a431f31
commit
c5672bf0d1
@ -415,7 +415,6 @@ exclude = [
|
||||
"sphinx/domains/python/_object.py",
|
||||
"sphinx/domains/rst.py",
|
||||
"sphinx/domains/std/__init__.py",
|
||||
"sphinx/ext/inheritance_diagram.py",
|
||||
"sphinx/ext/linkcode.py",
|
||||
"sphinx/ext/todo.py",
|
||||
"sphinx/ext/viewcode.py",
|
||||
|
@ -64,9 +64,13 @@ if TYPE_CHECKING:
|
||||
from sphinx.writers.latex import LaTeXTranslator
|
||||
from sphinx.writers.texinfo import TexinfoTranslator
|
||||
|
||||
module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names
|
||||
(\w+) \s* $ # class/final module name
|
||||
''', re.VERBOSE)
|
||||
module_sig_re = re.compile(
|
||||
r"""^
|
||||
(?:([\w.]*)\.)? # module names
|
||||
(\w+) \s* $ # class/final module name
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
|
||||
PY_BUILTINS: Final = frozenset(filter(inspect.isclass, vars(builtins).values()))
|
||||
@ -116,17 +120,21 @@ def import_classes(name: str, currmodule: str) -> Any:
|
||||
if target is None:
|
||||
raise InheritanceException(
|
||||
'Could not import class or module %r specified for '
|
||||
'inheritance diagram' % name)
|
||||
'inheritance diagram' % name
|
||||
)
|
||||
|
||||
if inspect.isclass(target):
|
||||
# If imported object is a class, just return it
|
||||
return [target]
|
||||
elif inspect.ismodule(target):
|
||||
# If imported object is a module, return classes defined on it
|
||||
return [cls for cls in target.__dict__.values()
|
||||
if inspect.isclass(cls) and cls.__module__ == target.__name__]
|
||||
raise InheritanceException('%r specified for inheritance diagram is '
|
||||
'not a class or module' % name)
|
||||
return [
|
||||
cls
|
||||
for cls in target.__dict__.values()
|
||||
if inspect.isclass(cls) and cls.__module__ == target.__name__
|
||||
]
|
||||
msg = f'{name!r} specified for inheritance diagram is not a class or module'
|
||||
raise InheritanceException(msg)
|
||||
|
||||
|
||||
class InheritanceException(Exception):
|
||||
@ -140,10 +148,16 @@ class InheritanceGraph:
|
||||
graphviz dot graph from them.
|
||||
"""
|
||||
|
||||
def __init__(self, class_names: list[str], currmodule: str, show_builtins: bool = False,
|
||||
private_bases: bool = False, parts: int = 0,
|
||||
aliases: dict[str, str] | None = None, top_classes: Sequence[Any] = (),
|
||||
) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
class_names: list[str],
|
||||
currmodule: str,
|
||||
show_builtins: bool = False,
|
||||
private_bases: bool = False,
|
||||
parts: int = 0,
|
||||
aliases: dict[str, str] | None = None,
|
||||
top_classes: Sequence[Any] = (),
|
||||
) -> None:
|
||||
"""*class_names* is a list of child classes to show bases from.
|
||||
|
||||
If *show_builtins* is True, then Python builtins will be shown
|
||||
@ -151,8 +165,9 @@ class InheritanceGraph:
|
||||
"""
|
||||
self.class_names = class_names
|
||||
classes = self._import_classes(class_names, currmodule)
|
||||
self.class_info = self._class_info(classes, show_builtins,
|
||||
private_bases, parts, aliases, top_classes)
|
||||
self.class_info = self._class_info(
|
||||
classes, show_builtins, private_bases, parts, aliases, top_classes
|
||||
)
|
||||
if not self.class_info:
|
||||
msg = 'No classes found for inheritance diagram'
|
||||
raise InheritanceException(msg)
|
||||
@ -164,9 +179,15 @@ class InheritanceGraph:
|
||||
classes.extend(import_classes(name, currmodule))
|
||||
return classes
|
||||
|
||||
def _class_info(self, classes: list[Any], show_builtins: bool, private_bases: bool,
|
||||
parts: int, aliases: dict[str, str] | None, top_classes: Sequence[Any],
|
||||
) -> list[tuple[str, str, Sequence[str], str | None]]:
|
||||
def _class_info(
|
||||
self,
|
||||
classes: list[Any],
|
||||
show_builtins: bool,
|
||||
private_bases: bool,
|
||||
parts: int,
|
||||
aliases: dict[str, str] | None,
|
||||
top_classes: Sequence[Any],
|
||||
) -> list[tuple[str, str, Sequence[str], str | None]]:
|
||||
"""Return name and bases for all classes that are ancestors of
|
||||
*classes*.
|
||||
|
||||
@ -197,7 +218,7 @@ class InheritanceGraph:
|
||||
tooltip = None
|
||||
try:
|
||||
if cls.__doc__:
|
||||
doc = cls.__doc__.strip().split("\n")[0]
|
||||
doc = cls.__doc__.strip().split('\n')[0]
|
||||
if doc:
|
||||
tooltip = '"%s"' % doc.replace('"', '\\"')
|
||||
except Exception: # might raise AttributeError for strange classes
|
||||
@ -223,12 +244,11 @@ class InheritanceGraph:
|
||||
|
||||
return [
|
||||
(cls_name, fullname, tuple(bases), tooltip)
|
||||
for (cls_name, fullname, bases, tooltip)
|
||||
in all_classes.values()
|
||||
for (cls_name, fullname, bases, tooltip) in all_classes.values()
|
||||
]
|
||||
|
||||
def class_name(
|
||||
self, cls: Any, parts: int = 0, aliases: dict[str, str] | None = None,
|
||||
self, cls: Any, parts: int = 0, aliases: dict[str, str] | None = None
|
||||
) -> str:
|
||||
"""Given a class object, return a fully-qualified name.
|
||||
|
||||
@ -263,8 +283,7 @@ class InheritanceGraph:
|
||||
'shape': 'box',
|
||||
'fontsize': 10,
|
||||
'height': 0.25,
|
||||
'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, '
|
||||
'Arial, Helvetica, sans"',
|
||||
'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans"',
|
||||
'style': '"setlinewidth(0.5),filled"',
|
||||
'fillcolor': 'white',
|
||||
}
|
||||
@ -279,12 +298,15 @@ class InheritanceGraph:
|
||||
def _format_graph_attrs(self, attrs: dict[str, Any]) -> str:
|
||||
return ''.join(f'{k}={v};\n' for k, v in sorted(attrs.items()))
|
||||
|
||||
def generate_dot(self, name: str, urls: dict[str, str] | None = None,
|
||||
env: BuildEnvironment | None = None,
|
||||
graph_attrs: dict | None = None,
|
||||
node_attrs: dict | None = None,
|
||||
edge_attrs: dict | None = None,
|
||||
) -> str:
|
||||
def generate_dot(
|
||||
self,
|
||||
name: str,
|
||||
urls: dict[str, str] | None = None,
|
||||
env: BuildEnvironment | None = None,
|
||||
graph_attrs: dict | None = None,
|
||||
node_attrs: dict | None = None,
|
||||
edge_attrs: dict | None = None,
|
||||
) -> str:
|
||||
"""Generate a graphviz dot graph from the classes that were passed in
|
||||
to __init__.
|
||||
|
||||
@ -320,19 +342,21 @@ class InheritanceGraph:
|
||||
# Write the node
|
||||
this_node_attrs = n_attrs.copy()
|
||||
if fullname in urls:
|
||||
this_node_attrs["URL"] = f'"{urls[fullname]}"'
|
||||
this_node_attrs["target"] = '"_top"'
|
||||
this_node_attrs['URL'] = f'"{urls[fullname]}"'
|
||||
this_node_attrs['target'] = '"_top"'
|
||||
if tooltip:
|
||||
this_node_attrs["tooltip"] = tooltip
|
||||
res.append(f' "{cls_name}" [{self._format_node_attrs(this_node_attrs)}];\n')
|
||||
this_node_attrs['tooltip'] = tooltip
|
||||
res.append(
|
||||
f' "{cls_name}" [{self._format_node_attrs(this_node_attrs)}];\n'
|
||||
)
|
||||
|
||||
# Write the edges
|
||||
res.extend(
|
||||
f' "{base_name}" -> "{cls_name}" [{self._format_node_attrs(e_attrs)}];\n'
|
||||
for base_name in bases
|
||||
)
|
||||
res.append("}\n")
|
||||
return "".join(res)
|
||||
res.append('}\n')
|
||||
return ''.join(res)
|
||||
|
||||
|
||||
class inheritance_diagram(graphviz):
|
||||
@ -376,11 +400,13 @@ class InheritanceDiagram(SphinxDirective):
|
||||
# Create a graph starting with the list of classes
|
||||
try:
|
||||
graph = InheritanceGraph(
|
||||
class_names, self.env.ref_context.get('py:module'), # type: ignore[arg-type]
|
||||
class_names,
|
||||
self.env.ref_context.get('py:module'), # type: ignore[arg-type]
|
||||
parts=node['parts'],
|
||||
private_bases='private-bases' in self.options,
|
||||
aliases=self.config.inheritance_alias,
|
||||
top_classes=node['top-classes'])
|
||||
top_classes=node['top-classes'],
|
||||
)
|
||||
except InheritanceException as err:
|
||||
return [node.document.reporter.warning(err, line=self.lineno)]
|
||||
|
||||
@ -390,7 +416,8 @@ class InheritanceDiagram(SphinxDirective):
|
||||
# removed from the doctree after we're done with them.
|
||||
for name in graph.get_all_class_names():
|
||||
refnodes, x = class_role( # type: ignore[misc]
|
||||
'class', ':class:`%s`' % name, name, 0, self.state.inliner)
|
||||
'class', f':class:`{name}`', name, 0, self.state.inliner
|
||||
)
|
||||
node.extend(refnodes)
|
||||
# Store the graph object so we can use it to generate the
|
||||
# dot file later
|
||||
@ -410,7 +437,9 @@ def get_graph_hash(node: inheritance_diagram) -> str:
|
||||
return hashlib.md5(encoded, usedforsecurity=False).hexdigest()[-10:]
|
||||
|
||||
|
||||
def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diagram) -> None:
|
||||
def html_visit_inheritance_diagram(
|
||||
self: HTML5Translator, node: inheritance_diagram
|
||||
) -> None:
|
||||
"""
|
||||
Output the graph for HTML. This will insert a PNG with clickable
|
||||
image map.
|
||||
@ -422,7 +451,9 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag
|
||||
|
||||
# Create a mapping from fully-qualified class names to URLs.
|
||||
graphviz_output_format = self.builder.env.config.graphviz_output_format.upper()
|
||||
current_filename = os.path.basename(self.builder.current_docname + self.builder.out_suffix)
|
||||
current_filename = os.path.basename(
|
||||
self.builder.current_docname + self.builder.out_suffix
|
||||
)
|
||||
urls = {}
|
||||
pending_xrefs = cast('Iterable[addnodes.pending_xref]', node)
|
||||
for child in pending_xrefs:
|
||||
@ -441,12 +472,21 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag
|
||||
urls[child['reftitle']] = '#' + child.get('refid')
|
||||
|
||||
dotcode = graph.generate_dot(name, urls, env=self.builder.env)
|
||||
render_dot_html(self, node, dotcode, {}, 'inheritance', 'inheritance',
|
||||
alt='Inheritance diagram of ' + node['content'])
|
||||
render_dot_html(
|
||||
self,
|
||||
node,
|
||||
dotcode,
|
||||
{},
|
||||
'inheritance',
|
||||
'inheritance',
|
||||
alt='Inheritance diagram of ' + node['content'],
|
||||
)
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def latex_visit_inheritance_diagram(self: LaTeXTranslator, node: inheritance_diagram) -> None:
|
||||
def latex_visit_inheritance_diagram(
|
||||
self: LaTeXTranslator, node: inheritance_diagram
|
||||
) -> None:
|
||||
"""
|
||||
Output the graph for LaTeX. This will insert a PDF.
|
||||
"""
|
||||
@ -455,14 +495,17 @@ def latex_visit_inheritance_diagram(self: LaTeXTranslator, node: inheritance_dia
|
||||
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"'})
|
||||
dotcode = graph.generate_dot(
|
||||
name, env=self.builder.env, graph_attrs={'size': '"6.0,6.0"'}
|
||||
)
|
||||
render_dot_latex(self, node, dotcode, {}, 'inheritance')
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def texinfo_visit_inheritance_diagram(self: TexinfoTranslator, node: inheritance_diagram,
|
||||
) -> None:
|
||||
def texinfo_visit_inheritance_diagram(
|
||||
self: TexinfoTranslator,
|
||||
node: inheritance_diagram,
|
||||
) -> None:
|
||||
"""
|
||||
Output the graph for Texinfo. This will insert a PNG.
|
||||
"""
|
||||
@ -471,8 +514,9 @@ def texinfo_visit_inheritance_diagram(self: TexinfoTranslator, node: inheritance
|
||||
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"'})
|
||||
dotcode = graph.generate_dot(
|
||||
name, env=self.builder.env, graph_attrs={'size': '"6.0,6.0"'}
|
||||
)
|
||||
render_dot_texinfo(self, node, dotcode, {}, 'inheritance')
|
||||
raise nodes.SkipNode
|
||||
|
||||
@ -489,7 +533,8 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
html=(html_visit_inheritance_diagram, None),
|
||||
text=(skip, None),
|
||||
man=(skip, None),
|
||||
texinfo=(texinfo_visit_inheritance_diagram, None))
|
||||
texinfo=(texinfo_visit_inheritance_diagram, None),
|
||||
)
|
||||
app.add_directive('inheritance-diagram', InheritanceDiagram)
|
||||
app.add_config_value('inheritance_graph_attrs', {}, '')
|
||||
app.add_config_value('inheritance_node_attrs', {}, '')
|
||||
|
Loading…
Reference in New Issue
Block a user