diff --git a/.copier-answers.yaml b/.copier-answers.yaml index 14233a0..25e287d 100644 --- a/.copier-answers.yaml +++ b/.copier-answers.yaml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: ebb6e1c +_commit: '4372075' _src_path: https://github.com/python-project-templates/base.git add_docs: true add_extension: python diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5514168..ba83c92 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -15,7 +15,7 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: diff --git a/Makefile b/Makefile index 495051b..c02b543 100644 --- a/Makefile +++ b/Makefile @@ -25,16 +25,16 @@ lint-py: ## lint python with ruff python -m ruff format --check sphinx_fuma lint-docs: ## lint docs with mdformat and codespell - python -m mdformat --check README.md docs/src - python -m codespell_lib README.md docs/src + python -m mdformat --check README.md $(wildcard docs/src) + python -m codespell_lib README.md $(wildcard docs/src) fix-py: ## autoformat python code with ruff python -m ruff check --fix sphinx_fuma python -m ruff format sphinx_fuma fix-docs: ## autoformat docs with mdformat and codespell - python -m mdformat README.md docs/src - python -m codespell_lib --write README.md docs/src + python -m mdformat README.md $(wildcard docs/src) + python -m codespell_lib --write README.md $(wildcard docs/src) lint: lint-py lint-docs ## run all linters lints: lint @@ -52,7 +52,7 @@ check-dist: ## check python sdist and wheel with check-dist check-types: ## check python types with ty ty check --python $$(which python) -checks: check-dist +checks: check-dist check-types # Alias check: checks diff --git a/pyproject.toml b/pyproject.toml index 7f6c28a..b7b3df5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ develop = [ "codespell", "hatchling", "mdformat", + "mdformat-frontmatter", "mdformat-tables>=1", "pytest", "pytest-cov", @@ -82,7 +83,7 @@ replace = 'version = "{new_version}"' [tool.coverage.run] branch = true omit = [ - "sphinx_fuma/tests/integration/", + "sphinx_fuma/tests/integration/*", ] [tool.coverage.report] diff --git a/sphinx_fuma/_options.py b/sphinx_fuma/_options.py index 195a115..3eadd76 100644 --- a/sphinx_fuma/_options.py +++ b/sphinx_fuma/_options.py @@ -7,9 +7,26 @@ """ from html import escape +from typing import NotRequired, TypedDict __all__ = ("build_context",) + +class _NavLink(TypedDict): + title: str + url: str + external: NotRequired[bool] + + +class _SidebarTab(TypedDict): + title: str + url: str + description: str + icon: str + match: str + active: bool + + _TRUTHY = {"1", "on", "true", "yes"} _FALSY = {"0", "off", "false", "no", ""} @@ -58,7 +75,7 @@ def _choice(value, allowed: tuple[str, ...], default: str) -> str: return text if text in allowed else default -def _links(value) -> list[dict[str, str]]: +def _links(value) -> list[_NavLink]: """Coerce ``nav_links`` into a list of ``{title, url, external}`` mappings. Accepts a list of mappings, a list of ``(title, url)`` pairs, or a @@ -66,14 +83,13 @@ def _links(value) -> list[dict[str, str]]: """ if not value: return [] + entries: list[_NavLink] = [] if isinstance(value, str): - entries = [] for chunk in value.split(","): title, _, url = chunk.partition("|") if title.strip() and url.strip(): entries.append({"title": title.strip(), "url": url.strip()}) else: - entries = [] for item in value: if isinstance(item, dict): title, url = _text(item.get("title") or item.get("name")), _text(item.get("url") or item.get("href")) @@ -88,7 +104,7 @@ def _links(value) -> list[dict[str, str]]: return entries -def _tabs(value, pagename: str) -> list[dict]: +def _tabs(value, pagename: str) -> list[_SidebarTab]: """Coerce ``sidebar_tabs`` into navigator entries and mark the active one. Accepts a list of mappings with ``title``, ``url`` and optional ``description`` @@ -97,7 +113,7 @@ def _tabs(value, pagename: str) -> list[dict]: """ if not value or isinstance(value, str): return [] - tabs = [] + tabs: list[_SidebarTab] = [] for item in value: if not isinstance(item, dict): continue diff --git a/sphinx_fuma/tests/test_theme.py b/sphinx_fuma/tests/test_theme.py index 81d19c3..9ef090b 100644 --- a/sphinx_fuma/tests/test_theme.py +++ b/sphinx_fuma/tests/test_theme.py @@ -127,15 +127,18 @@ def test_css_overrides_render_both_modes(self): "theme_dark_css_variables": {"--color-fd-primary": "blue"}, } )["fuma_css_overrides"] + assert isinstance(css, str) assert ":root {\n --color-fd-primary: red;\n}\n" in css assert "html.dark {\n --color-fd-primary: blue;\n}\n" in css def test_dark_overrides_also_cover_system_preference(self): css = build_context({"theme_dark_css_variables": {"color-fd-primary": "blue"}})["fuma_css_overrides"] + assert isinstance(css, str) assert "@media (prefers-color-scheme: dark) {\nhtml:not(.light) {" in css def test_no_media_block_without_dark_overrides(self): css = build_context({"theme_light_css_variables": {"color-fd-primary": "red"}})["fuma_css_overrides"] + assert isinstance(css, str) assert "prefers-color-scheme" not in css def test_edit_url_derived_from_github_url(self): @@ -262,6 +265,7 @@ def test_folder_slash_is_stripped_from_the_label(self, built): class TestColorPresets: def test_amber_matches_the_fumadocs_pairing(self): css = build_context({"theme_color_preset": "amber"})["fuma_css_overrides"] + assert isinstance(css, str) assert "--color-fd-primary: #cc8b00;" in css assert "--color-fd-primary: #fff383;" in css @@ -278,6 +282,7 @@ def test_explicit_variables_win_over_the_preset(self): "theme_dark_css_variables": {"color-fd-primary": "#ff0000"}, } )["fuma_css_overrides"] + assert isinstance(css, str) assert "--color-fd-primary: #ff0000;" in css assert "#fff383" not in css @@ -288,6 +293,7 @@ def test_preset_still_supplies_the_other_mode(self): "theme_dark_css_variables": {"color-fd-primary": "#ff0000"}, } )["fuma_css_overrides"] + assert isinstance(css, str) assert "--color-fd-primary: #cc8b00;" in css