diff --git a/CHANGES b/CHANGES index e3ea8974..9b689978 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,28 @@ $ uv add gp-sphinx --prerelease allow +### Development + +#### Lint toolchain: ruff 0.16 + +Minimum `ruff>=0.16.0` (was unpinned), so contributors and CI agree on +which diagnostics fire. See the +[release announcement](https://astral.sh/blog/ruff-v0.16.0). + +`ruff format` now formats Python code blocks embedded in Markdown, which +reflows snippets in the READMEs and docs pages. Contributors who run the +formatter on an older ruff will see those blocks revert, so upgrade +before committing. + +Linting now runs ruff's default rule set alongside the linters this +workspace picks explicitly. An explicit `select` replaces that default +set rather than adding to it, so the config uses `extend-select`; the +set is much larger than the old selection, and contributors will see +diagnostics from linters the workspace never named. Rules that flag a +deliberate idiom — blind excepts guarding a docs build against foreign +code, `exec` in the suites that synthesise test modules — carry a scoped +per-file ignore with its reasoning in `pyproject.toml`. (#73) + ## gp-sphinx 0.0.1a36 (2026-07-26) gp-sphinx 0.0.1a36 makes a class that documents its fields in an diff --git a/README.md b/README.md index 51a3d73f..b3cb992e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Replace your `docs/conf.py` with: ```python """Sphinx configuration for my-project.""" + from __future__ import annotations from gp_sphinx.config import merge_sphinx_config diff --git a/docs/_ext/package_reference.py b/docs/_ext/package_reference.py index 024b5988..b792ca19 100644 --- a/docs/_ext/package_reference.py +++ b/docs/_ext/package_reference.py @@ -458,10 +458,8 @@ def _repository_url_from_package_json(manifest: dict[str, t.Any]) -> str: return repo if isinstance(repo, dict): url = str(repo.get("url", "")) - if url.startswith("git+"): - url = url[len("git+") :] - if url.endswith(".git"): - url = url[: -len(".git")] + url = url.removeprefix("git+") + url = url.removesuffix(".git") return url return "" @@ -937,14 +935,18 @@ def maturity_badge(maturity: str) -> str: ( "autodoc", "Autodoc extensions", - "Domain-specific autodoc extensions: each adds directives that " - "generate documentation from a particular source-construct family.", + ( + "Domain-specific autodoc extensions: each adds directives that " + "generate documentation from a particular source-construct family." + ), ), ( "ux", "UX components", - "Badge primitives, layout presenters, and other shared " - "rendering helpers consumed by the autodoc family.", + ( + "Badge primitives, layout presenters, and other shared " + "rendering helpers consumed by the autodoc family." + ), ), ( "highlighting", @@ -954,8 +956,10 @@ def maturity_badge(maturity: str) -> str: ( "build-seo", "Build & SEO", - "PEP 517 backends, build orchestration, and crawl-indexing " - "extensions auto-loaded by gp-sphinx when ``docs_url`` is set.", + ( + "PEP 517 backends, build orchestration, and crawl-indexing " + "extensions auto-loaded by gp-sphinx when ``docs_url`` is set." + ), ), ) @@ -1612,10 +1616,12 @@ def _live_signature_markdown(package_name: str) -> str: # in E2). Directives that emit H1 via parse_text_to_nodes do NOT # set the page title — Sphinx's title extraction has already run. lines = [ - f"Public callables in `{record.module_name}` rendered from the " - "running interpreter at docs-build time. Drift between this " - "block and the prose elsewhere on the page indicates a stale " - "docstring or signature comment.", + ( + f"Public callables in `{record.module_name}` rendered from the " + "running interpreter at docs-build time. Drift between this " + "block and the prose elsewhere on the page indicates a stale " + "docstring or signature comment." + ), "", ] for name, sig in pairs: @@ -1693,9 +1699,11 @@ def _kitchen_sink_markdown(package_name: str) -> str: # Body-only: stub supplies anchor + H1 so Sphinx finds a page title. lines = [ - "Every directive and role this package registers, exercised once " - "on the same page — useful as a reference card for downstream " - "authors and as a visual-regression target.", + ( + "Every directive and role this package registers, exercised once " + "on the same page — useful as a reference card for downstream " + "authors and as a visual-regression target." + ), "", ] if directives_seen: @@ -1815,9 +1823,11 @@ def _surface_changelog_markdown(package_name: str) -> str: # Body-only: stub supplies anchor + H1 so Sphinx finds a page title. lines = [ - "Comparison of the package's currently-registered directives, " - "roles, and config values against the snapshot stored at " - f"`docs/_static/surface-snapshots/{package_name}.json`.", + ( + "Comparison of the package's currently-registered directives, " + "roles, and config values against the snapshot stored at " + f"`docs/_static/surface-snapshots/{package_name}.json`." + ), "", ] if not snapshot_path.is_file(): @@ -1928,8 +1938,10 @@ def _package_dependents_markdown(package_name: str) -> str: dependents = _package_dependents(package_name) # Body-only: stub supplies anchor + H1 so Sphinx finds a page title. lines = [ - f"Workspace packages that declare a `{package_name}` dependency in " - "their `pyproject.toml` `[project].dependencies` array.", + ( + f"Workspace packages that declare a `{package_name}` dependency in " + "their `pyproject.toml` `[project].dependencies` array." + ), "", ] if not dependents: diff --git a/docs/_ext/sphinx_demo_builder.py b/docs/_ext/sphinx_demo_builder.py index 9d412765..25d1b53c 100644 --- a/docs/_ext/sphinx_demo_builder.py +++ b/docs/_ext/sphinx_demo_builder.py @@ -21,7 +21,7 @@ from sphinx.roles import XRefRole if t.TYPE_CHECKING: - from collections.abc import Iterator, Set + from collections.abc import Iterator, Set as AbstractSet from docutils import nodes from sphinx.application import Sphinx @@ -49,7 +49,7 @@ def get_target_uri(self, docname: str, typ: str | None = None) -> str: """Return the in-archive URI for a document.""" return f"{docname}.txt" - def prepare_writing(self, docnames: Set[str]) -> None: + def prepare_writing(self, docnames: AbstractSet[str]) -> None: """No writer state is needed for the demo.""" def write_doc(self, docname: str, doctree: nodes.document) -> None: diff --git a/docs/packages/sphinx-vite-builder/how-to.md b/docs/packages/sphinx-vite-builder/how-to.md index cd3d3d86..2272e1ed 100644 --- a/docs/packages/sphinx-vite-builder/how-to.md +++ b/docs/packages/sphinx-vite-builder/how-to.md @@ -33,7 +33,7 @@ SIGKILL teardown on signal / `atexit`. ```python # docs/conf.py extensions = ["sphinx_vite_builder"] -sphinx_vite_builder_mode = "auto" # "auto" | "dev" | "prod" +sphinx_vite_builder_mode = "auto" # "auto" | "dev" | "prod" sphinx_vite_builder_root = "/abs/path/to/web" ``` diff --git a/docs/quickstart.md b/docs/quickstart.md index 6bea04ba..3774d9ae 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -62,6 +62,7 @@ In your project's `docs/conf.py`: ```python """Sphinx configuration for my-project.""" + from __future__ import annotations from gp_sphinx.config import merge_sphinx_config @@ -145,6 +146,7 @@ Create a file `my_module.py` next to your `docs/` directory: ```python """Demo module for the autodoc design system.""" + from __future__ import annotations from typing import Any diff --git a/packages/gp-sphinx/README.md b/packages/gp-sphinx/README.md index 00a31de4..ff05fe85 100644 --- a/packages/gp-sphinx/README.md +++ b/packages/gp-sphinx/README.md @@ -20,6 +20,7 @@ Replace ~300 lines of duplicated `docs/conf.py` with ~10 lines: ```python """Sphinx configuration for my-project.""" + from __future__ import annotations from gp_sphinx.config import merge_sphinx_config diff --git a/packages/sphinx-autodoc-argparse/src/sphinx_autodoc_argparse/domain.py b/packages/sphinx-autodoc-argparse/src/sphinx_autodoc_argparse/domain.py index a5bc02d9..86768e96 100644 --- a/packages/sphinx-autodoc-argparse/src/sphinx_autodoc_argparse/domain.py +++ b/packages/sphinx-autodoc-argparse/src/sphinx_autodoc_argparse/domain.py @@ -34,7 +34,7 @@ from sphinx.util.nodes import make_refnode if t.TYPE_CHECKING: - from collections.abc import Iterable, Iterator, Set + from collections.abc import Iterable, Iterator, Set as AbstractSet from docutils import nodes from docutils.nodes import Element @@ -299,7 +299,7 @@ def clear_doc(self, docname: str) -> None: def merge_domaindata( self, - docnames: Set[str], + docnames: AbstractSet[str], otherdata: dict[str, t.Any], ) -> None: """Merge sibling worker's ``domaindata`` under parallel builds.""" diff --git a/packages/sphinx-autodoc-docutils/src/sphinx_autodoc_docutils/domain.py b/packages/sphinx-autodoc-docutils/src/sphinx_autodoc_docutils/domain.py index 5e94526e..449adfda 100644 --- a/packages/sphinx-autodoc-docutils/src/sphinx_autodoc_docutils/domain.py +++ b/packages/sphinx-autodoc-docutils/src/sphinx_autodoc_docutils/domain.py @@ -36,7 +36,7 @@ from sphinx.util.nodes import make_id, make_refnode if t.TYPE_CHECKING: - from collections.abc import Iterable, Iterator, Set + from collections.abc import Iterable, Iterator, Set as AbstractSet from docutils import nodes from docutils.nodes import Element @@ -303,7 +303,7 @@ def clear_doc(self, docname: str) -> None: def merge_domaindata( self, - docnames: Set[str], + docnames: AbstractSet[str], otherdata: dict[str, t.Any], ) -> None: """Merge sibling worker's ``domaindata`` under parallel builds.""" diff --git a/packages/sphinx-autodoc-fastmcp/README.md b/packages/sphinx-autodoc-fastmcp/README.md index 0faf0acf..f78c0f75 100644 --- a/packages/sphinx-autodoc-fastmcp/README.md +++ b/packages/sphinx-autodoc-fastmcp/README.md @@ -33,7 +33,11 @@ fastmcp_area_map = { } fastmcp_model_module = "myproject.models" fastmcp_model_classes = {"SessionInfo", "WindowInfo"} -fastmcp_section_badge_map = {"Inspect": "readonly", "Act": "mutating", "Destroy": "destructive"} +fastmcp_section_badge_map = { + "Inspect": "readonly", + "Act": "mutating", + "Destroy": "destructive", +} fastmcp_section_badge_pages = {"tools/index", "index"} fastmcp_collector_mode = "register" # or "introspect" ``` diff --git a/packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_transforms.py b/packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_transforms.py index 5cd74d69..21b597ff 100644 --- a/packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_transforms.py +++ b/packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_transforms.py @@ -22,8 +22,6 @@ from sphinx.application import Sphinx from sphinx.domains.python import PythonDomain - pass - logger = sphinx_logging.getLogger(__name__) _PARAMETER_FIELD_LABELS = frozenset( diff --git a/packages/sphinx-autodoc-sphinx/src/sphinx_autodoc_sphinx/domain.py b/packages/sphinx-autodoc-sphinx/src/sphinx_autodoc_sphinx/domain.py index 7a3f605f..5d7a816d 100644 --- a/packages/sphinx-autodoc-sphinx/src/sphinx_autodoc_sphinx/domain.py +++ b/packages/sphinx-autodoc-sphinx/src/sphinx_autodoc_sphinx/domain.py @@ -36,7 +36,7 @@ from sphinx.util.nodes import make_id, make_refnode if t.TYPE_CHECKING: - from collections.abc import Iterable, Iterator, Set + from collections.abc import Iterable, Iterator, Set as AbstractSet from docutils import nodes from docutils.nodes import Element @@ -268,7 +268,7 @@ def clear_doc(self, docname: str) -> None: def merge_domaindata( self, - docnames: Set[str], + docnames: AbstractSet[str], otherdata: dict[str, t.Any], ) -> None: """Merge sibling worker's ``domaindata`` under parallel builds.""" diff --git a/packages/sphinx-autodoc-typehints-gp/src/sphinx_autodoc_typehints_gp/_field_xref_transform.py b/packages/sphinx-autodoc-typehints-gp/src/sphinx_autodoc_typehints_gp/_field_xref_transform.py index 3bfdaaf8..f94b04c0 100644 --- a/packages/sphinx-autodoc-typehints-gp/src/sphinx_autodoc_typehints_gp/_field_xref_transform.py +++ b/packages/sphinx-autodoc-typehints-gp/src/sphinx_autodoc_typehints_gp/_field_xref_transform.py @@ -274,7 +274,7 @@ def _is_em_dash_separator(text: str) -> bool: False """ stripped = text.lstrip() - return stripped.startswith(_EN_DASH + " ") or stripped.startswith("-- ") + return stripped.startswith((_EN_DASH + " ", "-- ")) _PROSE_FIELD_TOKENS: t.Final = ( diff --git a/packages/sphinx-gp-opengraph/src/sphinx_gp_opengraph/_description.py b/packages/sphinx-gp-opengraph/src/sphinx_gp_opengraph/_description.py index 08dbe3d9..03e7331d 100644 --- a/packages/sphinx-gp-opengraph/src/sphinx_gp_opengraph/_description.py +++ b/packages/sphinx-gp-opengraph/src/sphinx_gp_opengraph/_description.py @@ -26,13 +26,13 @@ from docutils import nodes if t.TYPE_CHECKING: - from collections.abc import Set + from collections.abc import Set as AbstractSet def get_description( doctree: nodes.document, description_length: int, - known_titles: Set[str] = frozenset(), + known_titles: AbstractSet[str] = frozenset(), ) -> str: """Return a plain-text description extracted from ``doctree``. @@ -83,7 +83,7 @@ def __init__( document: nodes.document, *, desc_len: int, - known_titles: Set[str] = frozenset(), + known_titles: AbstractSet[str] = frozenset(), ) -> None: super().__init__(document) self.description = "" diff --git a/packages/sphinx-ux-badges/README.md b/packages/sphinx-ux-badges/README.md index e2596825..556ce8f6 100644 --- a/packages/sphinx-ux-badges/README.md +++ b/packages/sphinx-ux-badges/README.md @@ -27,13 +27,15 @@ Then build badges in your directives or transforms: ```python from sphinx_ux_badges import build_badge, build_badge_group, build_toolbar -group = build_badge_group([ - build_badge( - "readonly", - tooltip="Read-only", - classes=["gp-sphinx-fastmcp__safety-readonly"], - ), -]) +group = build_badge_group( + [ + build_badge( + "readonly", + tooltip="Read-only", + classes=["gp-sphinx-fastmcp__safety-readonly"], + ), + ] +) ``` ## Documentation diff --git a/packages/sphinx-vite-builder/README.md b/packages/sphinx-vite-builder/README.md index 59879755..9f45f212 100644 --- a/packages/sphinx-vite-builder/README.md +++ b/packages/sphinx-vite-builder/README.md @@ -156,7 +156,7 @@ during `sphinx-build` (one-shot) and `sphinx-autobuild` (watched). ```python # docs/conf.py extensions = ["sphinx_vite_builder"] -sphinx_vite_builder_mode = "auto" # "auto" | "dev" | "prod" +sphinx_vite_builder_mode = "auto" # "auto" | "dev" | "prod" sphinx_vite_builder_root = "/abs/path/to/web" ``` diff --git a/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/process.py b/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/process.py index d3fb7418..40f05706 100644 --- a/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/process.py +++ b/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/process.py @@ -38,9 +38,6 @@ import sys import typing as t -if t.TYPE_CHECKING: - pass - _module_logger = logging.getLogger(__name__) diff --git a/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/vite.py b/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/vite.py index 60580f5a..6b3bcc2a 100644 --- a/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/vite.py +++ b/packages/sphinx-vite-builder/src/sphinx_vite_builder/_internal/vite.py @@ -22,7 +22,6 @@ import pathlib import shutil import textwrap -import typing as t from .bus import AsyncioBus from .errors import ( @@ -395,9 +394,3 @@ def run_vite_build( "vite_build_command", "vite_watch_command", ) - - -# Re-exports for type-checker friendliness when consumers import -# the orchestration module directly. -_AsyncProcess: t.TypeAlias = AsyncProcess -_AsyncioBus: t.TypeAlias = AsyncioBus diff --git a/pyproject.toml b/pyproject.toml index 4a9541fc..92410129 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dev = [ "coverage", "pytest-cov", # Lint - "ruff", + "ruff>=0.16.0", "mypy", "tomli; python_version < '3.11'", "typing-extensions", @@ -141,7 +141,10 @@ extend-exclude = [ ] [tool.ruff.lint] -select = [ +# `select` is deliberately unset: ruff 0.16 enables a curated default rule +# set, and an explicit `select` would replace it rather than extend it. +# `extend-select` layers this project's additional linters on top. +extend-select = [ "E", # pycodestyle "F", # pyflakes "I", # isort @@ -158,7 +161,7 @@ select = [ "PERF", # Perflint "RUF", # Ruff-specific rules "D", # pydocstyle - "FA100", # future annotations + "FA100", # future annotations ] ignore = [ "COM812", # missing trailing comma, ruff format conflict @@ -213,6 +216,47 @@ convention = "numpy" "tests/ext/api_style/*.py" = ["D", "E501", "UP", "A", "B", "COM", "EM", "TRY", "PERF", "RUF", "SIM", "FA100"] "tests/ext/fastmcp/*.py" = ["D", "E501", "UP", "A", "B", "COM", "EM", "TRY", "PERF", "RUF", "SIM", "FA100"] "tests/ext/docutils/*.py" = ["D", "E501", "UP", "A", "B", "COM", "EM", "TRY", "PERF", "RUF", "SIM", "FA100"] +# BLE001: these modules sit on a boundary where the other side is +# arbitrary user or third-party code — introspecting a documented +# project's modules, stringifying whatever annotation autodoc hands +# over, asking Sphinx's builder to resolve a URI, importing a user's +# argparse parser factory, reading intersphinx's untyped inventory. +# Each catch degrades to a fallback or a reported docutils error so one +# bad object cannot abort the whole docs build; narrowing them would let +# an exotic exception from foreign code escape and do exactly that. +"packages/gp-sphinx/src/gp_sphinx/config.py" = ["BLE001"] +"packages/sphinx-autodoc-argparse/src/sphinx_autodoc_argparse/directive.py" = ["BLE001"] +"packages/sphinx-autodoc-fastmcp/src/sphinx_autodoc_fastmcp/_directives.py" = ["BLE001"] +"packages/sphinx-autodoc-fastmcp/src/sphinx_autodoc_fastmcp/_transforms.py" = ["BLE001"] +# S110 rides along on `_store.py`: the intersphinx probe in +# `_resolve_builtin_link` is opportunistic, so a failure there means +# "the inventory has no usable answer" — the same outcome as a miss, and +# the very next statement supplies it from the static +# `PYTEST_BUILTIN_LINKS` map. The `pass` is that fallthrough; logging it +# would put a warning a docs author cannot act on into every build. +"packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_store.py" = ["BLE001", "S110"] +"packages/sphinx-autodoc-typehints-gp/src/sphinx_autodoc_typehints_gp/rendering.py" = ["BLE001"] +# S102: these suites compile fixture, annotation, and dataclass source +# strings into throwaway modules so the extensions can be driven against +# shapes that only exist for the test — deferred annotations, positional +# -only fixture params, `TYPE_CHECKING` aliases. The source is a literal +# in the test file, not user input. +"tests/ext/pytest_fixtures/test_sphinx_pytest_fixtures.py" = ["FLY002", "S102"] +"tests/ext/pytest_fixtures/test_type_checking_alias.py" = ["S102"] +"tests/ext/typehints_gp/test_documented_fields.py" = ["S102"] +# PYI046: `_FixtureMarker` is used — `_detection._get_fixture_marker` +# returns it — but the rule only looks inside the defining file, so a +# protocol that is private to the package rather than to the module +# reads as dead to it. Making it public would export an internal +# normalisation detail just to satisfy the check. +"packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_models.py" = ["PYI046"] +# FLY002: both joins assemble line-oriented text — a Python program fed +# to a subprocess here, and the expected RST block that +# `_build_autofixtures_directive_text` emits line by line in +# `test_sphinx_pytest_fixtures.py` above. One literal per output line is +# what keeps them readable and reviewable in a diff; an f-string +# carrying embedded newlines is neither. +"scripts/ci/package_tools.py" = ["FLY002"] [tool.pytest.ini_options] addopts = "-s --tb=short --no-header --showlocals --doctest-modules" diff --git a/tests/_sphinx_scenarios.py b/tests/_sphinx_scenarios.py index 035a7fea..51ac84e9 100644 --- a/tests/_sphinx_scenarios.py +++ b/tests/_sphinx_scenarios.py @@ -65,21 +65,21 @@ | int | float | bool - | None | list["ScenarioInputValue"] | tuple["ScenarioInputValue", ...] | set["ScenarioInputValue"] | frozenset["ScenarioInputValue"] | dict[str, "ScenarioInputValue"] + | None ) FrozenScenarioValue: t.TypeAlias = ( str | int | float | bool - | None | tuple["FrozenScenarioValue", ...] | dict[str, "FrozenScenarioValue"] + | None ) diff --git a/tests/docs/test_docs_policy.py b/tests/docs/test_docs_policy.py index 9ca8d9fb..08cab406 100644 --- a/tests/docs/test_docs_policy.py +++ b/tests/docs/test_docs_policy.py @@ -187,9 +187,9 @@ def test_package_how_to_pages_open_with_concept_prose() -> None: for path in sorted((DOCS_ROOT / "packages").glob("*/how-to.md")): for line in path.read_text(encoding="utf-8").splitlines(): stripped = line.strip() - if not stripped or stripped.startswith("(") or stripped.startswith("#"): + if not stripped or stripped.startswith(("(", "#")): continue - if stripped.startswith("```") or stripped.startswith("::::"): + if stripped.startswith(("```", "::::")): offenders.append(str(path.relative_to(REPO_ROOT))) break diff --git a/tests/ext/badges/test_palettes.py b/tests/ext/badges/test_palettes.py index 657e6709..981a827c 100644 --- a/tests/ext/badges/test_palettes.py +++ b/tests/ext/badges/test_palettes.py @@ -26,12 +26,12 @@ _VAR_REFERENCE = re.compile(r"var\((--gp-sphinx-badge-[\w-]+)\)") _TOKEN_SUFFIX = re.compile(r"-(bg|fg|border)$") -_ROOT_BLOCK = re.compile(r":root \{(.*?)\n\}", re.S) +_ROOT_BLOCK = re.compile(r":root \{(.*?)\n\}", re.DOTALL) _MEDIA_DARK_BLOCK = re.compile( r"@media \(prefers-color-scheme: dark\) \{(.*?)\n\}\n", - re.S, + re.DOTALL, ) -_BODY_DARK_BLOCK = re.compile(r'\nbody\[data-theme="dark"\] \{(.*?)\n\}', re.S) +_BODY_DARK_BLOCK = re.compile(r'\nbody\[data-theme="dark"\] \{(.*?)\n\}', re.DOTALL) def _palette_css() -> str: diff --git a/tests/ext/pytest_fixtures/test_sphinx_pytest_fixtures.py b/tests/ext/pytest_fixtures/test_sphinx_pytest_fixtures.py index de992cc9..6e574fc8 100644 --- a/tests/ext/pytest_fixtures/test_sphinx_pytest_fixtures.py +++ b/tests/ext/pytest_fixtures/test_sphinx_pytest_fixtures.py @@ -1304,8 +1304,10 @@ def _record_warning(message: str, *args: t.Any, **_kwargs: t.Any) -> None: assert result is None assert warning_calls == [ ( - "auto-pytest-plugin found no pytest fixtures in %r; " - "skipping generated fixture sections", + ( + "auto-pytest-plugin found no pytest fixtures in %r; " + "skipping generated fixture sections" + ), ("fixture_mod",), ) ] diff --git a/tests/test_gp_furo_theme.py b/tests/test_gp_furo_theme.py index 309521ef..27ed61ad 100644 --- a/tests/test_gp_furo_theme.py +++ b/tests/test_gp_furo_theme.py @@ -12,7 +12,6 @@ import importlib.metadata import pathlib import textwrap -import typing as t import pytest from gp_furo_theme import THEME_NAME, get_theme_path, get_vite_root, setup @@ -25,9 +24,6 @@ read_output, ) -if t.TYPE_CHECKING: - pass - def test_theme_path_exists() -> None: """Theme directory is bundled in the package.""" diff --git a/uv.lock b/uv.lock index 05b25916..fb997347 100644 --- a/uv.lock +++ b/uv.lock @@ -553,7 +553,7 @@ dev = [ { name = "pytest-playwright" }, { name = "pytest-rerunfailures" }, { name = "pytest-watcher" }, - { name = "ruff" }, + { name = "ruff", specifier = ">=0.16.0" }, { name = "sphinx-autobuild" }, { name = "sphinx-autodoc-api-style", editable = "packages/sphinx-autodoc-api-style" }, { name = "sphinx-autodoc-argparse", editable = "packages/sphinx-autodoc-argparse" }, @@ -1460,27 +1460,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/06/ae069393fc66e8ff33036d4b368003833bf6e88ccf182e17e7a2f1c754fd/ruff-0.15.22.tar.gz", hash = "sha256:3f15175b1fb580126f58285a5dae6b2ea89000136d980c64499211f116b54809", size = 4785063, upload-time = "2026-07-16T15:14:13.244Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/18/ee54b7ae1e121be7a28ea6da4b67564ebb0530e183a54415ab7e3bcd2c4e/ruff-0.15.22-py3-none-linux_armv6l.whl", hash = "sha256:44423e73493737f5e7c5b41d475483898ff37afcdae38bc3da5085e29af1c2d8", size = 10781258, upload-time = "2026-07-16T15:13:19.452Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d2/2520cb14761ddbeaf57642a76942fc36adcbdbe53b4532241995f6fc485c/ruff-0.15.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b82c6482946e9eda7ff2e091d25b8bad3f718684e1916d41bd56873cee05b697", size = 10999477, upload-time = "2026-07-16T15:13:23.318Z" }, - { url = "https://files.pythonhosted.org/packages/c9/10/74e53572aa758dfaa678c2a2646b5c5515d884b7ca56be4d2ce03ca4b560/ruff-0.15.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:11c1c715af53a09f714e011106bffc419751ec8232fcb5da42173284ea3fec6f", size = 10466716, upload-time = "2026-07-16T15:13:26.162Z" }, - { url = "https://files.pythonhosted.org/packages/1e/cc/44eaaf0844e028182f2d0a8f2190d0f359159aed0a9e5ab861d892f1ae2a/ruff-0.15.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742a29cf29bddb7c8327895d6a10e0e6c5b38a96dd407af9b5d0857f809c0576", size = 10892644, upload-time = "2026-07-16T15:13:29.229Z" }, - { url = "https://files.pythonhosted.org/packages/9f/21/8edf559014d2b0f82beea19cfb713993ad802ccda16868769979c6090a84/ruff-0.15.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72af58b951b0ae395935ae79763dc349bc0eb706319d28f7a33ad2cfb3cfc178", size = 10576719, upload-time = "2026-07-16T15:13:32.35Z" }, - { url = "https://files.pythonhosted.org/packages/bf/1e/3a13abd392a3b50b62e5938a831f9ab6e588358cacad5c18545b716d2182/ruff-0.15.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d425005c1835eb24e2ee4161cb90e8db263415f4a71c8c72c33abaa6c0c224", size = 11376494, upload-time = "2026-07-16T15:13:35.958Z" }, - { url = "https://files.pythonhosted.org/packages/bf/3e/422d3d95bcf04dd78e1aeac22184d4f9a8fb2c01865d39d44618484a0317/ruff-0.15.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b9b3f8779a4f08c969defc3c8c35abffaa757e601ed5ae66d6d1db6519969a", size = 12208370, upload-time = "2026-07-16T15:13:39.185Z" }, - { url = "https://files.pythonhosted.org/packages/1e/91/5d065a0e0a02bf4813f5119ad278462eed081d2b832eb7c021ade0ec9e65/ruff-0.15.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e0dd1b2e4d3d585f897a0d137cbf4eaf6223bef4e8ce34d6bb12556c5f9249e", size = 11581098, upload-time = "2026-07-16T15:13:42.132Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f9/a0d4871d12fae702eb1f41b686caf05f1f8b124dc6db6f784f53d74918fa/ruff-0.15.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365523eb91d9224e1bcb03b022fbf0facb8f9e23792a2c53d9d4b3924bdbdebb", size = 11399422, upload-time = "2026-07-16T15:13:45.2Z" }, - { url = "https://files.pythonhosted.org/packages/18/80/c843a5176cddbceb0b7e8dd41cf9993490796c1c469348d384f5a5c13c56/ruff-0.15.22-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fabfd168afdf29fee5be98b831efa9683c94d7c5a3b58b9ce5a2e38444589a74", size = 11381683, upload-time = "2026-07-16T15:13:48.46Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/8485de0ae92239438a36cfc51350db9b9e85c9ebdfaea91b18e422706662/ruff-0.15.22-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:225dbf095a87f1d9f90f5fd7924d2613ee452a75a4308c63a8f50f761787aa7c", size = 10850295, upload-time = "2026-07-16T15:13:51.655Z" }, - { url = "https://files.pythonhosted.org/packages/fa/91/24977ec2ec72eaf15e4394ace2959fdff2dd1e14f03e005e838023407169/ruff-0.15.22-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1877d63b9d24ed278744f1523fd11b85540566d54641f97c566d7d9dc5ca5296", size = 10579640, upload-time = "2026-07-16T15:13:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/9c/47/9b51216951974df1f263ac19da550d34252e0ed7218c25f10c5ef9ed7517/ruff-0.15.22-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1606c510bd7215680d32efab38965f7cdec3ef69f5170a3f4791404ffdd5262", size = 11105077, upload-time = "2026-07-16T15:13:57.915Z" }, - { url = "https://files.pythonhosted.org/packages/c2/47/20e9d4a3b8016778acea5fc32bb50d35d207500a17ddb529ffa6996feef8/ruff-0.15.22-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:630479b18625f5ffc373f77603a22a9f8ac0acd7ff0501178b5db28ec71e9c64", size = 11490980, upload-time = "2026-07-16T15:14:01.032Z" }, - { url = "https://files.pythonhosted.org/packages/4d/76/3f72d8fc38c1cb77b38c56a70da9d0c17700cc1cc50f9649c9d3c8f5ba71/ruff-0.15.22-py3-none-win32.whl", hash = "sha256:e5ba0e4a13fd14abbed2a77b517a3911290c6c6c59ef67784328d1668fab76cf", size = 10789165, upload-time = "2026-07-16T15:14:04.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/46/4965251734c2b6fcdca1b1b187d20bcac3af0ee5b083b89c910bb961ce3a/ruff-0.15.22-py3-none-win_amd64.whl", hash = "sha256:9be63ba1eb936acd2d1342fb8337c356353706fce233b2a15a09a97037e6acde", size = 11938297, upload-time = "2026-07-16T15:14:07.316Z" }, - { url = "https://files.pythonhosted.org/packages/57/c9/e69b1ff4c8b69093ef08b8919ab767af0569666865b39c30a8795d88d3c6/ruff-0.15.22-py3-none-win_arm64.whl", hash = "sha256:e1168075b72158510839f250027659cdd78476f40507dd517892304c41318661", size = 11298172, upload-time = "2026-07-16T15:14:10.51Z" }, +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz", hash = "sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size = 4790557, upload-time = "2026-07-23T19:11:30.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl", hash = "sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size = 10754633, upload-time = "2026-07-23T19:10:46.415Z" }, + { url = "https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size = 10969164, upload-time = "2026-07-23T19:10:50.271Z" }, + { url = "https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size = 10488846, upload-time = "2026-07-23T19:10:52.639Z" }, + { url = "https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size = 10889729, upload-time = "2026-07-23T19:10:54.89Z" }, + { url = "https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size = 10568275, upload-time = "2026-07-23T19:10:56.993Z" }, + { url = "https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size = 11385112, upload-time = "2026-07-23T19:10:59.615Z" }, + { url = "https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size = 12207008, upload-time = "2026-07-23T19:11:02.154Z" }, + { url = "https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size = 11650842, upload-time = "2026-07-23T19:11:04.557Z" }, + { url = "https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size = 11400718, upload-time = "2026-07-23T19:11:09.233Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size = 11426177, upload-time = "2026-07-23T19:11:11.994Z" }, + { url = "https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size = 10856126, upload-time = "2026-07-23T19:11:14.221Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size = 10571208, upload-time = "2026-07-23T19:11:16.378Z" }, + { url = "https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size = 11063329, upload-time = "2026-07-23T19:11:19.173Z" }, + { url = "https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size = 11489751, upload-time = "2026-07-23T19:11:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl", hash = "sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size = 10785885, upload-time = "2026-07-23T19:11:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl", hash = "sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size = 11923141, upload-time = "2026-07-23T19:11:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl", hash = "sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size = 11273407, upload-time = "2026-07-23T19:11:28.705Z" }, ] [[package]]