Skip to content

fix(scoreboards): tell the shared code where the plugin lives - #405

Merged
ChuckBuilds merged 1 commit into
mainfrom
fix/declare-plugin-dir
Sep 3, 2026
Merged

fix(scoreboards): tell the shared code where the plugin lives#405
ChuckBuilds merged 1 commit into
mainfrom
fix/declare-plugin-dir

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Every grid-snapped font was rendering a pixel narrow, on every device.

The shared sports code reads a plugin's config_schema.json to tell a default font size from one the user chose — a default gets snapped to the font's pixel grid, a choice is left alone. It located the schema by inspecting loaded modules, which cannot work under the real plugin loader:

# PluginLoader._namespace_plugin_modules
namespaced = f"_plg_{safe_id}_{mod_name}"
sys.modules[namespaced] = mod
del sys.modules[mod_name]        # the original name goes away

So the lookup returned nothing → every configured size looked user-chosen → the snap was skipped → 4x6-font.ttf drew at 6 instead of 7, which is 3px-wide glyphs instead of 4px.

On a 256×64 panel that made the betting odds, the team records and the date row hard to read.

Fix

Each SportsCore declares _PLUGIN_DIR from its own __file__, which the shared code prefers over guessing. Needs core ChuckBuilds/LEDMatrix#519.

The guard

scripts/test_plugin_dir_under_loader.py reproduces the loader's sequence exactly — import sports.py under its bare name, then rename it away — because that combination is what makes the class report __module__ == "sports" with no such entry in sys.modules.

Both halves matter, and my first draft of this guard got it wrong: it imported under the namespaced name, __module__ still resolved, and it passed against the broken code. The corrected version was verified to fail for all eight with the declarations removed, and pass with them restored.

How this shipped

Found by a user counting pixels on a photo of the panel — not by any gate here.

  • Every test imported plugins directly, which leaves the bare module entry in place, so the lookup succeeded.
  • The safety harness loads plugins its own way and never reproduced it.
  • 176 byte-identical renders passed throughout.

That gap is what the new guard closes.

Verified on hardware

live service
before plugin_dir=None, 4x6-font.ttf@6 for all six football managers
after plugin_dir resolves, odds=@7 detail=@7, all eight scoreboards

Patch bumps. No behaviour change beyond restoring the intended font sizes.

Every grid-snapped font was rendering a pixel narrow on every device.

The shared sports code reads this plugin's config_schema.json to tell a default
font size from one the user chose: a default is snapped to the font's pixel
grid, a choice is left alone. It located the schema by inspecting loaded
modules, which cannot work under the real plugin loader --
PluginLoader._namespace_plugin_modules renames a plugin's modules to
"_plg_<id>_<module>" and removes the original names, so nothing is left to
inspect.

The lookup returned nothing, every configured size then looked user-chosen, the
snap was skipped, and 4x6-font.ttf drew at 6 instead of 7: 3px-wide glyphs
instead of 4px. On a 256x64 panel the betting odds, the team records and the
date row were hard to read.

Each SportsCore now declares _PLUGIN_DIR from its own __file__, which the
shared code prefers over guessing (ChuckBuilds/LEDMatrix#519).

scripts/test_plugin_dir_under_loader.py stops this recurring. It reproduces the
loader's sequence exactly -- import sports.py under its BARE name, then rename
it away -- because that is what makes the class report __module__ == "sports"
with no such entry in sys.modules.

Both halves matter, and the first draft of this guard got it wrong: it imported
under the namespaced name, __module__ still resolved, and it passed against the
broken code. Verified the corrected version fails for all eight with the
declarations removed and passes with them restored.

Found by a user counting pixels on a photo of the panel. No gate here caught
it: every test imported plugins directly, which leaves the bare module entry in
place, and the safety harness loads plugins its own way.
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 17ca4fd3-59d6-4e81-a4e4-dfe77f177ebb


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 20 complexity

Metric Results
Complexity 20

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@ChuckBuilds
ChuckBuilds merged commit aa749dd into main Sep 3, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants