plugin_adapter narrates every step of acquiring content from every plugin --
"Has get_vegas_content", "Native: calling get_vegas_content()", "Native
content returned None", "Has scroll_helper", per-item sizes -- once per plugin
per cycle, all at INFO.
Measured on a live rig: 13,408 log lines an hour, of which 13,366 were INFO
and 35 were WARNING. Roughly 223 lines a minute of string formatting on a Pi
that is also driving the panel, written through journald to the SD card, with
the 35 lines that actually indicate a problem buried among them.
Top repeated messages in that hour:
717 Scroll progress: elapsed=... total_scrolled=.../... px
399 [plugin] --> INCLUDED in Vegas scroll
323 [plugin] content_type=static, display_mode=fixed
195 [plugin] Has get_vegas_content: True
195 [plugin] Native: calling get_vegas_content()
168 [plugin] Native: get_vegas_content() returned None
168 [plugin] Native content returned None <- the same fact, twice
54 logger.info calls in plugin_adapter become logger.debug, along with the
per-frame scroll-progress line in scroll_helper. Together those are 3,174 of
the 13,408 lines an hour, a 23% cut, and the ~3,600 odds-manager lines are
addressed separately by ledmatrix-plugins#300.
Nothing is lost: the 19 warning/error/exception calls in the module are
untouched, so real failures still surface at their own level. This is a
logging-level change only -- no control flow, no behaviour.
One INFO call is deliberate and stays. The padding-strip message picks its
level at runtime (`logger.warning if (left and right) else logger.info`) and
test_vegas_plugin_adapter.py pins that choice; it survives because it is not a
direct logger.info call site. That test still passes.
Mutation-checked both ways: reintroducing a single INFO trace fails the guard,
and demoting the warning/error calls along with the trace fails a second guard
written for exactly that mistake. 537 vegas and scroll tests pass.
(cherry picked from commit e496d95dfe)
(cherry picked from commit 8d1e43c15a)
Common Utilities
This directory contains reusable utilities and helpers for LEDMatrix plugins and core modules.
Adaptive Layout & Images (src/adaptive_layout.py, src/adaptive_images.py)
The recommended way to lay out plugins that render legibly on any panel
size (64x32 through 256x128+) without hand-tuned coordinates. Re-exported
from src.common for convenience; canonical import paths are
src.adaptive_layout / src.adaptive_images.
# Every BasePlugin already has self.layout and the draw helpers:
regs = scoreboard_regions(self.layout.bounds, ctx=self.layout)
self.draw_image(away_logo, regs.away_slot, mode="fill_height",
crop_to_ink=True, cache_key=f"logo:{abbr}")
self.draw_fit(score_text, regs.score_area) # largest crisp font that fits
self.draw_fit(status, regs.status_band)
Key pieces: Region (rect algebra: bands/columns/splits/offset),
font ladders (LADDER_GRID, LADDER_ARCADE — discrete crisp sizes, never
fractional scaling), LayoutContext (fit_text, fit_image, by_tier,
px), and composite carvers scoreboard_regions() / media_row().
Full guide: docs/ADAPTIVE_LAYOUT.md.
Error Handling (error_handler.py)
Common error handling patterns and utilities:
handle_file_operation()- Handle file I/O with consistent error handlinghandle_json_operation()- Handle JSON operations with error handlingsafe_execute()- Safely execute operations with error handlingretry_on_failure()- Decorator for retrying failed operationslog_and_continue()- Log non-critical errors and continuelog_and_raise()- Log errors and raise exceptions
Example Usage
from src.common.error_handler import handle_json_operation, safe_execute
# Handle JSON loading
config = handle_json_operation(
lambda: json.load(open('config.json')),
"Failed to load config",
logger,
default={}
)
# Safe execution with error handling
result = safe_execute(
lambda: risky_operation(),
"Operation failed",
logger,
default=None
)
API Helpers (api_helper.py)
Utilities for making HTTP requests and handling API responses.
Configuration Helpers (config_helper.py)
Utilities for loading, saving, and validating configuration files.
Display Helpers (display_helper.py)
Utilities for rendering content to the LED matrix display.
Game Helpers (game_helper.py)
Utilities for processing game data and team information.
Logo Helpers (logo_helper.py)
Utilities for loading and managing team logos.
Text Helpers (text_helper.py)
Utilities for text processing and formatting.
Scroll Helpers (scroll_helper.py)
Utilities for scrolling text on the display.
General Utilities (utils.py)
General-purpose utility functions:
- Team abbreviation normalization
- Time formatting
- Boolean parsing
- Logger creation (deprecated - use
src.logging_config.get_logger())
Permission Utilities (permission_utils.py)
Helpers for ensuring directory permissions and ownership are correct
when running as a service (used by CacheManager to set up its
persistent cache directory).
Best Practices
- Use centralized logging: Import from
src.logging_configinstead of creating loggers directly - Use error handlers: Use
error_handlerutilities for consistent error handling - Reuse utilities: Check existing utilities before creating new ones
- Document additions: Add documentation when adding new utilities