From c5672bf0d1a845beeb81cdcf52a6c94928ce72a9 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 25 Dec 2024 19:33:37 +0000 Subject: [PATCH] Enable automatic formatting for ``sphinx/ext/inheritance_diagram.py`` --- .ruff.toml | 1 - sphinx/ext/inheritance_diagram.py | 145 +++++++++++++++++++----------- 2 files changed, 95 insertions(+), 51 deletions(-) diff --git a/.ruff.toml b/.ruff.toml index cadfb76bd99..233651a4482 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -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", diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index b3ebd8f1c84..c4381b7aff1 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -64,9 +64,13 @@ class E(B): pass 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 @@ def __init__(self, class_names: list[str], currmodule: str, show_builtins: bool """ 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 @@ def _import_classes(self, class_names: list[str], currmodule: str) -> list[Any]: 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 @@ def recurse(cls: Any) -> None: 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 @@ def recurse(cls: Any) -> None: 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 @@ def get_all_class_names(self) -> list[str]: '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 @@ def _format_node_attrs(self, attrs: dict[str, Any]) -> str: 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 @@ def generate_dot(self, name: str, urls: dict[str, str] | None = None, # 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 @@ def run(self) -> list[Node]: # 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 @@ def run(self) -> list[Node]: # 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', {}, '')