Convert & migrate
There are two separate migrations on this page. The first — converting a legacy in-app plugin to explicit
mixlar imports — is something you can do any time, to any plugin, at your own pace. The second — the app
itself adopting the SDK as its single source of truth instead of defining these classes inline — is a
maintainer-side change to mixlar_mini.py. Neither depends on the other.
Converting a legacy plugin to explicit imports
Section titled “Converting a legacy plugin to explicit imports”Legacy plugins (see PC Software/Plugin Examples/*.py) rely on the app injecting names into their module
namespace before exec-ing them: MixlarPlugin, the color constants (ACCENT, CARD2, WHITE, and so
on), _fa, _EDITOR_COMBO_STYLE, _style_combo_view. That’s why those examples reference MixlarPlugin
and ACCENT with no import line at the top — the names only resolve inside the running app, which means
no autocomplete, no type checking, and no way to run the file standalone.
Before — legacy style, only works when injected by the app:
class MouseBatteryPlugin(MixlarPlugin): plugin_id = "mouse_battery" plugin_icon_color = ACCENT
def build_settings_ui(self, layout, settings): icon = _fa("fa5s.battery-full", color=ACCENT) ...After — explicit imports, works everywhere:
from mixlar import MixlarPluginfrom mixlar.colors import ACCENTfrom mixlar.qt import _fa
class MouseBatteryPlugin(MixlarPlugin): plugin_id = "mouse_battery" plugin_icon_color = ACCENT
def build_settings_ui(self, layout, settings): icon = _fa("fa5s.battery-full", color=ACCENT) ...Nothing about the class body changes — only the top of the file. This is safe precisely because of the
SDK’s “single source of truth” seam: mixlar.plugin detects a running app and re-exports its live
MixlarPlugin; mixlar.colors and mixlar.qt do the same for the palette and the Qt helpers. So:
- Off-app (your editor,
mixlar-sdk validate/emulate, tests, CI) — you get faithful standalone implementations: real values, real behavior, just not backed by the actual running app or a real serial link. - Inside the app — the imports resolve to the app’s own objects, byte-identical to what injection would have given you.
Run mixlar-sdk validate after converting to confirm nothing regressed.
Adopting the SDK inside the app
Section titled “Adopting the SDK inside the app”This is the bigger, maintainer-side move. Today mixlar_mini.py defines MixlarPlugin
(PC Software/mixlar_mini.py:3454), PluginRegistry (:3665), the color constants (around :2749), and
_plugin_package_digest / _verify_plugin_signature / _PUBLISHER_KEYS (:3839, :3908, :3903)
inline. Instead, the app would import mixlar and use this SDK’s implementations as the canonical ones:
# in mixlar_mini.py, instead of defining these classes inline:from mixlar.plugin import MixlarPluginfrom mixlar.registry import PluginRegistryfrom mixlar.colors import ACCENT, CARD, CARD2, WHITE, GRAY, SEP, RED, GREEN, ORANGE, PURPLEfrom mixlar.signing import package_digest as _plugin_package_digestfrom mixlar.signing import verify_signature as _verify_plugin_signaturefrom mixlar.signing import PUBLISHER_KEYS as _PUBLISHER_KEYSWhy this is safe to do incrementally
Section titled “Why this is safe to do incrementally”The re-export mechanism in mixlar.plugin / mixlar.registry / mixlar.colors only fires when
sys.modules already contains mixlar_mini — it’s designed for the current one-way direction (app
injects, SDK detects and mirrors). Flipping it so the app imports from mixlar instead removes the
duplication entirely: one implementation, one place bugs get fixed, and this SDK’s own test suite
(tests/) becomes a real regression suite for that shared code instead of a parallel reimplementation that
could silently drift from the app’s copy.
What this buys the app
Section titled “What this buys the app”mixlar.manifest.validate_package/mixlar.validator.lint_packagebecome the app’s own manifest and widget validation, instead of a second implementation to keep in sync.mixlar.packaging.pack/unpack/installbecome the app’s own.mixpluginhandling — see Packaging &.mixplugin.- The app’s plugin-loading code and
mixlar_cli.util.load_plugin_instancesbecome the same function, instead of two implementations that must be kept behaviorally identical by hand (as they are today, deliberately mirrored).
What it costs
Section titled “What it costs”Dependency surface. mixlar currently pulls in cryptography and packaging unconditionally (core
pyproject.toml dependencies). Both are almost certainly already present in the app’s own
requirements.txt/build — cryptography for OS credential handling, packaging is extremely common
transitively — but confirm before assuming.
Packaging implication (PyInstaller)
Section titled “Packaging implication (PyInstaller)”If the app imports mixlar, Builds/mixlar_mini.spec needs to know about it — PyInstaller doesn’t
discover it automatically, since nothing in the app today imports it. Either of these works:
# mixlar_mini.spec — explicit listhiddenimports = [ ..., # existing entries "mixlar", "mixlar.plugin", "mixlar.registry", "mixlar.colors", "mixlar.protocol", "mixlar.manifest", "mixlar.signing", "mixlar.widgets", "mixlar.validator", "mixlar.settings_schema", "mixlar.events", "mixlar.macros", "mixlar.sliders", "mixlar.icons", "mixlar.imaging", "mixlar.packaging", "mixlar.emulator", "mixlar.emulator.device", "mixlar.emulator.render", "mixlar.qt",]or, simpler and more future-proof against new submodules, use collect_submodules in the spec’s
Analysis block:
from PyInstaller.utils.hooks import collect_submoduleshiddenimports += collect_submodules("mixlar")Suggested order of operations
Section titled “Suggested order of operations”- Confirm
cryptography/packagingare already in the app’s dependency set (they almost certainly are). - Swap the color constants first (
mixlar.colors) — lowest risk, no behavioral surface, easiest to verify visually. - Swap
signing/manifest/packaging/validatornext — these are pure functions with no Qt/registry coupling, and this SDK’stests/already cover their exact behavior. - Swap
MixlarPlugin/PluginRegistrylast — this is the class-identity change every loaded plugin’sissubclasscheck depends on. Test with a couple of real plugins fromPC Software/Plugin Examples/before calling it done. - Add the PyInstaller
hiddenimports(orcollect_submodules) change in the same pass as step 4, and do a fullBuilds\build.batplus a smoke test — an import that works from source but is missing from the frozen.exeis exactly the kind of bug that doesn’t show up until someone else’s machine.
Related pages
Section titled “Related pages”- Plugin API reference — the full
MixlarPluginsurface you’re targeting. - CLI: validate & emulate — run these after every conversion step.
- Packaging & signing — background on the
signingmodule referenced above.