From 5746d62f7561ada4e856de87311679dfa811563a Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Tue, 28 Jul 2026 09:27:11 -0400 Subject: [PATCH] Fixes for ruff 16 --- yardang/__init__.py | 2 +- yardang/build.py | 84 ++++++++++++++++++----------------- yardang/cli.py | 81 +++++++++++++++++---------------- yardang/tests/test_all.py | 21 +++++++++ yardang/tests/test_breathe.py | 2 +- yardang/tests/test_wiki.py | 17 +++++++ yardang/wiki.py | 45 +++++++++---------- 7 files changed, 145 insertions(+), 107 deletions(-) diff --git a/yardang/__init__.py b/yardang/__init__.py index d7a2789..1ca5635 100644 --- a/yardang/__init__.py +++ b/yardang/__init__.py @@ -7,6 +7,6 @@ "BUNDLED_THEMES", "generate_docs_configuration", "generate_wiki_configuration", - "run_doxygen_if_needed", "process_wiki_output", + "run_doxygen_if_needed", ) diff --git a/yardang/build.py b/yardang/build.py index 081f535..55aca54 100644 --- a/yardang/build.py +++ b/yardang/build.py @@ -1,23 +1,23 @@ import os.path import shutil import subprocess +from collections.abc import Callable from contextlib import contextmanager from pathlib import Path from tempfile import TemporaryDirectory -from typing import Callable, Dict, List, Optional, Union from jinja2 import Environment, FileSystemLoader from .utils import get_config, get_config_flex -__all__ = ("generate_docs_configuration", "run_doxygen_if_needed", "generate_wiki_configuration", "BUNDLED_THEMES") +__all__ = ("BUNDLED_THEMES", "generate_docs_configuration", "generate_wiki_configuration", "run_doxygen_if_needed") # Themes for which yardang ships per-theme defaults (a bundled ``{theme}.css`` and/or # an optional dependency). Used as the default set for ``yardang preview``. BUNDLED_THEMES = ("furo", "sphinxawesome_theme", "shibuya") -def _resolve_custom_asset(value: Optional[Union[str, Path]], theme: Optional[str], extension: str, *, assets_dir: Path) -> Optional[str]: +def _resolve_custom_asset(value: str | Path | None, theme: str | None, extension: str, *, assets_dir: Path) -> str | None: """Resolve custom CSS/JS content for the docs build. Resolution precedence: @@ -48,11 +48,11 @@ def _resolve_custom_asset(value: Optional[Union[str, Path]], theme: Optional[str def run_doxygen_if_needed( - breathe_projects: Dict[str, str], + breathe_projects: dict[str, str], *, force: bool = False, quiet: bool = False, -) -> Dict[str, bool]: +) -> dict[str, bool]: """Run doxygen for breathe projects if needed. For each project in breathe_projects, checks if the XML output directory @@ -112,19 +112,23 @@ def run_doxygen_if_needed( if not quiet: print(f"Running doxygen for project '{project_name}'...") - kwargs = {"cwd": doxyfile_path.parent} if quiet: - kwargs["stdout"] = subprocess.DEVNULL - kwargs["stderr"] = subprocess.DEVNULL - - result = subprocess.run([doxygen_path], **kwargs) + result = subprocess.run( + [doxygen_path], + cwd=doxyfile_path.parent, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=False, + ) + else: + result = subprocess.run([doxygen_path], cwd=doxyfile_path.parent, check=False) results[project_name] = result.returncode == 0 if not quiet and result.returncode == 0: print(f" Generated XML documentation in {xml_dir}") elif not quiet: print(f" Doxygen failed with return code {result.returncode}") - except Exception as e: + except OSError as e: if not quiet: print(f" Error running doxygen: {e}") results[project_name] = False @@ -135,27 +139,27 @@ def run_doxygen_if_needed( @contextmanager def generate_docs_configuration( *, - project: Optional[str] = None, - title: Optional[str] = None, - module: Optional[str] = None, - description: Optional[str] = None, - author: Optional[str] = None, - copyright: Optional[str] = None, - version: Optional[str] = None, - theme: Optional[str] = None, - docs_root: Optional[str] = None, - root: Optional[str] = None, - cname: Optional[str] = None, - pages: Optional[List] = None, - use_autoapi: Optional[bool] = None, - autoapi_ignore: Optional[List] = None, - custom_css: Optional[Path] = None, - custom_js: Optional[Path] = None, - html_output_dir: Optional[str] = None, - config_base: Optional[str] = None, - previous_versions: Optional[bool] = False, - adjust_arguments: Callable = None, - adjust_template: Callable = None, + project: str | None = None, + title: str | None = None, + module: str | None = None, + description: str | None = None, + author: str | None = None, + copyright: str | None = None, + version: str | None = None, + theme: str | None = None, + docs_root: str | None = None, + root: str | None = None, + cname: str | None = None, + pages: list | None = None, + use_autoapi: bool | None = None, + autoapi_ignore: list | None = None, + custom_css: Path | None = None, + custom_js: Path | None = None, + html_output_dir: str | None = None, + config_base: str | None = None, + previous_versions: bool | None = False, + adjust_arguments: Callable | None = None, + adjust_template: Callable | None = None, ): """Generate Sphinx documentation configuration from pyproject.toml. @@ -651,15 +655,15 @@ def generate_wiki_configuration( docs_root: str = "", root: str = "", cname: str = "", - pages: Optional[List] = None, - use_autoapi: Optional[bool] = None, - autoapi_ignore: Optional[List] = None, - custom_css: Optional[Path] = None, - custom_js: Optional[Path] = None, + pages: list | None = None, + use_autoapi: bool | None = None, + autoapi_ignore: list | None = None, + custom_css: Path | None = None, + custom_js: Path | None = None, config_base: str = "tool.yardang", - previous_versions: Optional[bool] = False, - adjust_arguments: Callable = None, - adjust_template: Callable = None, + previous_versions: bool | None = False, + adjust_arguments: Callable | None = None, + adjust_template: Callable | None = None, ): """Generate Sphinx configuration for GitHub Wiki markdown output. diff --git a/yardang/cli.py b/yardang/cli.py index 5a7f02b..244bb96 100644 --- a/yardang/cli.py +++ b/yardang/cli.py @@ -3,7 +3,6 @@ from subprocess import Popen from sys import executable, stderr, stdout from time import sleep -from typing import List, Optional from typer import Exit, Typer @@ -17,24 +16,24 @@ def build( quiet: bool = False, debug: bool = False, pdb: bool = False, - project: Optional[str] = None, - title: Optional[str] = None, - module: Optional[str] = None, - description: Optional[str] = None, - author: Optional[str] = None, - copyright: Optional[str] = None, - version: Optional[str] = None, - theme: Optional[str] = None, - docs_root: Optional[str] = None, - root: Optional[str] = None, - cname: Optional[str] = None, - pages: Optional[List[Path]] = None, - use_autoapi: Optional[bool] = None, - custom_css: Optional[Path] = None, - custom_js: Optional[Path] = None, + project: str | None = None, + title: str | None = None, + module: str | None = None, + description: str | None = None, + author: str | None = None, + copyright: str | None = None, + version: str | None = None, + theme: str | None = None, + docs_root: str | None = None, + root: str | None = None, + cname: str | None = None, + pages: list[Path] | None = None, + use_autoapi: bool | None = None, + custom_css: Path | None = None, + custom_js: Path | None = None, output: str = "docs/html", - config_base: Optional[str] = "tool.yardang", - previous_versions: Optional[bool] = False, + config_base: str | None = "tool.yardang", + previous_versions: bool | None = False, ): with generate_docs_configuration( project=project, @@ -76,9 +75,9 @@ def build( sleep(0.1) if process.returncode != 0: if pdb: - import pdb + import pdb # noqa: T100 - pdb.set_trace() + pdb.set_trace() # noqa: T100 raise Exit(process.returncode) @@ -91,24 +90,24 @@ def wiki( quiet: bool = False, debug: bool = False, pdb: bool = False, - project: Optional[str] = None, - title: Optional[str] = None, - module: Optional[str] = None, - description: Optional[str] = None, - author: Optional[str] = None, - copyright: Optional[str] = None, - version: Optional[str] = None, - theme: Optional[str] = None, - docs_root: Optional[str] = None, - root: Optional[str] = None, - cname: Optional[str] = None, - pages: Optional[List[Path]] = None, - use_autoapi: Optional[bool] = None, - custom_css: Optional[Path] = None, - custom_js: Optional[Path] = None, - config_base: Optional[str] = "tool.yardang", - previous_versions: Optional[bool] = False, - output_dir: Optional[str] = None, + project: str | None = None, + title: str | None = None, + module: str | None = None, + description: str | None = None, + author: str | None = None, + copyright: str | None = None, + version: str | None = None, + theme: str | None = None, + docs_root: str | None = None, + root: str | None = None, + cname: str | None = None, + pages: list[Path] | None = None, + use_autoapi: bool | None = None, + custom_css: Path | None = None, + custom_js: Path | None = None, + config_base: str | None = "tool.yardang", + previous_versions: bool | None = False, + output_dir: str | None = None, skip_postprocess: bool = False, ): """Generate GitHub Wiki compatible markdown documentation. @@ -174,9 +173,9 @@ def wiki( sleep(0.1) if process.returncode != 0: if pdb: - import pdb + import pdb # noqa: T100 - pdb.set_trace() + pdb.set_trace() # noqa: T100 raise Exit(process.returncode) # Post-process for GitHub Wiki compatibility @@ -205,7 +204,7 @@ def wiki( def preview( *, - themes: Optional[List[str]] = None, + themes: list[str] | None = None, output: str = "docs/html/_previews", quiet: bool = False, debug: bool = False, diff --git a/yardang/tests/test_all.py b/yardang/tests/test_all.py index 0b89b6f..ce9a8a0 100644 --- a/yardang/tests/test_all.py +++ b/yardang/tests/test_all.py @@ -1,6 +1,9 @@ import os from pathlib import Path +import pytest +from typer import Exit + from yardang.build import generate_docs_configuration from yardang.cli import build, debug from yardang.utils import get_config_flex @@ -16,6 +19,24 @@ def test_cli(): debug() +def test_cli_pdb_on_failure(monkeypatch): + class FailedProcess: + returncode = 1 + + @staticmethod + def poll(): + return 1 + + traced = [] + monkeypatch.setattr("yardang.cli.Popen", lambda *_args, **_kwargs: FailedProcess()) + monkeypatch.setattr("pdb.set_trace", lambda: traced.append(True)) + + with pytest.raises(Exit): + build(pdb=True) + + assert traced == [True] + + class TestUseAutoapi: """Tests for use_autoapi parameter handling.""" diff --git a/yardang/tests/test_breathe.py b/yardang/tests/test_breathe.py index 4efc820..afaaaa6 100644 --- a/yardang/tests/test_breathe.py +++ b/yardang/tests/test_breathe.py @@ -431,7 +431,7 @@ class MockResult: monkeypatch.setattr(subprocess, "run", mock_run) - result = run_doxygen_if_needed({"mylib": str(xml_dir)}, quiet=True) + result = run_doxygen_if_needed({"mylib": str(xml_dir)}) assert result == {"mylib": True} assert len(run_called) == 1 assert run_called[0][1] == tmp_path # cwd should be Doxyfile's parent diff --git a/yardang/tests/test_wiki.py b/yardang/tests/test_wiki.py index fd97eed..0fd41d6 100644 --- a/yardang/tests/test_wiki.py +++ b/yardang/tests/test_wiki.py @@ -167,6 +167,23 @@ def test_get_page_title_index_becomes_home(self, tmp_path): title = get_page_title(md_file) assert title == "Home" + def test_get_page_title_missing_file_falls_back_to_filename(self, tmp_path): + from yardang.wiki import get_page_title + + title = get_page_title(tmp_path / "missing-page.md") + + assert title == "Missing Page" + + def test_extract_toctree_entries(self): + from yardang.wiki import extract_toctree_entries + + content = """```{toctree} +--- +overview +```""" + + assert extract_toctree_entries(content) == [(None, "overview")] + def test_convert_filename_to_wiki_format(self): """Test filename conversion for wiki format.""" from yardang.wiki import convert_filename_to_wiki_format diff --git a/yardang/wiki.py b/yardang/wiki.py index 867eb7e..1568bbb 100644 --- a/yardang/wiki.py +++ b/yardang/wiki.py @@ -8,14 +8,13 @@ import re import shutil from pathlib import Path -from typing import Dict, List, Optional, Tuple __all__ = ( - "generate_sidebar", - "generate_footer", "fix_wiki_links", - "process_wiki_output", + "generate_footer", + "generate_sidebar", "get_page_title", + "process_wiki_output", ) @@ -33,16 +32,16 @@ def get_page_title(filepath: Path) -> str: """ try: content = filepath.read_text(encoding="utf-8") - # Look for first H1 heading - match = re.search(r"^#\s+(.+?)(?:\s*\{.*\})?$", content, re.MULTILINE) - if match: - title = match.group(1).strip() - # Remove any remaining markdown formatting - title = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", title) - title = re.sub(r"`([^`]+)`", r"\1", title) - return title - except Exception: - pass + except (OSError, UnicodeError): + content = "" + # Look for first H1 heading + match = re.search(r"^#\s+(.+?)(?:\s*\{.*\})?$", content, re.MULTILINE) + if match: + title = match.group(1).strip() + # Remove any remaining markdown formatting + title = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", title) + title = re.sub(r"`([^`]+)`", r"\1", title) + return title # Fallback to filename name = filepath.stem @@ -74,7 +73,7 @@ def convert_filename_to_wiki_format(filename: str) -> str: return name -def fix_wiki_links(content: str, all_pages: Dict[str, str]) -> str: +def fix_wiki_links(content: str, all_pages: dict[str, str]) -> str: """Fix internal links to use GitHub Wiki format. Converts relative markdown links to GitHub Wiki internal links. @@ -108,8 +107,7 @@ def replace_link(match): anchor = "#" + anchor # Remove .md extension if present - if path.endswith(".md"): - path = path[:-3] + path = path.removesuffix(".md") # Convert path to wiki page name page_name = convert_filename_to_wiki_format(path) @@ -454,7 +452,7 @@ def _is_api_page(filename: str, content: str) -> bool: return indicator_count >= 2 -def extract_toctree_entries(content: str) -> List[Tuple[str, str]]: +def extract_toctree_entries(content: str) -> list[tuple[str, str]]: """Extract toctree entries from markdown content. Parses MyST-style toctree directives to find linked pages. @@ -478,7 +476,7 @@ def extract_toctree_entries(content: str) -> List[Tuple[str, str]]: for line in lines: line = line.strip() # Skip directive header and options - if line.startswith("```") or line.startswith(":") or line.startswith("---"): + if line.startswith(("```", ":", "---")): if line == "---": in_content = True continue @@ -498,7 +496,7 @@ def extract_toctree_entries(content: str) -> List[Tuple[str, str]]: def generate_sidebar( output_dir: Path, - pages: List[str], + pages: list[str], project_name: str = "", *, include_home: bool = True, @@ -549,8 +547,7 @@ def generate_sidebar( # Also try the flattened format (docs-src-overview instead of overview) flattened_name = page_path.replace("/", "-").replace(".md", "") - if flattened_name.startswith("docs-src-"): - flattened_name = flattened_name[9:] # Remove docs-src- prefix for cleaner names + flattened_name = flattened_name.removeprefix("docs-src-") # Remove docs-src- prefix for cleaner names # Try to find the file - check both formats md_file = None @@ -656,7 +653,7 @@ def rename_index_to_home(output_dir: Path) -> None: shutil.move(str(index_file), str(home_file)) -def flatten_directory_structure(output_dir: Path, max_filename_length: int = 200) -> Dict[str, str]: +def flatten_directory_structure(output_dir: Path, max_filename_length: int = 200) -> dict[str, str]: """Flatten nested directory structure for GitHub Wiki. GitHub Wiki doesn't support nested directories, so we need to @@ -743,7 +740,7 @@ def flatten_directory_structure(output_dir: Path, max_filename_length: int = 200 def process_wiki_output( output_dir: Path, - pages: Optional[List[str]] = None, + pages: list[str] | None = None, project_name: str = "", docs_url: str = "", repo_url: str = "",