fix(mainsail): theme installer updates for current Mainsail docs branch (#833)

This commit is contained in:
Phil Rennie authored and GitHub committed 2026-11-04 18:05:35 +01:00
1 parent 3c3ef62b53
commit 485b7bc7bf
3 files changed
+131 -9

No files matched your search

@@ -76,7 +76,7 @@ class MainsailThemeInstallerExtension(BaseExtension):
# noinspection PyMethodMayBeStatic
class MainsailThemeInstallMenu(BaseMenu):
THEMES_URL: str = (
"https://raw.githubusercontent.com/mainsail-crew/gb-docs/main/_data/themes.csv"
"https://raw.githubusercontent.com/mainsail-crew/docs/zensical/_data/themes.csv"
)
def __init__(self, instances: List[Klipper]):
@@ -94,8 +94,9 @@ class MainsailThemeInstallMenu(BaseMenu):
)
def set_options(self) -> None:
# Menu numbers start at 1 to match the theme IDs on the Mainsail docs page
self.options = {
f"{index}": Option(self.install_theme, opt_index=f"{index}")
f"{index + 1}": Option(self.install_theme, opt_index=f"{index}")
for index in range(len(self.themes))
}
@@ -107,11 +108,12 @@ class MainsailThemeInstallMenu(BaseMenu):
f"""
╟───────────────────────────────────────────────────────╢
║ {line1:<62} ║
║ https://docs.mainsail.xyz/theming/themes ║
║ https://docs.mainsail.xyz/features/custom- ║
║ themes/community-themes/ ║
╟───────────────────────────────────────────────────────╢
"""
)[1:]
for i, theme in enumerate(self.themes):
for i, theme in enumerate(self.themes, start=1):
j: str = f" {i}" if i < 10 else f"{i}"
row: str = f"{j}) [{theme.name}]"
menu += f"║ {row:<53} ║\n"
@@ -123,12 +125,19 @@ class MainsailThemeInstallMenu(BaseMenu):
themes: List[ThemeData] = []
content: str = response.read().decode()
csv_data: List[str] = content.splitlines()
fieldnames = ["name", "short_note", "author", "repo"]
csv_reader = csv.DictReader(csv_data, fieldnames=fieldnames, delimiter=",")
next(csv_reader) # skip the header of the csv file
# read columns by the csv header, so extra columns in the list
# (e.g. "branch" and "preview", used by the docs page) are ignored
csv_reader = csv.DictReader(csv_data, delimiter=",")
for row in csv_reader:
row: Dict[str, str] # type: ignore
theme: ThemeData = ThemeData(**row)
if not row.get("author") or not row.get("repo"):
continue
theme: ThemeData = ThemeData(
name=row.get("name") or row["repo"],
short_note=row.get("short_note") or "",
author=row["author"],
repo=row["repo"],
)
themes.append(theme)
return themes
@@ -5,7 +5,7 @@
"maintained_by": "dw-0",
"display_name": "Mainsail Theme Installer",
"description": ["Install Mainsail Themes maintained by the Mainsail community."],
"website": "https://docs.mainsail.xyz/theming/themes",
"website": "https://docs.mainsail.xyz/features/custom-themes/community-themes/",
"updates": false
}
}
@@ -0,0 +1,113 @@
# ======================================================================= #
# Copyright (C) 2020 - 2026 Dominik Willner <dev.dw-0@proton.me> #
# #
# This file is part of KIAUH - Klipper Installation And Update Helper #
# https://github.com/dw-0/kiauh #
# #
# This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= #
from __future__ import annotations
import pytest
from extensions.mainsail_theme_installer.mainsail_theme_installer_extension import (
MainsailThemeInstallMenu,
ThemeData,
)
MODULE = "extensions.mainsail_theme_installer.mainsail_theme_installer_extension"
# current format of the list in mainsail-crew/docs
DOCS_CSV = (
"name,short_note,author,repo,branch,preview\n"
"Dracula,,steadyjaw,dracula-mainsail-theme,master,screenshot.jpg\n"
"Printables,(unofficial),8bitmcu,mainsail-printables,main,screenshot.jpg\n"
)
# legacy format of the list in mainsail-crew/gb-docs
LEGACY_CSV = (
"name,short_note,author,repo\n"
"Dracula,,steadyjaw,dracula-mainsail-theme\n"
"Printables,(unofficial),8bitmcu,mainsail-printables\n"
)
EXPECTED_THEMES = [
ThemeData("Dracula", "", "steadyjaw", "dracula-mainsail-theme"),
ThemeData("Printables", "(unofficial)", "8bitmcu", "mainsail-printables"),
]
class _FakeResponse:
def __init__(self, body: str) -> None:
self._body = body.encode()
def __enter__(self):
return self
def __exit__(self, *args):
return None
def read(self) -> bytes:
return self._body
def _patch_themes_csv(monkeypatch: pytest.MonkeyPatch, body: str) -> None:
class FakeUrlLib:
@staticmethod
def urlopen(url: str):
return _FakeResponse(body)
monkeypatch.setattr(f"{MODULE}.urllib.request", FakeUrlLib())
@pytest.fixture
def menu(monkeypatch: pytest.MonkeyPatch) -> MainsailThemeInstallMenu:
_patch_themes_csv(monkeypatch, DOCS_CSV)
return MainsailThemeInstallMenu([])
class TestLoadThemes:
def test_parses_docs_format_and_ignores_extra_columns(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
_patch_themes_csv(monkeypatch, DOCS_CSV)
assert MainsailThemeInstallMenu([]).themes == EXPECTED_THEMES
def test_parses_legacy_format(self, monkeypatch: pytest.MonkeyPatch) -> None:
_patch_themes_csv(monkeypatch, LEGACY_CSV)
assert MainsailThemeInstallMenu([]).themes == EXPECTED_THEMES
def test_skips_blank_and_incomplete_rows(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
_patch_themes_csv(monkeypatch, DOCS_CSV + "\n" + "Broken,,,,,\n")
assert MainsailThemeInstallMenu([]).themes == EXPECTED_THEMES
class TestThemeMenuNumbering:
def test_options_start_at_one_to_match_docs_ids(
self, menu: MainsailThemeInstallMenu
) -> None:
menu.set_options()
assert list(menu.options) == ["1", "2"]
assert menu.options["1"].opt_index == "0"
assert menu.options["2"].opt_index == "1"
def test_menu_lists_themes_from_one(
self, menu: MainsailThemeInstallMenu, capsys
) -> None:
menu.print_menu()
out = capsys.readouterr().out
assert " 1) [Dracula]" in out
assert " 2) [Printables]" in out
assert " 0) [" not in out
def test_menu_links_to_current_docs(
self, menu: MainsailThemeInstallMenu, capsys
) -> None:
menu.print_menu()
out = capsys.readouterr().out
# the url is too long for the menu box, so it is wrapped over two lines
assert "║ https://docs.mainsail.xyz/features/custom- ║" in out
assert "║ themes/community-themes/ ║" in out
assert "theming/themes" not in out