Keypirinha is a multi-threaded application and plugins methods are called in an asynchronous fashion. While the exposed API is thread-safe, plugin developer should keep in mind that application and plugin state may change while her code is running.
13.1.2. Plugin Lifecycle¶
Once the list of valid packages is built, Keypirinha scans their files and look
*.py scripts. Each one of those scripts is loaded through the Python
interpreter and the application performs some introspection to list all the
classes derived from
keypirinha.Plugin and instantiates them.
The application then calls the
keypirinha.Plugin.on_start() method of
every loaded plugin so they have the opportunity to do heavy one-time
initialization, if any.
For now, this call is immediately followed by a call to
keypirinha.Plugin.on_catalog() method. Note that this behavior might be
altered in a future version so
keypirinha.Plugin.on_catalog() may not
always be called at startup time.
Keypirinha monitors the Live Packages directory to detect any change made to
any file of the loaded packages (i.e.: not only the
If a modification is detected, and unless it concerns only
(in which case
keypirinha.Plugin.on_config_changed() is called), the
concerned package will be fully reloaded.
At the beginning of the reloading process, the entire package is first unloaded from the application including its resources and associated items. Also, Python is asked to destroy as much references as possible that link to the concerned Plugins.
It becomes tricky. By design, it is not possible to ensure that any Python object is totally unloaded and that its memory freed. Being it a module or a class instance. Python implements a Garbage Collector to manage its memory allocations and some reference to an object might still exist, after a module has been unloaded, due to inter-dependencies for example. While this works just fine most of the time, race conditions may sometimes occur when, for example, the code of a plugin is running while the application tries to unload it.
To avoid that and to be as flexible as possible, Keypirinha will never force a
particular plugin, or more generally a thread, to terminate. Instead, it offers
to the Plugins a very cheap API call
keypirinha.Plugin.should_terminate(), that allows Plugins to
frequently check if they should stop any work and leave the current call.
It is up to the plugin developer to call the
keypirinha.Plugin.should_terminate() method as frequently as
possible to check if the current call should be interrupted immediately.
Especially at I/O boundaries like file operation, directories scanning,
network requests, etc...
To synthesize, it is technically possible that several instances of a same plugin coexist. In that case, Keypirinha will always use and communicate with the last loaded instance so the user wouldn’t even notice. To differentiate several instances of a Plugin, Keypirinha internally gives an incremented ID number to every loaded instance of a Package and its plugins.
The InstanceID is an unsigned integer internally created and managed by the application, assigned at runtime to every loaded package and plugin. It is essentially used to ensure plugins are not messing up the catalog.
When a package is loaded for the first time, it receives the InstanceID
as well as its plugins. When any change is detected in one or several of its
files, the package is reloaded and its InstanceID is incremented.
By extension, every plugin of a package receives the InstanceID of its parent package when it is loaded or reloaded.
220.127.116.11. Messages Workflow¶
Keypirinha sends messages to its plugins either to notify them about a specific event, or to request them to perform a specific task.
When the user starts typing their search and each time search terms have
keypirinha.Plugin.on_suggest() method is called. There is
a subtlety here: if no item has been selected yet (i.e.
Tab key has not
been pressed yet), the message is broadcasted to every loaded package.
Otherwise, it is sent only to the parent plugin.
When the user wants to execute the selected item, the
keypirinha.Plugin.on_execute() method of the appropriate plugin is
called and it is up to it to actually execute the passed item.
These are the main messages that a plugin developer usually wants to implement. Other messages are mainly notifications that helps plugin to be up-to-date with user’s settings and environment.
13.1.3. Getting started¶
Plugin development should be done in the Live Packages directory.
The best way to get your hands in the dirt is to use the
Test package as a
new package skeleton, then have a look at the source code of the official
Official packages are all located in the
Appspackage shows how to use Keypirinha‘s API to scan directories and files.
Winamppackages interact with the Win32 API via the
ctypesPython standard module.
PuTTYpackages show how to dig into system’s Registry using the
winregPython standard module.
Calcpackage imports a third-party bundled Python module.
GoogleTranslatepackage does online HTTP requests to a web-service.
URLpackage extract an embedded resource file and parse it.