Summary
check_plugin.py's "empty warn: drew nothing but display() returned X, so the mode is not skipped" fires on a single frame, rendered with force_clear=True, under a frozen clock. All three of those defeat a scrolling plugin, whose first frame is legitimately blank while the content scrolls in. Across the 44 plugins installed on this rig, 60 of the 76 warnings — 79% — are false positives.
A warning that's wrong four times out of five is one people learn to scroll past, which is a problem because the 16 real ones matter (see ChuckBuilds/ledmatrix-plugins#456).
The three causes
1. One frame only.harness._render_size calls _render_mode(inst, mode) exactly once per (size, mode).
2. force_clear=True on every call.harness.py:142-161:
def_render_mode(plugin_instance: Any, mode: str) ->Any:
sig=inspect.signature(plugin_instance.display)
if"display_mode"insig.parameters:
returnplugin_instance.display(force_clear=True, display_mode=mode)
For a scroll plugin force_clear means "reset the scroll to the start", so even repeated calls through this path would never advance.
3. Frozen clock._freeze uses freezegun.freeze_time(freeze_time) with the default tick=False, so a scroll driven by elapsed wall time never moves.
Measurement
Driving display() properly — one force_clear=True frame, then force_clear=False frames, under freeze_time(..., tick=True) — at 128x64:
| plugin | warnings from check_plugin | real? | first frame with content |
|---|
| f1-scoreboard | 42 (7 modes × 6 sizes) | no | frames 2-4 |
| ledmatrix-elections | 16 (2 modes × 8 sizes) | no | frame 4 |
| ledmatrix-leaderboard | 2 (64x32, 64x64) | no | frame 38 |
| nfl-draft | 8 | yes | never (300 frames) |
| starlark-apps | 8 | yes | never (300 frames) |
| on-air | 8 | deliberate | never (by design) |
f1-scoreboard's own test/harness.json already documents the situation:
"the seven scroll modes (standings/results/qualifying/practice/sprint/calendar) start with a blank scroll-in buffer so a single-frame capture is empty and not worth committing"
— i.e. the plugin author knew, wrote it down, and the tool warns anyway on every run.
Suggested fix
Give the emptiness check a few frames before it concludes anything:
# in _render_size, after the first renderifresult.imageisnotNoneandnot_has_content(result.image):
for_inrange(EMPTY_RECHECK_FRAMES): # ~8 is enough; scrolls lit by frame 4 here_render_mode_no_clear(inst, mode)
if_has_content(dm.get_image()):
break
with two supporting changes:
- a
force_clear=False variant of _render_mode, so follow-up frames don't reset the scroll; _freeze(..., tick=True) for the re-check (or advance the frozen clock explicitly between frames) so elapsed-time scrolls progress. Goldens should keep using the non-ticking freeze — only the emptiness re-check needs time to move.
Only warn if the mode is still blank after those frames. That keeps every true positive in the table above and drops all the noise.
Related, and worth considering separately: the core treats a None return as "don't skip" (display_controller.py:2110, if isinstance(result, bool)). The warning text says "so the mode is not skipped", which is accurate, but plugins annotated -> None are silently opted out of the skip contract. A stricter check — or a deprecation warning for display() implementations that never return a bool — would surface that class directly.
Environment
LEDMatrix v3.3.0-4-g0730d952, 256x64 rig, 44 installed plugins.
Summary
check_plugin.py's "empty warn: drew nothing but display() returned X, so the mode is not skipped" fires on a single frame, rendered withforce_clear=True, under a frozen clock. All three of those defeat a scrolling plugin, whose first frame is legitimately blank while the content scrolls in. Across the 44 plugins installed on this rig, 60 of the 76 warnings — 79% — are false positives.A warning that's wrong four times out of five is one people learn to scroll past, which is a problem because the 16 real ones matter (see ChuckBuilds/ledmatrix-plugins#456).
The three causes
1. One frame only.
harness._render_sizecalls_render_mode(inst, mode)exactly once per (size, mode).2.
force_clear=Trueon every call.harness.py:142-161:For a scroll plugin
force_clearmeans "reset the scroll to the start", so even repeated calls through this path would never advance.3. Frozen clock.
_freezeusesfreezegun.freeze_time(freeze_time)with the defaulttick=False, so a scroll driven by elapsed wall time never moves.Measurement
Driving
display()properly — oneforce_clear=Trueframe, thenforce_clear=Falseframes, underfreeze_time(..., tick=True)— at 128x64:f1-scoreboard's own
test/harness.jsonalready documents the situation:— i.e. the plugin author knew, wrote it down, and the tool warns anyway on every run.
Suggested fix
Give the emptiness check a few frames before it concludes anything:
with two supporting changes:
force_clear=Falsevariant of_render_mode, so follow-up frames don't reset the scroll;_freeze(..., tick=True)for the re-check (or advance the frozen clock explicitly between frames) so elapsed-time scrolls progress. Goldens should keep using the non-ticking freeze — only the emptiness re-check needs time to move.Only warn if the mode is still blank after those frames. That keeps every true positive in the table above and drops all the noise.
Related, and worth considering separately: the core treats a
Nonereturn as "don't skip" (display_controller.py:2110,if isinstance(result, bool)). The warning text says "so the mode is not skipped", which is accurate, but plugins annotated-> Noneare silently opted out of the skip contract. A stricter check — or a deprecation warning fordisplay()implementations that never return a bool — would surface that class directly.Environment
LEDMatrix
v3.3.0-4-g0730d952, 256x64 rig, 44 installed plugins.