Plugin Development
This section has guidelines on creating extension plugins for pyetta.
Click Subcommands
The click commands used by pyetta subclass a special implementation of both click groups and commands. This allows for special properties to be injected in via the provided decorators.
- class pyetta.cli.utils.PyettaCommand(category: str = 'Commands', plugin_name: Optional[str] = None, *args, **kwargs)
Bases:
click.core.CommandCommand base for pyetta commands, use this as your class injection for click commands.
This uses the category property to allow proper help text to group the command types.
To use this specialisation within the plugin, the standard click decorators may be used. See the foo_plugin.py Example for usage.
Magic Method (load_plugin)
The load_plugin is a magic method that the cli tool will attempt to find
after loading your python module from the relevant places. If this method is
not found or an exception is thrown during the loading of a plugin, a
ImportError will be thrown instead and the cli tool will terminate.
Warning
Because of this behaviour, misbehaved plugins can break the cli tool.
Consider uninstalling the plugin if this occurs, or use the option flag
--ignore-plugins with the name of the plugins. This flag has to be used
before the extras flag as they are evaluated in the order of occurrence.
Loading Plugins
Plugins can be loaded in 2 distinct ways.
Using the
--extrasflag.Using the entrypoint group
pyetta.plugins.
Note
Any plugin developed to be used as a plugin can be directly invoked using the --extras flag. No additional
development is needed.
Using Entry Point pyetta.plugins
A plugin can be loaded using the entrypoint. This allows for plugin developers to distribute their plugins using PyPI or
any other python package repository. pyetta uses this mechanism to load its own builtin handlers, which can be seen
from the snippet in the project pyproject.toml manifest.
[project.entry-points."pyetta.plugins"]
_builtins = "pyetta._builtins"
A plugin package may support multiple entry points. All of which can have their own load plugin entry points. To enforce
consistency, pyetta plugin entries should be modules which have the Magic Method (load_plugin) as part of their members.
The system will extract this method and call it when loading the CLI tool.
Using --extras
The CLI flag allows developers to include project specific plugins that do not need to be distributed. This allows for once of for hyper specific stages to be implemented as part of the firmware development (such as a customer firmware update process).
foo_plugin.py Example
The foo_plugin.py example shows a module that is designed as a sample for what a plugin might look like.
Tip
See the examples folder for examples of plugins. This guide only covers the basics via the foo_plugin.py
file which is also located within that folder.
Adding Sub Commands
Subcommands can be added to the CLI by creating them using click, then injecting the commands into the system via the Magic Method (load_plugin).
The snippet from examples/foo_plugin.py shows a new command being added into the system. Executing the --help
option on pyetta will result in this new loader being present.
1@click.command("lfoo",
2 help="Loader for the foo.",
3 cls=PyettaCommand, category='Loaders',
4 plugin_name="foo_plugin")
5def lfoo() -> ExecutionCallable:
6 """Custom click based cli command. This will be added dynamically at
7 runtime but can take any options typical to the cli.
8
9 Given the pipeline architecture, ensure this returns a callable that
10 registers the component to the pipeline stage."""
11
12 @execution_config
13 def configure_pipeline(_: Context,
14 pipeline: ExecutionPipeline) -> None:
15 click.echo("Running the foo loader!")
16 pipeline.loader = Loader()
17
18 # if the resource to register is a context manager, use click's
19 # context.with_resource() function to register and load it.
20
21 return configure_pipeline
All defined objects and classes will not have any effect until they are loaded. This can be done by calling the helper
method add_command_to_cli.
1def load_plugin():
2 """Magic method to load the plugin to the system. This is called by the CLI
3 prior to invoking any command."""
4 add_command_to_cli(lfoo)
Debugging and Validating Plugins
Plugins can be debugged by either running the cli tool in debug mode, or by creating a script that acts as a wrapper around the entry point.
An example of such a script is the entry point python script used to call pyetta itself. This can be called by importing
and calling the pyetta.__main__.main() function.
1import logging
2
3from pyetta.cli.cli import cli
4
5logging.basicConfig(level=logging.ERROR)
6
7
8def main():
9 cli()
10
11
12# no need to check if name is main, as our file name is explicit.
13main()
Validation at a high level can be performed by testing the correct loading of the plugin. Plugins are all loaded before
the --help dialog, so any loaded plugins will be visible in the top level help. For the plugin example, we will see
the lfoo loader present in the system.
The [plugin: foo_plugin] hint is provided by the plugin loader to inform the user which commands are provided by
which plugins.
Usage: cli_entry.py [OPTIONS] STAGE1 [ARGS]... [STAGE2 [ARGS]...]...
Python Embedded Test Toolbox and Automation
...
Loaders:
...
lfoo Loader for the foo. [plugin: foo_plugin]
...
...