Skip to content

Commit d407fcd

Browse files
committed
Some initial documentation on plugin development
1 parent 6bf49f5 commit d407fcd

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

docs/Developing-Plugins.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Developing Plugins for Kalico
2+
3+
Kalico now supports loading external plugins packaged as a python distribution. This document is meant as a light guide for plugin authors to get started packaging their plugin.
4+
5+
Commonly, these plugins will simply be symlinked or copied into `klippy/extras/`. This has multiple downsides
6+
however. Moonraker will note that Kalico is "dirty" (there are changes to files) and future changes to Kalico may conflict with a plugin.
7+
8+
`klippy/plugins/` was implemented to give a "safer" location for plugin authors to install to, however adoption has barely begun.
9+
10+
To make the whole system more user-friendly, and prevent some of these issues from arising, Kalico has implemented a Python-standard plugin loading system.
11+
12+
13+
## A light overview of Python packaging
14+
15+
Python packages (often distributed as `my_package-v0.0.0.tar.gz` or `my_package-v0.0.0.whl`) are effectively just an installable zip file, adding code to a python environment.
16+
17+
Within these files you can define metadata that allows other packages to interact with yours in sepcific ways.
18+
19+
Kalico's official plugin support takes advantage of the Python [Entry Points for Plugins](https://setuptools.pypa.io/en/latest/userguide/entry_point.html#entry-points-for-plugins) system, allowing for easy installation and discovery.
20+
21+
Once installed, a package with an entry-point under `kalico.plugins` can be discovered by Kalico and loaded at runtime (See `Printer.load_object()` in [`klippy/printer.py`](../klippy/printer.py)).
22+
23+
A full example plugin can be found at [github.com/KalicoCrew/plugin-example](https://github.com/KalicoCrew/plugin-example)
24+
25+
26+
## Writing a new plugin from scratch
27+
28+
At it's core, a Kalico plugin is a python script that exposes functions for loading the plugin based on a configuration.
29+
30+
```python
31+
from __future__ import annotations
32+
import typing
33+
34+
if typing.TYPE_CHECKING:
35+
from klippy.configfile import ConfigWrapper
36+
37+
38+
class MyPlugin:
39+
def __init__(self, config: ConfigWrapper):
40+
self.printer = config.get_printer()
41+
self.value = config.get("value")
42+
43+
def get_status(self, eventtime: float | None = None) -> dict:
44+
"If defined, get_status is used to share information with other parts of Klippy"
45+
46+
return {
47+
# In templates, `{printer.my_plugin.value}` will be available
48+
"value": self.value
49+
}
50+
51+
52+
def load_config(config: ConfigWrapper) -> MyPlugin:
53+
"Create an instance of MyPlugin when loaded as [my_plugin]"
54+
55+
return MyPlugin(config)
56+
57+
58+
# def load_config_prefix(config: ConfigWrapper) -> MyPlugin:
59+
# """
60+
# Create a named instance of MyPlugin, such as [my_plugin has_a_name]
61+
#
62+
# config.get_name() would return the "my_plugin has_a_name". Often that name
63+
# will be read as `config.get_name().split(maxsplit=1)[-1]` leaving only "has_a_name"
64+
# """
65+
#
66+
# return MyPlugin(config)
67+
```
68+
69+
To package your plugin for use in Kalico, you need a build tool such as [`uv`](https://docs.astral.sh/uv/).
70+
71+
Next to `my_plugin.py`, create a file named `pyproject.toml`.
72+
73+
```toml
74+
[project]
75+
name = "my_plugin"
76+
version = "0.1"
77+
description = "A good description of my plugin"
78+
readme = "readme.md"
79+
classifiers = [
80+
"Environment :: Plugins",
81+
"Framework :: Klippy",
82+
]
83+
84+
[project.entry-points."kalico.plugins"]
85+
my_plugin = "my_plugin"
86+
```
87+
88+
You will also want to create `readme.md` with some example documentation about how to configure and use your plugin
89+
90+
At this point, you have the bare minimum to build and install your Kalico plugin.
91+
`uv build` will package your plugin, creating `dist/my_plugin-0.1.tar.gz` and `dist/my_plugin-0.1-py3-none-any.whl`.
92+
93+
Kalico will discover the plugin on startup, expose the module's documentation to your frontend, and load the plugin when requested by the end users configuration.

docs/_kalico/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ nav:
138138
- Exclude_Object.md
139139
- Using_PWM_Tools.md
140140
- Developer Documentation:
141+
- Developing-Plugins.md
141142
- Code_Overview.md
142143
- Kinematics.md
143144
- Protocol.md

0 commit comments

Comments
 (0)