From 4199c0cf42761a597440bb2e43914499adeccb25 Mon Sep 17 00:00:00 2001 From: Denis Rouzaud Date: Tue, 13 Aug 2024 11:18:12 +0200 Subject: [PATCH] run pre-commit (#158) --- .pre-commit-config.yaml | 8 +- autoautosummary.py | 51 +++++--- conf.in.py | 16 ++- inheritance_diagram.py | 271 +++++++++++++++++++++++----------------- process_links.py | 5 +- scripts/make_api_rst.py | 40 +++--- 6 files changed, 228 insertions(+), 163 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6edd3381e9b4..e2b3c25c40be 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: # Fix end of files - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace exclude: .*\.qgs @@ -32,21 +32,21 @@ repos: # Black formatting - repo: https://github.com/psf/black - rev: "24.3.0" + rev: "24.8.0" hooks: - id: black args: ["--line-length=99"] # tool to automatically upgrade syntax for newer versions of the language - repo: https://github.com/asottile/pyupgrade - rev: v3.15.2 + rev: v3.17.0 hooks: - id: pyupgrade args: [--py311-plus] # Lint files - repo: https://github.com/pycqa/flake8 - rev: "7.0.0" + rev: "7.1.1" hooks: - id: flake8 args: [ diff --git a/autoautosummary.py b/autoautosummary.py index 2e9ec0f595b0..0bfda22ed502 100644 --- a/autoautosummary.py +++ b/autoautosummary.py @@ -2,18 +2,18 @@ # see https://stackoverflow.com/questions/20569011/python-sphinx-autosummary-automated-listing-of-member-functions # added toctree and nosignatures in options -from enum import Enum import re -from typing import Any, List, Optional +from enum import Enum +from typing import Any import PyQt5 from docutils import nodes from docutils.parsers.rst import directives -from sphinx.ext.autosummary import Autosummary, get_documenter from sphinx.ext import autosummary -from sphinx.util.inspect import safe_getattr -from sphinx.util import logging +from sphinx.ext.autosummary import Autosummary, get_documenter from sphinx.locale import __ +from sphinx.util import logging +from sphinx.util.inspect import safe_getattr # from sphinx.directives import directive logger = logging.getLogger(__name__) @@ -21,11 +21,13 @@ old_extract_summary = autosummary.extract_summary + def new_extract_summary(doc: list[str], document: Any) -> str: res = old_extract_summary(doc, document) - res = re.sub(r'\`((?!(?:None|True|False))[a-zA-Z0-9_]+)\`', r'\1', res) + res = re.sub(r"\`((?!(?:None|True|False))[a-zA-Z0-9_]+)\`", r"\1", res) return res + autosummary.extract_summary = new_extract_summary @@ -46,7 +48,7 @@ class AutoAutoSummary(Autosummary): "attributes": directives.unchanged, "nosignatures": directives.unchanged, "toctree": directives.unchanged, - "exclude-members": directives.unchanged + "exclude-members": directives.unchanged, } required_arguments = 1 @@ -55,18 +57,27 @@ class AutoAutoSummary(Autosummary): def skip_member(doc, obj: Any, name: str, options, objtype: str) -> bool: # print(name, name in options.get('exclude-members', '').split(',')) try: - if name in options.get('exclude-members', '').split(','): + if name in options.get("exclude-members", "").split(","): return True - return doc.settings.env.app.emit_firstresult('autodoc-skip-member', objtype, name, - obj, False, {}) + return doc.settings.env.app.emit_firstresult( + "autodoc-skip-member", objtype, name, obj, False, {} + ) except Exception as exc: - logger.warning(__('autosummary: failed to determine %r to be documented.' - 'the following exception was raised:\n%s'), - name, exc, type='autosummary') + logger.warning( + __( + "autosummary: failed to determine %r to be documented." + "the following exception was raised:\n%s" + ), + name, + exc, + type="autosummary", + ) return False @staticmethod - def get_members(doc, obj, typ, options, include_public: Optional[List]=None, signal=False, enum=False): + def get_members( + doc, obj, typ, options, include_public: list | None = None, signal=False, enum=False + ): try: if not include_public: include_public = [] @@ -81,7 +92,9 @@ def get_members(doc, obj, typ, options, include_public: Optional[List]=None, sig # cl = get_class_that_defined_method(chobj) # print(name, chobj.__qualname__, type(chobj), issubclass(chobj, Enum), documenter.objtype) if documenter.objtype == typ: - skipped = AutoAutoSummary.skip_member(doc, chobj, name, options, documenter.objtype) + skipped = AutoAutoSummary.skip_member( + doc, chobj, name, options, documenter.objtype + ) if skipped is True: continue if typ == "attribute": @@ -122,7 +135,9 @@ def run(self): c = getattr(m, class_name) if "methods" in self.options: rubric_title = "Methods" - _, rubric_elems = self.get_members(self.state.document, c, "method", self.options, ["__init__"]) + _, rubric_elems = self.get_members( + self.state.document, c, "method", self.options, ["__init__"] + ) elif "enums" in self.options: rubric_title = "Enums" _, rubric_elems = self.get_members( @@ -130,7 +145,9 @@ def run(self): ) elif "signals" in self.options: rubric_title = "Signals" - _, rubric_elems = self.get_members(self.state.document, c, "attribute", self.options, None, signal=True) + _, rubric_elems = self.get_members( + self.state.document, c, "attribute", self.options, None, signal=True + ) elif "attributes" in self.options: rubric_title = "Attributes" _, rubric_elems = self.get_members( diff --git a/conf.in.py b/conf.in.py index bde8233e9379..ae438e24632a 100644 --- a/conf.in.py +++ b/conf.in.py @@ -23,8 +23,7 @@ "sphinxcontrib.jquery", "sphinx.ext.linkcode", "inheritance_diagram", - "sphinx.ext.graphviz" - + "sphinx.ext.graphviz", ] # , 'rinoh.frontend.sphinx'], 'sphinx_autodoc_typehints' # The suffix of source filenames. @@ -49,7 +48,7 @@ if version == "master": QGIS_GIT_TAG = "master" else: - QGIS_GIT_TAG = f"release-{release.replace('.','_')}" + QGIS_GIT_TAG = f"release-{release.replace('.', '_')}" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -130,7 +129,7 @@ current_ltr = str(cfg["current_ltr"]) version_list = ("master", current_stable, current_ltr) -graphviz_output_format = 'svg' +graphviz_output_format = "svg" url = cfg["pyqgis_url"] if not url.endswith("/"): @@ -164,7 +163,7 @@ templates_path = ["_templates"] -autodoc_default_options = {'show-inheritance': True} +autodoc_default_options = {"show-inheritance": True} # If false, no module index is generated. html_domain_indices = True @@ -247,7 +246,12 @@ def linkcode_resolve(domain, info): def setup(app): try: from autoautosummary import AutoAutoSummary - from process_links import process_docstring, process_signature, skip_member, process_bases + from process_links import ( + process_bases, + process_docstring, + process_signature, + skip_member, + ) app.add_directive("autoautosummary", AutoAutoSummary) app.connect("autodoc-process-signature", process_signature) diff --git a/inheritance_diagram.py b/inheritance_diagram.py index fcd51227a478..8900492d35ed 100644 --- a/inheritance_diagram.py +++ b/inheritance_diagram.py @@ -39,10 +39,10 @@ class E(B): pass from os import path from typing import TYPE_CHECKING, Any, ClassVar, cast +import sphinx from docutils import nodes from docutils.parsers.rst import directives - -import sphinx +from qgis.PyQt import sip from sphinx import addnodes from sphinx.ext.graphviz import ( figure_wrapper, @@ -55,7 +55,6 @@ class E(B): pass if TYPE_CHECKING: from docutils.nodes import Node - from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment from sphinx.util.typing import ExtensionMetadata, OptionSpec @@ -63,16 +62,17 @@ 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 +module_sig_re = re.compile( + r"""^(?:([\w.]*)\.)? # module names (\w+) \s* $ # class/final module name - ''', re.VERBOSE) - + """, + re.VERBOSE, +) -py_builtins = [obj for obj in vars(builtins).values() - if inspect.isclass(obj)] -from qgis.PyQt import sip +py_builtins = [obj for obj in vars(builtins).values() if inspect.isclass(obj)] py_builtins.extend([sip.wrapper, sip.simplewrapper]) + def try_import(objname: str) -> Any: """Import a object or module using *name* and *currentmodule*. *name* should be a relative name from *currentmodule* or @@ -108,7 +108,7 @@ def import_classes(name: str, currmodule: str) -> Any: # import class or module using currmodule if currmodule: - target = try_import(currmodule + '.' + name) + target = try_import(currmodule + "." + name) # import class or module without currmodule if target is None: @@ -116,18 +116,22 @@ 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) + "Could not import class or module %r specified for " "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__ + ] + raise InheritanceException( + "%r specified for inheritance diagram is " "not a class or module" % name + ) class InheritanceException(Exception): @@ -141,10 +145,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 @@ -152,10 +162,11 @@ 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' + msg = "No classes found for inheritance diagram" raise InheritanceException(msg) def _import_classes(self, class_names: list[str], currmodule: str) -> list[Any]: @@ -165,9 +176,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, list[str], str]]: + 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, list[str], str]]: """Return name and bases for all classes that are ancestors of *classes*. @@ -185,10 +202,12 @@ def _class_info(self, classes: list[Any], show_builtins: bool, private_bases: bo """ all_classes = {} - def recurse(cls: Any, include_bases: bool, include_derived: bool=False, current_depth: int=0) -> None: + def recurse( + cls: Any, include_bases: bool, include_derived: bool = False, current_depth: int = 0 + ) -> None: if not show_builtins and cls in py_builtins: return - if not private_bases and cls.__name__.startswith('_'): + if not private_bases and cls.__name__.startswith("_"): return nodename = self.class_name(cls, parts, aliases) @@ -215,7 +234,7 @@ def recurse(cls: Any, include_bases: bool, include_derived: bool=False, current_ for base in cls.__bases__: if not show_builtins and base in py_builtins: continue - if not private_bases and base.__name__.startswith('_'): + if not private_bases and base.__name__.startswith("_"): continue baselist.append(self.class_name(base, parts, aliases)) if base not in all_classes: @@ -228,7 +247,7 @@ def recurse(cls: Any, include_bases: bool, include_derived: bool=False, current_ continue derivedlist.append(self.class_name(derived, parts, aliases)) if derived not in all_classes: - recurse(derived, False, depth<5, depth) + recurse(derived, False, depth < 5, depth) for cls in classes: recurse(cls, include_bases=True, include_derived=True, current_depth=0) @@ -236,7 +255,10 @@ def recurse(cls: Any, include_bases: bool, include_derived: bool=False, current_ return list(all_classes.values()) # type: ignore[arg-type] 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. @@ -244,15 +266,15 @@ def class_name( completely general. """ module = cls.__module__ - if module in ('__builtin__', 'builtins'): + if module in ("__builtin__", "builtins"): fullname = cls.__name__ else: - fullname = f'{module}.{cls.__qualname__}' + fullname = f"{module}.{cls.__qualname__}" if parts == 0: result = fullname else: - name_parts = fullname.split('.') - result = '.'.join(name_parts[-parts:]) + name_parts = fullname.split(".") + result = ".".join(name_parts[-parts:]) if aliases is not None and result in aliases: return aliases[result] return result @@ -263,36 +285,38 @@ def get_all_class_names(self) -> list[str]: # These are the default attrs for graphviz default_graph_attrs = { - 'rankdir': 'LR', - 'size': '"8.0, 12.0"', - 'bgcolor': 'transparent', + "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', + "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)"', + "arrowsize": 0.5, + "style": '"setlinewidth(0.5)"', } def _format_node_attrs(self, attrs: dict[str, Any]) -> str: - return ','.join(f'{k}={v}' for k, v in sorted(attrs.items())) + return ",".join(f"{k}={v}" for k, v in sorted(attrs.items())) 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: + 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: """Generate a graphviz dot graph from the classes that were passed in to __init__. @@ -320,32 +344,34 @@ def generate_dot(self, name: str, urls: dict[str, str] | None = None, e_attrs.update(env.config.inheritance_edge_attrs) res: list[str] = [ - f'digraph {name} {{\n', + f"digraph {name} {{\n", self._format_graph_attrs(g_attrs), ] for name, fullname, bases, tooltip, derived in sorted(self.class_info): # Write the node this_node_attrs = n_attrs.copy() - if any(n.endswith(f'.{name}') for n in self.class_names): - this_node_attrs['fillcolor'] = '"#e7f2fa"' + if any(n.endswith(f".{name}") for n in self.class_names): + this_node_attrs["fillcolor"] = '"#e7f2fa"' if fullname in urls: this_node_attrs["URL"] = '"%s"' % urls[fullname] this_node_attrs["target"] = '"_top"' if tooltip: this_node_attrs["tooltip"] = tooltip - res.append(' "%s" [%s];\n' % (name, self._format_node_attrs(this_node_attrs))) + res.append(f' "{name}" [{self._format_node_attrs(this_node_attrs)}];\n') # Write the edges res.extend( - ' "%s" -> "%s" [%s];\n' % (base_name, name, self._format_node_attrs(e_attrs)) + f' "{base_name}" -> "{name}" [{self._format_node_attrs(e_attrs)}];\n' for base_name in bases ) # Write derived classes res.extend( - ' "%s" -> "%s" [%s];\n' % (name, derived_name, self._format_node_attrs(e_attrs)) + ' "{}" -> "{}" [{}];\n'.format( + name, derived_name, self._format_node_attrs(e_attrs) + ) for derived_name in derived ) @@ -358,8 +384,6 @@ class inheritance_diagram(graphviz): A docutils node to use as a placeholder for the inheritance diagram. """ - pass - class InheritanceDiagram(SphinxDirective): """ @@ -371,34 +395,36 @@ class InheritanceDiagram(SphinxDirective): optional_arguments = 0 final_argument_whitespace = True option_spec: ClassVar[OptionSpec] = { - 'parts': int, - 'private-bases': directives.flag, - 'caption': directives.unchanged, - 'top-classes': directives.unchanged_required, + "parts": int, + "private-bases": directives.flag, + "caption": directives.unchanged, + "top-classes": directives.unchanged_required, } def run(self) -> list[Node]: node = inheritance_diagram() node.document = self.state.document class_names = self.arguments[0].split() - class_role = self.env.get_domain('py').role('class') + 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(','): + 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) + node["top-classes"].append(cls) # 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] - parts=node['parts'], - private_bases='private-bases' in self.options, + 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)] @@ -408,23 +434,24 @@ 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", ":class:`%s`" % name, name, 0, self.state.inliner + ) node.extend(refnodes) # Store the graph object so we can use it to generate the # dot file later - node['graph'] = graph + node["graph"] = graph - if 'caption' not in self.options: + if "caption" not in self.options: self.add_name(node) return [node] else: - figure = figure_wrapper(self, node, self.options['caption']) + figure = figure_wrapper(self, node, self.options["caption"]) self.add_name(figure) return [figure] def get_graph_hash(node: inheritance_diagram) -> str: - encoded = (node['content'] + str(node['parts'])).encode() + encoded = (node["content"] + str(node["parts"])).encode() return hashlib.md5(encoded, usedforsecurity=False).hexdigest()[-10:] @@ -433,10 +460,10 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag Output the graph for HTML. This will insert a PNG with clickable image map. """ - graph = node['graph'] + graph = node["graph"] graph_hash = get_graph_hash(node) - name = 'inheritance%s' % graph_hash + name = "inheritance%s" % graph_hash # Create a mapping from fully-qualified class names to URLs. graphviz_output_format = self.builder.env.config.graphviz_output_format.upper() @@ -444,26 +471,33 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag urls = {} pending_xrefs = cast(Iterable[addnodes.pending_xref], node) for child in pending_xrefs: - if child.get('refuri') is not None: + if child.get("refuri") is not None: # Construct the name from the URI if the reference is external via intersphinx - if not child.get('internal', True): - refname = child['refuri'].rsplit('#', 1)[-1] + if not child.get("internal", True): + refname = child["refuri"].rsplit("#", 1)[-1] else: - refname = child['reftitle'] + refname = child["reftitle"] - if '#' in child.get('refuri'): - urls[refname] = child['refuri'].split('#')[0] + if "#" in child.get("refuri"): + urls[refname] = child["refuri"].split("#")[0] else: - urls[refname] = child.get('refuri') - elif child.get('refid') is not None: - if graphviz_output_format == 'SVG': - urls[child['reftitle']] = current_filename + '#' + child.get('refid') + urls[refname] = child.get("refuri") + elif child.get("refid") is not None: + if graphviz_output_format == "SVG": + urls[child["reftitle"]] = current_filename + "#" + child.get("refid") else: - urls[child['reftitle']] = '#' + child.get('refid') + 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 @@ -471,30 +505,30 @@ def latex_visit_inheritance_diagram(self: LaTeXTranslator, node: inheritance_dia """ Output the graph for LaTeX. This will insert a PDF. """ - graph = node['graph'] + graph = node["graph"] graph_hash = get_graph_hash(node) - name = 'inheritance%s' % graph_hash + name = "inheritance%s" % graph_hash - dotcode = graph.generate_dot(name, env=self.builder.env, - graph_attrs={'size': '"6.0,6.0"'}) - render_dot_latex(self, node, dotcode, {}, 'inheritance') + 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. """ - graph = node['graph'] + graph = node["graph"] graph_hash = get_graph_hash(node) - name = 'inheritance%s' % graph_hash + name = "inheritance%s" % graph_hash - dotcode = graph.generate_dot(name, env=self.builder.env, - graph_attrs={'size': '"6.0,6.0"'}) - render_dot_texinfo(self, node, dotcode, {}, 'inheritance') + 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 @@ -503,17 +537,18 @@ def skip(self: nodes.NodeVisitor, node: inheritance_diagram) -> None: def setup(app: Sphinx) -> ExtensionMetadata: - app.setup_extension('sphinx.ext.graphviz') + app.setup_extension("sphinx.ext.graphviz") app.add_node( inheritance_diagram, latex=(latex_visit_inheritance_diagram, None), html=(html_visit_inheritance_diagram, None), text=(skip, None), man=(skip, 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', {}, '') - app.add_config_value('inheritance_edge_attrs', {}, '') - app.add_config_value('inheritance_alias', {}, '') - return {'version': sphinx.__display_version__, 'parallel_read_safe': True} + 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", {}, "") + app.add_config_value("inheritance_edge_attrs", {}, "") + app.add_config_value("inheritance_alias", {}, "") + return {"version": sphinx.__display_version__, "parallel_read_safe": True} diff --git a/process_links.py b/process_links.py index 1e3c3adc60dc..b7f79ebe3d65 100644 --- a/process_links.py +++ b/process_links.py @@ -14,6 +14,7 @@ cfg = yaml.safe_load(f) from sphinx.ext.autodoc import Documenter + old_get_doc = Documenter.get_doc @@ -21,7 +22,7 @@ def new_get_doc(self) -> list[list[str]] | None: try: if self.object_name in self.parent.__attribute_docs__: docs = self.parent.__attribute_docs__[self.object_name] - return [docs.split('\n')] + return [docs.split("\n")] except AttributeError: pass @@ -139,5 +140,5 @@ def process_bases(app, name, obj, option, bases: list) -> None: """Here we fine tune how the base class's classes are displayed.""" for i, base in enumerate(bases): # replace 'sip.wrapper' base class with 'object' - if base.__name__ == 'wrapper': + if base.__name__ == "wrapper": bases[i] = object diff --git a/scripts/make_api_rst.py b/scripts/make_api_rst.py index e66864ceecaa..45a7863b55e1 100755 --- a/scripts/make_api_rst.py +++ b/scripts/make_api_rst.py @@ -64,16 +64,18 @@ def ltr_tag(v): current_ltr = cfg["current_ltr"] current_stable_minor = int(current_stable.split(".")[1]) + 2 # '3.38' => 40 current_ltr_minor = int(current_ltr.split(".")[1]) + 2 # '3.38' => 40 -old_versions_links = ", ".join(reversed( - [ - f"`3.{v} `_" - for v in range(0, current_stable_minor, 2) - if v not in (current_stable_minor, current_ltr_minor) - ] -)) +old_versions_links = ", ".join( + reversed( + [ + f"`3.{v} `_" + for v in range(0, current_stable_minor, 2) + if v not in (current_stable_minor, current_ltr_minor) + ] + ) +) py_ext_sig_re = re.compile( -r"""^(?:([\w.]+::)?([\w.]+\.)?(\w+)\s*(?:\((.*)\)(?:\s*->\s*([\w.]+(?:\[.*?\])?))?(?:\s*\[(signal)\])?)?)?$""" + r"""^(?:([\w.]+::)?([\w.]+\.)?(\w+)\s*(?:\((.*)\)(?:\s*->\s*([\w.]+(?:\[.*?\])?))?(?:\s*\[(signal)\])?)?)?$""" ) @@ -195,13 +197,17 @@ def generate_docs(): class_doc = getattr(_class, method).__doc__ - if class_doc and all(py_ext_sig_re.match(line) for line in str(class_doc).split('\n')): + if class_doc and all( + py_ext_sig_re.match(line) for line in str(class_doc).split("\n") + ): # print(f'docs are function signature only {class_doc}') class_doc = None - if hasattr(_class, '__bases__'): + if hasattr(_class, "__bases__"): for base in _class.__bases__: - if hasattr(base, method) and (not class_doc or getattr(base, method).__doc__ == str(class_doc)): + if hasattr(base, method) and ( + not class_doc or getattr(base, method).__doc__ == str(class_doc) + ): # print(f'skipping overridden method with no new doc {method}') exclude_methods.add(method) break @@ -211,9 +217,11 @@ def generate_docs(): # print(getattr(base, method).__doc__) pass - substitutions = {"PACKAGE": package_name, - "CLASS": class_name, - "EXCLUDE_METHODS": ','.join(exclude_methods)} + substitutions = { + "PACKAGE": package_name, + "CLASS": class_name, + "EXCLUDE_METHODS": ",".join(exclude_methods), + } class_template = template.substitute(**substitutions) class_rst = open(f"api/{qgis_version}/{package_name}/{class_name}.rst", "w") print(class_template, file=class_rst) @@ -251,8 +259,8 @@ def extract_package_classes(package): continue _class = getattr(package, class_name) - if hasattr(_class, '__name__') and class_name != _class.__name__: - print(f'Skipping alias {class_name}, {_class.__name__}') + if hasattr(_class, "__name__") and class_name != _class.__name__: + print(f"Skipping alias {class_name}, {_class.__name__}") continue # if not re.match('^Qgi?s', class_name):