From 0ec343181503e64c6f2330b07f1bdb2c1f9f4117 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 00:08:01 +0000 Subject: [PATCH] docs(code): document deliberate duplicates instead of merging them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audit surfaced several near-duplicate implementations that turned out to be either deliberate forks or behaviorally different — merging any of them would risk changing behavior on installed devices, so each now carries an explicit comment stating the relationship: - VisualDisplayManager: headless fork of DisplayManager; header now lists the ~15 mirrored methods and warns that DisplayManager changes must be mirrored. - normalize_abbreviation: LogoDownloader's version (called directly by nine scoreboard plugins) replaces filesystem-unsafe characters; LogoHelper's strips spaces. Logo filenames on existing installs depend on both behaviors staying put. - The two PluginTestBase classes: the shipped one is plugin-author API, the repo's own richer harness lives in test/plugins/ — now cross-referenced. Also verified (no change needed): ConfigManager's backup/rollback methods genuinely delegate to AtomicConfigManager, and SportsCore already delegates _read_bdf_native_size to FontManager. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr --- src/common/logo_helper.py | 11 +++++++++-- src/logo_downloader.py | 9 ++++++++- src/plugin_system/testing/plugin_test_base.py | 5 +++++ src/plugin_system/testing/visual_display_manager.py | 11 +++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/common/logo_helper.py b/src/common/logo_helper.py index 7d0dc4df..13f9f73e 100644 --- a/src/common/logo_helper.py +++ b/src/common/logo_helper.py @@ -187,10 +187,17 @@ class LogoHelper: def normalize_abbreviation(self, team_abbr: str) -> str: """ Normalize team abbreviation for consistent filename usage. - + + NOTE: this deliberately differs from + LogoDownloader.normalize_abbreviation (src/logo_downloader.py), + which replaces filesystem-unsafe characters (/ \\ : * ? " < > |) + but does not strip spaces. Plugins call the LogoDownloader + version; changing either implementation changes which logo + filenames resolve on existing installs. + Args: team_abbr: Raw team abbreviation - + Returns: Normalized abbreviation """ diff --git a/src/logo_downloader.py b/src/logo_downloader.py index e4dad335..b799b7c1 100644 --- a/src/logo_downloader.py +++ b/src/logo_downloader.py @@ -118,7 +118,14 @@ class LogoDownloader: @staticmethod def normalize_abbreviation(abbreviation: str) -> str: - """Normalize team abbreviation for consistent filename usage.""" + """Normalize team abbreviation for consistent filename usage. + + Public API: sports scoreboard plugins call this directly. + NOTE: LogoHelper.normalize_abbreviation (src/common/logo_helper.py) + is a deliberately different variant (strips spaces, fewer character + replacements) — keep both behaviors stable; logo filenames on + existing installs depend on them. + """ # Handle special characters that can cause filesystem issues normalized = abbreviation.upper() diff --git a/src/plugin_system/testing/plugin_test_base.py b/src/plugin_system/testing/plugin_test_base.py index f873ea9e..806f3d3f 100644 --- a/src/plugin_system/testing/plugin_test_base.py +++ b/src/plugin_system/testing/plugin_test_base.py @@ -2,6 +2,11 @@ Base test class for LEDMatrix plugins. Provides common fixtures and helper methods for plugin testing. + +Note: this is the plugin-author-facing base class shipped with the +core (importable as src.plugin_system.testing.plugin_test_base). The +repo's own plugin tests use a separate, richer harness in +test/plugins/test_plugin_base.py — the two are intentionally distinct. """ import unittest diff --git a/src/plugin_system/testing/visual_display_manager.py b/src/plugin_system/testing/visual_display_manager.py index e3dc2ec6..5211a226 100644 --- a/src/plugin_system/testing/visual_display_manager.py +++ b/src/plugin_system/testing/visual_display_manager.py @@ -10,6 +10,17 @@ without requiring hardware or the RGBMatrixEmulator. Used for: Unlike MockDisplayManager (which logs calls but doesn't render) or MagicMock (which tracks nothing visual), this class creates a real PIL Image canvas and draws text using the actual project fonts. + +MAINTENANCE WARNING: this class is a deliberate fork of +src/display_manager.py so it can run without hardware. It mirrors +these DisplayManager methods by name and behavior: _load_fonts, +_draw_bdf_text, get_font_height, get_text_width, draw_text, +draw_text_with_icons, draw_weather_icon (and the _draw_sun/_draw_cloud/ +_draw_rain/_draw_snow/_draw_storm family), format_date_with_ordinal, +capture_mode, set_scrolling_state, is_currently_scrolling, +process_deferred_updates, update_display, render_size. A behavior +change to any of those in DisplayManager must be mirrored here, or +plugin visual tests will pass against stale behavior. """ import math