From 7e52e010fd4d0ccea13f4df8f35f751d7eae73d1 Mon Sep 17 00:00:00 2001 From: cdeust Date: Tue, 28 Jul 2026 21:35:49 +0200 Subject: [PATCH 1/4] refactor(scripts): extract the shared badge SVG renderer Behavior-preserving. A second generator (generate_repo_badges.py, next commit) needs the same shields-style geometry the MCP Toplist refresher already had, so the geometry moves to a sibling module rather than being copied. What stays in the refresher is what makes that badge THAT badge: the bar icon, the banner palette, and the wording of its claim. Path-based sibling import, following the launcher.py/launcher_deps*.py idiom already in scripts/: it resolves identically whether the file runs as a script (script dir already on sys.path) or is loaded through importlib.util.spec_from_file_location by a test, which is how tests_py loads every script gate. XML escaping moves INTO the renderer rather than staying at each call site. The one bug this code has ever shipped was an unescaped '<' from the "Top <0.1%" tier making the badge unparseable XML; centralising the escape means a new generator cannot reintroduce it by forgetting. Proof of preservation: render_badge(964/81919, 2026-07-28) is byte-identical to the committed assets/badge-mcp-toplist.svg, and the existing 51 tests pass unchanged (51 passed in 0.82s). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BJt9KN23rUNQzwoJv4jRWw --- scripts/badge_render.py | 169 +++++++++++++++++++++++++++ scripts/refresh_mcp_toplist_badge.py | 115 +++++++----------- 2 files changed, 208 insertions(+), 76 deletions(-) create mode 100644 scripts/badge_render.py diff --git a/scripts/badge_render.py b/scripts/badge_render.py new file mode 100644 index 00000000..c2318a51 --- /dev/null +++ b/scripts/badge_render.py @@ -0,0 +1,169 @@ +"""Shields-style two-panel badge SVG rendering, shared by the badge generators. + +Extracted from refresh_mcp_toplist_badge.py when a second generator +(generate_repo_badges.py) needed the same geometry. Both emit the same +anatomy — a dark label panel, a coloured message panel, a drop-shadowed +text run in each — and differ only in their data and provenance. + +Two constraints shape every choice here, and neither is negotiable on the +one surface these badges exist for (a README rendered by GitHub): + + * No