Instructions on how to write a new DDE plugin.
When to write a plugin
Only write a plugin if you want to create an DDE export for databases like UDD or apt-xapian-index.
If you just periodically generate a small amount of static data, you can publish it by saving it in a format like yaml, json or pickle and put it in ~/.dde (see DDE/StaticData).
The plugin interface
Plugins are instances of an octofuss.Tree, which represent a subtree in the DDE information space; an octofuss.Tree is defined as an object which implements the following 4 methods:
lhas, that tells if a subtree exists or not
lget, that gets the value of a node in the subtree
llist, that list the child nodes of a node in the subtree
ldoc, that gives documentation about a node in the subtree
Plugins get one parameter called path which the path of the requested subtree split into a list. [] means the node itself.
Some optional keyword arguments can be passed as hints for optimization purposes, and you should normally ignore them: this explains why every method also has a **kw parameter, but besides remembering to put it there, you should not worry about it.
Here is some annotated example plugin implementing a node with a value and no subtrees:
import octofuss # Plugin interface class Plugin(octofuss.Tree): def __init__(self): # The first parameter is the name of this node in the tree # The second parameter is the documentation for this node to use # if the 'ldoc' method is missing super(Plugin, self).__init__("plugin", "Example plugin") def lhas(self, path, **kw): """ Return True if the path exists, False if not. """ # We are empty, so no subtrees exist: if path: return False # But we exist, so if path is [] return True: return True def lget(self, path, **kw): """ Return the value of the node at path, or None if the path does not exist """ # We are empty, so no subtrees exist: if path: return None # If path is [], return our value return "I am an example plugin" def llist(self, path, **kw): """ Return a list with the names of the child nodes. If there are no child nodes or the path is invalid, return [] """ return [] def ldoc(self, path, **kw): """ Return the documentation for the given node. Return None if the node does not exist. """ if path: return None return "Example plugin"
To allow DDE to instantiate the plugin, add to your module an 'init' function. It is passed optional information as keyword parameters (currently not really used, but planned for the future), and generates dictionaries with the octofuss.Tree objects and their mount point in the DDE tree:
def init(**kw): if os.environ.get("DDE_AVOID_CRUFT", None) is not None: return yield dict( tree = Plugin(), # Mount as /test/plugin root = "/test" )
The init function should only generate those plugins that are in a condition to be run (for example, ensuring that their data files exist, or that connections to their databases can be established).
Tips & Tricks
Do not start to write a plugin from scratch: have a look at the existing plugins at the DDE git repository for inspiration and for stealing ideas.
Get in touch with Enrico if you need help
- Only implement views corresponding to common use cases: DDE should be simple to query. You should not reimplment SQL or LDAP using URLs: for special needs, people can craft a SQL or LDAP query, and if the need becomes more general, the query can be turned into a DDE plugin.
See also: