diff --git a/.ruff-excludes.toml b/.ruff-excludes.toml index 5b05d8ec83f..dd2d96ffecb 100644 --- a/.ruff-excludes.toml +++ b/.ruff-excludes.toml @@ -43,78 +43,6 @@ "./boards/microchip/mec172xevb_assy6906/support/mec172x_remote_flasher.py" = [ "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports ] -"./doc/_extensions/zephyr/api_overview.py" = [ - "E501", # https://docs.astral.sh/ruff/rules/line-too-long - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/application.py" = [ - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "SIM102", # https://docs.astral.sh/ruff/rules/collapsible-if - "UP032", # https://docs.astral.sh/ruff/rules/f-string -] -"./doc/_extensions/zephyr/domain/__init__.py" = [ - "B023", # https://docs.astral.sh/ruff/rules/function-uses-loop-variable - "B026", # https://docs.astral.sh/ruff/rules/star-arg-unpacking-after-keyword-arg - "E402", # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file - "E501", # https://docs.astral.sh/ruff/rules/line-too-long - "F401", # https://docs.astral.sh/ruff/rules/unused-import - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/doxybridge.py" = [ - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/doxyrunner.py" = [ - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "SIM115", # https://docs.astral.sh/ruff/rules/open-file-with-context-handler - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation - "UP024", # https://docs.astral.sh/ruff/rules/os-error-alias - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/doxytooltip/__init__.py" = [ - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/external_content.py" = [ - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/gh_utils.py" = [ - "E402", # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/kconfig/__init__.py" = [ - "E402", # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file - "SIM112", # https://docs.astral.sh/ruff/rules/uncapitalized-environment-variables - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation - "UP028", # https://docs.astral.sh/ruff/rules/yield-in-for-loop - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] -"./doc/_extensions/zephyr/link-roles.py" = [ - "B006", # https://docs.astral.sh/ruff/rules/mutable-argument-default - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "SIM102", # https://docs.astral.sh/ruff/rules/collapsible-if - "UP010", # https://docs.astral.sh/ruff/rules/unnecessary-future-import -] -"./doc/_extensions/zephyr/manifest_projects_table.py" = [ - "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports - "SIM114", # https://docs.astral.sh/ruff/rules/if-with-same-arms - "UP006", # https://docs.astral.sh/ruff/rules/non-pep585-annotation - "UP035", # https://docs.astral.sh/ruff/rules/deprecated-import -] "./doc/_scripts/gen_boards_catalog.py" = [ "E401", # https://docs.astral.sh/ruff/rules/multiple-imports-on-one-line "I001", # https://docs.astral.sh/ruff/rules/unsorted-imports diff --git a/doc/_extensions/zephyr/api_overview.py b/doc/_extensions/zephyr/api_overview.py index 15bbe0e804b..3d56e5eaee4 100644 --- a/doc/_extensions/zephyr/api_overview.py +++ b/doc/_extensions/zephyr/api_overview.py @@ -1,14 +1,14 @@ # Copyright (c) 2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -import doxmlparser +from pathlib import Path +from typing import Any +import doxmlparser from docutils import nodes from doxmlparser.compound import DoxCompoundKind -from pathlib import Path from sphinx.application import Sphinx from sphinx.util.docutils import SphinxDirective -from typing import Any, Dict class ApiOverview(SphinxDirective): @@ -56,7 +56,9 @@ def visit_group(app, group, all_groups, rows, indent=0): if since: since_url = nodes.inline() - reference = nodes.reference(text=f"v{since.strip()}.0", refuri=f"{github_uri}/v{since.strip()}.0") + reference = nodes.reference( + text=f"v{since.strip()}.0", refuri=f"{github_uri}/v{since.strip()}.0" + ) reference.attributes["internal"] = True since_url += reference else: @@ -161,7 +163,7 @@ def sync_contents(app: Sphinx) -> None: app.builder.env.api_overview_table = generate_table(app, toplevel, groups) -def setup(app) -> Dict[str, Any]: +def setup(app) -> dict[str, Any]: app.add_config_value("api_overview_doxygen_xml_dir", "html/doxygen/xml", "env") app.add_config_value("api_overview_doxygen_base_url", "../../doxygen/html", "env") diff --git a/doc/_extensions/zephyr/application.py b/doc/_extensions/zephyr/application.py index d59cb4294b1..4b2867b6ab0 100644 --- a/doc/_extensions/zephyr/application.py +++ b/doc/_extensions/zephyr/application.py @@ -4,11 +4,10 @@ '''Sphinx extensions related to managing Zephyr applications.''' -from docutils import nodes -from docutils.parsers.rst import Directive -from docutils.parsers.rst import directives from pathlib import Path +from docutils import nodes +from docutils.parsers.rst import Directive, directives ZEPHYR_BASE = Path(__file__).parents[3] @@ -79,8 +78,7 @@ class ZephyrAppCommandsDirective(Directive): flash_args = self.options.get('flash-args', None) if tool not in self.TOOLS: - raise self.error('Unknown tool {}; choose from: {}'.format( - tool, self.TOOLS)) + raise self.error(f'Unknown tool {tool}; choose from: {self.TOOLS}') if app and zephyr_app: raise self.error('Both app and zephyr-app options were given.') @@ -92,25 +90,22 @@ class ZephyrAppCommandsDirective(Directive): raise self.error('build-dir-fmt is only supported for the west build tool.') if generator not in self.GENERATORS: - raise self.error('Unknown generator {}; choose from: {}'.format( - generator, self.GENERATORS)) + raise self.error(f'Unknown generator {generator}; choose from: {self.GENERATORS}') if host_os not in self.HOST_OS: - raise self.error('Unknown host-os {}; choose from: {}'.format( - host_os, self.HOST_OS)) + raise self.error(f'Unknown host-os {host_os}; choose from: {self.HOST_OS}') if compact and skip_config: raise self.error('Both compact and maybe-skip-config options were given.') - if zephyr_app: - # as folks might use "<...>" notation to indicate a variable portion of the path, we - # deliberately don't check for the validity of such paths. - if not any([x in zephyr_app for x in ["<", ">"]]): - app_path = ZEPHYR_BASE / zephyr_app - if not app_path.is_dir(): - raise self.error( - f"zephyr-app: {zephyr_app} is not a valid folder in the zephyr tree." - ) + # as folks might use "<...>" notation to indicate a variable portion of the path, we + # deliberately don't check for the validity of such paths. + if zephyr_app and not any([x in zephyr_app for x in ["<", ">"]]): + app_path = ZEPHYR_BASE / zephyr_app + if not app_path.is_dir(): + raise self.error( + f"zephyr-app: {zephyr_app} is not a valid folder in the zephyr tree." + ) app = app or zephyr_app in_tree = self.IN_TREE_STR if zephyr_app else None @@ -168,7 +163,7 @@ class ZephyrAppCommandsDirective(Directive): if tool_comment: paragraph = nodes.paragraph() paragraph += nodes.Text(tool_comment.format( - 'CMake and {}'.format(generator))) + f'CMake and {generator}')) content.append(paragraph) content.append(self._lit_block(c)) else: @@ -208,30 +203,30 @@ class ZephyrAppCommandsDirective(Directive): # west always defaults to ninja gen_arg = ' -G\'Unix Makefiles\'' if generator == 'make' else '' cmake_args = gen_arg + self._cmake_args(**kwargs) - cmake_args = ' --{}'.format(cmake_args) if cmake_args != '' else '' + cmake_args = f' --{cmake_args}' if cmake_args != '' else '' build_args = "".join(f" -o {b}" for b in build_args) if build_args else "" - west_args = ' {}'.format(west_args) if west_args else '' - flash_args = ' {}'.format(flash_args) if flash_args else '' + west_args = f' {west_args}' if west_args else '' + flash_args = f' {flash_args}' if flash_args else '' snippet_args = ''.join(f' -S {s}' for s in snippets) if snippets else '' shield_args = ''.join(f' --shield {s}' for s in shield) if shield else '' # ignore zephyr_app since west needs to run within # the installation. Instead rely on relative path. - src = ' {}'.format(app) if app and not cd_into else '' + src = f' {app}' if app and not cd_into else '' if build_dir_fmt is None: - dst = ' -d {}'.format(build_dir) if build_dir != 'build' else '' + dst = f' -d {build_dir}' if build_dir != 'build' else '' build_dst = dst else: app_name = app.split('/')[-1] build_dir_formatted = build_dir_fmt.format(app=app_name, board=board, source_dir=app) - dst = ' -d {}'.format(build_dir_formatted) + dst = f' -d {build_dir_formatted}' build_dst = '' if in_tree and not compact: content.append(in_tree) if cd_into and app: - content.append('cd {}'.format(app)) + content.append(f'cd {app}') # We always have to run west build. # @@ -252,21 +247,21 @@ class ZephyrAppCommandsDirective(Directive): # etc. commands can use the signed file which must be created # in this step. if 'sign' in goals: - content.append('west sign{}'.format(dst)) + content.append(f'west sign{dst}') for goal in goals: if goal in {'build', 'sign'}: continue elif goal == 'flash': - content.append('west flash{}{}'.format(flash_args, dst)) + content.append(f'west flash{flash_args}{dst}') elif goal == 'debug': - content.append('west debug{}'.format(dst)) + content.append(f'west debug{dst}') elif goal == 'debugserver': - content.append('west debugserver{}'.format(dst)) + content.append(f'west debugserver{dst}') elif goal == 'attach': - content.append('west attach{}'.format(dst)) + content.append(f'west attach{dst}') else: - content.append('west build -t {}{}'.format(goal, dst)) + content.append(f'west build -t {goal}{dst}') return content @@ -274,14 +269,15 @@ class ZephyrAppCommandsDirective(Directive): def _mkdir(mkdir, build_dir, host_os, skip_config): content = [] if skip_config: - content.append("# If you already made a build directory ({}) and ran cmake, just 'cd {}' instead.".format(build_dir, build_dir)) # noqa: E501 + content.append(f"# If you already made a build directory ({build_dir}) and ran cmake, " + f"just 'cd {build_dir}' instead.") if host_os == 'all': - content.append('mkdir {} && cd {}'.format(build_dir, build_dir)) + content.append(f'mkdir {build_dir} && cd {build_dir}') if host_os == "unix": - content.append('{} {} && cd {}'.format(mkdir, build_dir, build_dir)) + content.append(f'{mkdir} {build_dir} && cd {build_dir}') elif host_os == "win": build_dir = build_dir.replace('/', '\\') - content.append('mkdir {} & cd {}'.format(build_dir, build_dir)) + content.append(f'mkdir {build_dir} & cd {build_dir}') return content @staticmethod @@ -289,11 +285,11 @@ class ZephyrAppCommandsDirective(Directive): board = kwargs['board'] conf = kwargs['conf'] gen_args = kwargs['gen_args'] - board_arg = ' -DBOARD={}'.format(board) if board else '' - conf_arg = ' -DCONF_FILE={}'.format(conf) if conf else '' - gen_args = ' {}'.format(gen_args) if gen_args else '' + board_arg = f' -DBOARD={board}' if board else '' + conf_arg = f' -DCONF_FILE={conf}' if conf else '' + gen_args = f' {gen_args}' if gen_args else '' - return '{}{}{}'.format(board_arg, conf_arg, gen_args) + return f'{board_arg}{conf_arg}{gen_args}' def _cd_into(self, mkdir, **kwargs): app = kwargs['app'] @@ -319,13 +315,13 @@ class ZephyrAppCommandsDirective(Directive): if os_comment: content.append(os_comment.format('Linux/macOS')) if app: - content.append('cd {}'.format(app)) + content.append(f'cd {app}') elif host == "win": if os_comment: content.append(os_comment.format('Windows')) if app: backslashified = app.replace('/', '\\') - content.append('cd {}'.format(backslashified)) + content.append(f'cd {backslashified}') if mkdir: content.extend(self._mkdir(mkdir, build_dir, host, skip_config)) if not compact: @@ -359,39 +355,36 @@ class ZephyrAppCommandsDirective(Directive): cmake_build_dir = '' tool_build_dir = '' else: - source_dir = ' {}'.format(app) if app else ' .' - cmake_build_dir = ' -B{}'.format(build_dir) - tool_build_dir = ' -C{}'.format(build_dir) + source_dir = f' {app}' if app else ' .' + cmake_build_dir = f' -B{build_dir}' + tool_build_dir = f' -C{build_dir}' # Now generate the actual cmake and make/ninja commands gen_arg = ' -GNinja' if generator == 'ninja' else '' - build_args = ' {}'.format(build_args) if build_args else '' + build_args = f' {build_args}' if build_args else '' snippet_args = ' -DSNIPPET="{}"'.format(';'.join(snippets)) if snippets else '' shield_args = ' -DSHIELD="{}"'.format(';'.join(shield)) if shield else '' cmake_args = self._cmake_args(**kwargs) if not compact: if not cd_into and skip_config: - content.append("# If you already ran cmake with -B{}, you " \ - "can skip this step and run {} directly.". - format(build_dir, generator)) # noqa: E501 + content.append(f'# If you already ran cmake with -B{build_dir}, you ' + f'can skip this step and run {generator} directly.') else: - content.append('# Use cmake to configure a {}-based build' \ - 'system:'.format(generator.capitalize())) # noqa: E501 + content.append(f'# Use cmake to configure a {generator.capitalize()}-based build' + 'system:') - content.append('cmake{}{}{}{}{}{}'.format(cmake_build_dir, gen_arg, - cmake_args, snippet_args, shield_args, source_dir)) + content.append(f'cmake{cmake_build_dir}{gen_arg}{cmake_args}{snippet_args}{shield_args}{source_dir}') if not compact: content.extend(['', '# Now run the build tool on the generated build system:']) if 'build' in goals: - content.append('{}{}{}'.format(generator, tool_build_dir, - build_args)) + content.append(f'{generator}{tool_build_dir}{build_args}') for goal in goals: if goal == 'build': continue - content.append('{}{} {}'.format(generator, tool_build_dir, goal)) + content.append(f'{generator}{tool_build_dir} {goal}') return content diff --git a/doc/_extensions/zephyr/domain/__init__.py b/doc/_extensions/zephyr/domain/__init__.py index 1751b39d820..b598ef3a3e5 100644 --- a/doc/_extensions/zephyr/domain/__init__.py +++ b/doc/_extensions/zephyr/domain/__init__.py @@ -26,15 +26,17 @@ Roles """ +import json import sys +from collections.abc import Iterator from os import path from pathlib import Path -from typing import Any, Dict, Iterator, List, Tuple, Final +from typing import Any +from anytree import ChildResolverError, Node, PreOrderIter, Resolver, search from docutils import nodes from docutils.parsers.rst import directives from docutils.statemachine import StringList - from sphinx import addnodes from sphinx.application import Sphinx from sphinx.domains import Domain, ObjType @@ -51,20 +53,15 @@ from sphinx.util.template import SphinxRenderer from zephyr.doxybridge import DoxygenGroupDirective from zephyr.gh_utils import gh_link_get_url - -import json - -from anytree import Node, Resolver, ChildResolverError, PreOrderIter, search - __version__ = "0.2.0" -ZEPHYR_BASE = Path(__file__).parents[4] -sys.path.insert(0, str(ZEPHYR_BASE / "scripts/dts/python-devicetree/src")) +sys.path.insert(0, str(Path(__file__).parents[4] / "scripts/dts/python-devicetree/src")) sys.path.insert(0, str(Path(__file__).parents[3] / "_scripts")) from gen_boards_catalog import get_catalog +ZEPHYR_BASE = Path(__file__).parents[4] TEMPLATES_DIR = Path(__file__).parent / "templates" RESOURCES_DIR = Path(__file__).parent / "static" @@ -295,10 +292,10 @@ class CodeSampleCategoriesTocPatching(SphinxPostTransform): reference = nodes.reference( "", "", + *[nodes.Text(tree.category["name"])], internal=True, refuri=docname, anchorname="", - *[nodes.Text(tree.category["name"])], classes=["category-link"], ) compact_paragraph += reference @@ -328,10 +325,10 @@ class CodeSampleCategoriesTocPatching(SphinxPostTransform): sample_xref = nodes.reference( "", "", + *[nodes.Text(code_sample["name"])], internal=True, refuri=code_sample["docname"], anchorname="", - *[nodes.Text(code_sample["name"])], classes=["code-sample-link"], ) sample_xref["reftitle"] = code_sample["description"].astext() @@ -414,7 +411,8 @@ class ProcessCodeSampleListingNode(SphinxPostTransform): "", """ """, @@ -432,7 +430,8 @@ class ProcessCodeSampleListingNode(SphinxPostTransform): category_node = search.find( code_samples_categories_tree, - lambda node: hasattr(node, "category") and node.category["id"] == category, + lambda node, category=category: hasattr(node, "category") + and node.category["id"] == category, ) self.output_sample_categories_sections(category_node, container) @@ -721,13 +720,13 @@ class ZephyrDomain(Domain): "board": BoardDirective, } - object_types: Dict[str, ObjType] = { + object_types: dict[str, ObjType] = { "code-sample": ObjType("code sample", "code-sample"), "code-sample-category": ObjType("code sample category", "code-sample-category"), "board": ObjType("board", "board"), } - initial_data: Dict[str, Any] = { + initial_data: dict[str, Any] = { "code-samples": {}, # id -> code sample data "code-samples-categories": {}, # id -> code sample category data "code-samples-categories-tree": Node("samples"), @@ -754,11 +753,12 @@ class ZephyrDomain(Domain): self.data["has_code_sample_listing"].pop(docname, None) self.data["has_board_catalog"].pop(docname, None) - def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: + def merge_domaindata(self, docnames: list[str], otherdata: dict) -> None: self.data["code-samples"].update(otherdata["code-samples"]) self.data["code-samples-categories"].update(otherdata["code-samples-categories"]) - # self.data["boards"] contains all the boards right from builder-inited time, but it still # potentially needs merging since a board's docname property is set by BoardDirective to + # self.data["boards"] contains all the boards right from builder-inited time, but it still + # potentially needs merging since a board's docname property is set by BoardDirective to # indicate the board is documented in a specific document. for board_name, board in otherdata["boards"].items(): if "docname" in board: @@ -819,7 +819,7 @@ class ZephyrDomain(Domain): ) # used by Sphinx Immaterial theme - def get_object_synopses(self) -> Iterator[Tuple[Tuple[str, str], str]]: + def get_object_synopses(self) -> Iterator[tuple[tuple[str, str], str]]: for _, code_sample in self.data["code-samples"].items(): yield ( (code_sample["docname"], code_sample["id"]), @@ -899,7 +899,7 @@ class ZephyrDomain(Domain): class CustomDoxygenGroupDirective(DoxygenGroupDirective): """Monkey patch for Breathe's DoxygenGroupDirective.""" - def run(self) -> List[Node]: + def run(self) -> list[Node]: nodes = super().run() if self.config.zephyr_breathe_insert_related_samples: diff --git a/doc/_extensions/zephyr/doxybridge.py b/doc/_extensions/zephyr/doxybridge.py index b15b1fc2f9a..fe0074b65da 100644 --- a/doc/_extensions/zephyr/doxybridge.py +++ b/doc/_extensions/zephyr/doxybridge.py @@ -4,22 +4,19 @@ Copyright (c) 2024 The Linux Foundation SPDX-License-Identifier: Apache-2.0 """ -import os -from typing import Any, Dict - import concurrent.futures +import os +from typing import Any +import doxmlparser from docutils import nodes - +from doxmlparser.compound import DoxCompoundKind, DoxMemberKind from sphinx import addnodes from sphinx.application import Sphinx +from sphinx.domains.c import CXRefRole from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util import logging from sphinx.util.docutils import SphinxDirective -from sphinx.domains.c import CXRefRole - -import doxmlparser -from doxmlparser.compound import DoxCompoundKind, DoxMemberKind logger = logging.getLogger(__name__) @@ -154,7 +151,7 @@ def parse_sections(compounddef): return cache -def parse_compound(inDirName, baseName) -> Dict: +def parse_compound(inDirName, baseName) -> dict: rootObj = doxmlparser.compound.parse(inDirName + "/" + baseName + ".xml", True) cache = {} group_titles = {} @@ -218,7 +215,7 @@ def doxygen_parse(app: Sphinx) -> None: parse_index(app, str(app.config.doxybridge_dir / "xml")) -def setup(app: Sphinx) -> Dict[str, Any]: +def setup(app: Sphinx) -> dict[str, Any]: app.add_config_value("doxybridge_dir", None, "env") app.add_directive("doxygengroup", DoxygenGroupDirective) diff --git a/doc/_extensions/zephyr/doxyrunner.py b/doc/_extensions/zephyr/doxyrunner.py index 64d4a2c793a..bdbc0daba6e 100644 --- a/doc/_extensions/zephyr/doxyrunner.py +++ b/doc/_extensions/zephyr/doxyrunner.py @@ -43,19 +43,18 @@ Configuration options import filecmp import hashlib -from pathlib import Path import re import shlex import shutil -from subprocess import Popen, PIPE, STDOUT import tempfile -from typing import List, Dict, Optional, Any +from pathlib import Path +from subprocess import PIPE, STDOUT, Popen +from typing import Any from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment from sphinx.util import logging - __version__ = "0.1.0" @@ -77,7 +76,7 @@ def hash_file(file: Path) -> str: return sha256.hexdigest() -def get_doxygen_option(doxyfile: str, option: str) -> List[str]: +def get_doxygen_option(doxyfile: str, option: str) -> list[str]: """Obtain the value of a Doxygen option. Args: @@ -133,9 +132,9 @@ def process_doxyfile( outdir: Path, silent: bool, fmt: bool = False, - fmt_pattern: Optional[str] = None, - fmt_vars: Optional[Dict[str, str]] = None, - outdir_var: Optional[str] = None, + fmt_pattern: str | None = None, + fmt_vars: dict[str, str] | None = None, + outdir_var: str | None = None, ) -> str: """Process Doxyfile. @@ -270,11 +269,11 @@ def run_doxygen(doxygen: str, doxyfile: str, silent: bool = False) -> None: silent: If Doxygen output should be logged or not. """ - f_doxyfile = tempfile.NamedTemporaryFile("w", delete=False) - f_doxyfile.write(doxyfile) - f_doxyfile.close() + with tempfile.NamedTemporaryFile("w", delete=False) as f_doxyfile: + f_doxyfile.write(doxyfile) + f_doxyfile_name = f_doxyfile.name - p = Popen([doxygen, f_doxyfile.name], stdout=PIPE, stderr=STDOUT, encoding="utf-8") + p = Popen([doxygen, f_doxyfile_name], stdout=PIPE, stderr=STDOUT, encoding="utf-8") while True: line = p.stdout.readline() # type: ignore if line: @@ -282,10 +281,10 @@ def run_doxygen(doxygen: str, doxyfile: str, silent: bool = False) -> None: if p.poll() is not None: break - Path(f_doxyfile.name).unlink() + Path(f_doxyfile_name).unlink() if p.returncode: - raise IOError(f"Doxygen process returned non-zero ({p.returncode})") + raise OSError(f"Doxygen process returned non-zero ({p.returncode})") def sync_doxygen(doxyfile: str, new: Path, prev: Path) -> None: @@ -380,7 +379,7 @@ def doxygen_build(app: Sphinx) -> None: shutil.rmtree(tmp_outdir) -def setup(app: Sphinx) -> Dict[str, Any]: +def setup(app: Sphinx) -> dict[str, Any]: app.add_config_value("doxyrunner_doxygen", "doxygen", "env") app.add_config_value("doxyrunner_doxyfile", None, "env") app.add_config_value("doxyrunner_outdir", None, "env") diff --git a/doc/_extensions/zephyr/doxytooltip/__init__.py b/doc/_extensions/zephyr/doxytooltip/__init__.py index 8c768fded27..574e65be2c3 100644 --- a/doc/_extensions/zephyr/doxytooltip/__init__.py +++ b/doc/_extensions/zephyr/doxytooltip/__init__.py @@ -10,8 +10,7 @@ to enable tooltips for C domain links. """ from pathlib import Path - -from typing import Any, Dict +from typing import Any from sphinx.application import Sphinx from sphinx.util import logging @@ -20,7 +19,7 @@ logger = logging.getLogger(__name__) RESOURCES_DIR = Path(__file__).parent / "static" -def setup(app: Sphinx) -> Dict[str, Any]: +def setup(app: Sphinx) -> dict[str, Any]: app.config.html_static_path.append(RESOURCES_DIR.as_posix()) app.add_js_file("tippy/popper.min.js") diff --git a/doc/_extensions/zephyr/external_content.py b/doc/_extensions/zephyr/external_content.py index 7e739a5e244..704e834e96d 100644 --- a/doc/_extensions/zephyr/external_content.py +++ b/doc/_extensions/zephyr/external_content.py @@ -32,15 +32,14 @@ Configuration options import filecmp import os -from pathlib import Path import re import shutil import tempfile -from typing import Dict, Any, List, Optional +from pathlib import Path +from typing import Any from sphinx.application import Sphinx - __version__ = "0.1.0" @@ -51,9 +50,9 @@ DEFAULT_DIRECTIVES = ("figure", "image", "include", "literalinclude") def adjust_includes( fname: Path, basepath: Path, - directives: List[str], + directives: list[str], encoding: str, - dstpath: Optional[Path] = None, + dstpath: Path | None = None, ) -> None: """Adjust included content paths. @@ -162,7 +161,7 @@ def sync_contents(app: Sphinx) -> None: file.unlink() -def setup(app: Sphinx) -> Dict[str, Any]: +def setup(app: Sphinx) -> dict[str, Any]: app.add_config_value("external_content_contents", [], "env") app.add_config_value("external_content_directives", DEFAULT_DIRECTIVES, "env") app.add_config_value("external_content_keep", [], "") diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index d367100812e..67998cd4382 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -33,26 +33,25 @@ Configuration options for, e.g., auto-generated pages not in Git. """ -from functools import partial import os import re import subprocess import sys from datetime import datetime +from functools import partial from pathlib import Path from textwrap import dedent -from typing import Final, Optional, Tuple +from typing import Final from urllib.parse import quote from sphinx.application import Sphinx from sphinx.util.i18n import format_date -ZEPHYR_BASE : Final[str] = Path(__file__).parents[3] -SCRIPTS : Final[str] = ZEPHYR_BASE / "scripts" -sys.path.insert(0, str(SCRIPTS)) +sys.path.insert(0, str(Path(__file__).parents[3] / "scripts")) from get_maintainer import Maintainers +ZEPHYR_BASE : Final[str] = Path(__file__).parents[3] MAINTAINERS : Final[Maintainers] = Maintainers(filename=f"{ZEPHYR_BASE}/MAINTAINERS.yml") @@ -90,7 +89,7 @@ def get_page_prefix(app: Sphinx, pagename: str) -> str: return found_prefix -def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[str]: +def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> str | None: """Obtain GitHub URL for the given page. Args: @@ -117,7 +116,7 @@ def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[ ) -def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optional[str]: +def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> str | None: """Link to open a new Github issue regarding "pagename" with title, body, and labels already pre-filled with useful information. @@ -164,7 +163,7 @@ def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optiona return f"{app.config.gh_link_base_url}/issues/new?title={title}&labels={labels}&body={body}" -def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: +def git_info_filter(app: Sphinx, pagename) -> tuple[str, str] | None: """Return a tuple with the date and SHA1 of the last commit made to a page. Arguments: diff --git a/doc/_extensions/zephyr/kconfig/__init__.py b/doc/_extensions/zephyr/kconfig/__init__.py index 905376d8168..fe037d1c894 100644 --- a/doc/_extensions/zephyr/kconfig/__init__.py +++ b/doc/_extensions/zephyr/kconfig/__init__.py @@ -33,10 +33,11 @@ import json import os import re import sys +from collections.abc import Iterable from itertools import chain from pathlib import Path from tempfile import TemporaryDirectory -from typing import Any, Dict, Iterable, List, Optional, Tuple +from typing import Any from docutils import nodes from sphinx.addnodes import pending_xref @@ -53,22 +54,19 @@ from sphinx.util.nodes import make_refnode __version__ = "0.1.0" -RESOURCES_DIR = Path(__file__).parent / "static" -ZEPHYR_BASE = Path(__file__).parents[4] - -SCRIPTS = ZEPHYR_BASE / "scripts" -sys.path.insert(0, str(SCRIPTS)) - -KCONFIGLIB = SCRIPTS / "kconfig" -sys.path.insert(0, str(KCONFIGLIB)) +sys.path.insert(0, str(Path(__file__).parents[4] / "scripts")) +sys.path.insert(0, str(Path(__file__).parents[4] / "scripts/kconfig")) import kconfiglib import list_boards import list_hardware import zephyr_module +RESOURCES_DIR = Path(__file__).parent / "static" +ZEPHYR_BASE = Path(__file__).parents[4] -def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: + +def kconfig_load(app: Sphinx) -> tuple[kconfiglib.Kconfig, dict[str, str]]: """Load Kconfig""" with TemporaryDirectory() as td: modules = zephyr_module.parse_modules(ZEPHYR_BASE) @@ -131,7 +129,7 @@ def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: # base environment os.environ["ZEPHYR_BASE"] = str(ZEPHYR_BASE) - os.environ["srctree"] = str(ZEPHYR_BASE) + os.environ["srctree"] = str(ZEPHYR_BASE) # noqa: SIM112 os.environ["KCONFIG_DOC_MODE"] = "1" os.environ["KCONFIG_BINARY_DIR"] = td @@ -232,13 +230,12 @@ class KconfigDomain(Domain): object_types = {"option": ObjType("option", "option")} roles = {"option": XRefRole()} directives = {"search": KconfigSearch} - initial_data: Dict[str, Any] = {"options": set()} + initial_data: dict[str, Any] = {"options": set()} - def get_objects(self) -> Iterable[Tuple[str, str, str, str, str, int]]: - for obj in self.data["options"]: - yield obj + def get_objects(self) -> Iterable[tuple[str, str, str, str, str, int]]: + yield from self.data["options"] - def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: + def merge_domaindata(self, docnames: list[str], otherdata: dict) -> None: self.data["options"].update(otherdata["options"]) def resolve_xref( @@ -250,7 +247,7 @@ class KconfigDomain(Domain): target: str, node: pending_xref, contnode: nodes.Element, - ) -> Optional[nodes.Element]: + ) -> nodes.Element | None: match = [ (docname, anchor) for name, _, _, docname, anchor, _ in self.get_objects() @@ -443,8 +440,8 @@ def kconfig_install( app: Sphinx, pagename: str, templatename: str, - context: Dict, - doctree: Optional[nodes.Node], + context: dict, + doctree: nodes.Node | None, ) -> None: """Install the Kconfig library files on pages that require it.""" if ( diff --git a/doc/_extensions/zephyr/link-roles.py b/doc/_extensions/zephyr/link-roles.py index be82226bd57..64877b63830 100644 --- a/doc/_extensions/zephyr/link-roles.py +++ b/doc/_extensions/zephyr/link-roles.py @@ -4,14 +4,14 @@ # based on http://protips.readthedocs.io/link-roles.html -from __future__ import print_function -from __future__ import unicode_literals import re import subprocess -from docutils import nodes +from collections.abc import Sequence from pathlib import Path +from typing import Any, Final + +from docutils import nodes from sphinx.util import logging -from typing import Final ZEPHYR_BASE: Final[str] = Path(__file__).parents[3] @@ -58,8 +58,17 @@ def setup(app): def modulelink(default_module=None, format="blob"): - def role(name, rawtext, text, lineno, inliner, options={}, content=[]): - # Set default values + def role( + name: str, + rawtext: str, + text: str, + lineno: int, + inliner, + options: dict[str, Any] | None = None, + content: Sequence[str] = (), + ): + if options is None: + options = {} module = default_module rev = get_github_rev() config = inliner.document.settings.env.app.config @@ -110,11 +119,10 @@ def modulelink(default_module=None, format="blob"): if not any( p.match(glob) for glob in config.link_roles_manifest_project_broken_links_ignore_globs - ): - if not Path(ZEPHYR_BASE, link).exists(): - logger.warning( - f"{link} not found in {config.link_roles_manifest_project} {trace}" - ) + ) and not Path(ZEPHYR_BASE, link).exists(): + logger.warning( + f"{link} not found in {config.link_roles_manifest_project} {trace}" + ) url = f"{baseurl}/{format}/{rev}/{link}" node = nodes.reference(rawtext, link_text, refuri=url, **options) diff --git a/doc/_extensions/zephyr/manifest_projects_table.py b/doc/_extensions/zephyr/manifest_projects_table.py index 0eaa06d45cf..2fc7069c004 100644 --- a/doc/_extensions/zephyr/manifest_projects_table.py +++ b/doc/_extensions/zephyr/manifest_projects_table.py @@ -27,7 +27,7 @@ SPDX-License-Identifier: Apache-2.0 """ import re -from typing import Any, Dict, List +from typing import Any from docutils import nodes from docutils.parsers.rst import directives @@ -35,7 +35,6 @@ from sphinx.application import Sphinx from sphinx.util.docutils import SphinxDirective from west.manifest import Manifest - __version__ = "0.1.0" @@ -67,7 +66,7 @@ class ManifestProjectsTable(SphinxDirective): return f"{base_url}/releases/tag/{rev}" - def run(self) -> List[nodes.Element]: + def run(self) -> list[nodes.Element]: active_filter = self.options.get("filter", None) manifest = Manifest.from_file(self.env.config.manifest_projects_table_manifest) @@ -75,11 +74,14 @@ class ManifestProjectsTable(SphinxDirective): for project in manifest.projects: if project.name == "manifest": continue - if active_filter == 'active' and manifest.is_active(project): - projects.append(project) - elif active_filter == 'inactive' and not manifest.is_active(project): - projects.append(project) - elif active_filter == 'all' or active_filter is None: + if ( + active_filter == "active" + and manifest.is_active(project) + or active_filter == "inactive" + and not manifest.is_active(project) + or active_filter == "all" + or active_filter is None + ): projects.append(project) # build table @@ -129,7 +131,7 @@ class ManifestProjectsTable(SphinxDirective): return [table] -def setup(app: Sphinx) -> Dict[str, Any]: +def setup(app: Sphinx) -> dict[str, Any]: app.add_config_value("manifest_projects_table_manifest", None, "env") directives.register_directive("manifest-projects-table", ManifestProjectsTable)