-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Plugins: Decky Loader doesn't instantiate and call plugin classes correctly #509
Comments
Some thoughts I had on this on Discord (conversation starting at https://canary.discord.com/channels/960281551428522045/960284327445418044/1131286537145958410):
|
I've also come across this and I can confirm it is confusing. 😄 The current Plugin "class" is treated more like a module/namespace, so it's confusing when I'm currently working around it by making a separate class and instantiating that myself, treating Plugin like an API layer and moving all the "business logic" to the other class. This code is probably easier to understand and test, albeit it's also more verbose. Still, it doesn't take away from how confusing the Plugin's Possible fixesIf we're speculating on designs that would allow proper instantiation while remaining compatible, I'd consider adding a new static/class method where the plugin developer can return an instance of the plugin. This doesn't replace the existing Allowing the plugin developer to return an instance allows configuring the Plugin with parameters and provides inversion of control, making the Plugin code more easily testable. For example: class Plugin:
@staticmethod
def instance() -> Plugin:
# Plugin developer can grab configs needed for instantiating the plugin class here
return Plugin()
def __init__(self) -> None:
# Plugin developer can perform whatever fast initialisation they need to here -- _main still exists for slower initialisation using asyncio
pass Decky Loader could pass in configuration to the Here are quick examples of all the configuration possibilities I've mentioned: # Loader could pass in lots of parameters...
class Plugin:
@staticmethod
def instance(plugin_path, bin_path, ...) -> Plugin:
# Plugin developer can grab configs needed for instantiating the plugin class here
return Plugin(plugin_path=plugin_path)
# ... But it might be more future proof to have a data class instead:
@dataclass
class PluginConfig:
plugin_dir: Path
runtime_dir: Path
... # Feel free to add more later -- it'll be backwards-compatible manner
class Plugin:
@staticmethod
def instance(config: PluginConfig) -> Plugin:
# Plugin developer can grab configs needed for instantiating the plugin class here
return Plugin(plugin_config=config)
# ... Or decky_plugin can continue to be used:
class Plugin:
@staticmethod
def instance() -> Plugin:
# Plugin developer can grab configs needed for instantiating the plugin class here
return Plugin(
settings_dir=decky_plugin.DECKY_PLUGIN_SETTINGS_DIR,
...
) When it comes to loading the plugin, potentially this could be as simple as detecting the presence of decky-loader/backend/plugin.py Line 85 in 6d086fb
self.Plugin = module.Plugin
if hasattr(self.Plugin, "instance") and callable(self.Plugin.instance):
self.Plugin = self.Plugin.instance(...) However I can see a lot of manual passing of |
fixed on websockets branch |
Please confirm
Bug Report Description
Plugins ship with a
main.py
that define a single Python classPlugin
.At the moment Decky doesn't actually instantiate that class, it just calls
_main
and_unload
with the class itself asself
, which is incorrect and leads to bugs and confusion when trying to interact withself
insidePlugin
. Most notably simple method calls likeself.method()
fail, complaining aboutself
not being an instance of the object. The workaround for this isPlugin.method(self)
, but this is pretty jank.See:
decky-loader/backend/plugin.py
Line 90 in 6d086fb
Expected Behaviour
Decky should just instantiate the Plugin class normally and call methods on it like on any other standard Python object. Alternatively,
_main
and_unload
(and possibly any plugin method called by the frontend?) should be marked properly with@classmethod
SteamOS version
n/a
Selected Update Channel
Stable
Have you modified the read-only filesystem at any point?
n/a
Logs
n/a
The text was updated successfully, but these errors were encountered: