Extending Albert using Python

This page focuses on the practical aspects of extending Albert using Python and its peculiarities. To get an overview of the API refer to the general extension section.

Writing Python plugins

An Albert Python plugin is a Python module having an interface defined in the Albert stub file. At runtime the stub file is written to your user Python plugin directory, where it serves as inline documentation and coding assistance in your IDE while development.

A minimal trigger query handler plugin:

from albert import *

md_iid = '3.0'
md_version = '1.0'
md_name = 'My plugin'
md_description = 'Does things'

class Plugin(PluginInstance, TriggerQueryHandler):

    def __init__(self):
        PluginInstance.__init__(self)
        TriggerQueryHandler.__init__(self)
        
    def handleTriggerQuery(self, query):
        # query.add(StandardItem(…))

Next, skim through the Python stub file. For reference see the official plugins. In case of questions see the C++ API.

Plugin directories

Python plugin directories are the directories at python/plugins relative to the app data directories.

  • xdg:
    • ~/.local/share/albert/python/plugins
    • /usr/local/share/albert/python/plugins
    • /usr/share/albert/python/plugins
  • macOS:
    • ~/Library/Application Support/Albert/python/plugins
    • /Library/Application Support/Albert/python/plugins
    • $BUNDLE_PATH/Contents/PlugIns/python/plugins

Technical notes and limitations

  • Due to the different type systems, multiple virtual inheritance of extension interfaces is not supported. However, multiple extensions can be added by reimplementing albert.PluginInstance.extensions().
  • Python plugin execution is subject to the Python Global Interpreter Lock (GIL). This means that only one thread can execute Python code at a time. This can become a problem for parallelization of queries or multithreaded global queries. Long running handlers will introduce noticeable lags. Do not block execution in your query handlers, especially not in handleGlobalQuery. If you can, use IndexQueryHandler instead, which performs the handling in C++ space.
  • PyBind11 method resolution does not support mixin behavior. Usually this should not be much of a problem, but there is one prevalent use case: Reusing id, name and description of the PluginInstance class for your Extension. For the sake of minimal boilerplate the mixin behavior is emulated for these methods. I.e. if you inherit PluginInstance and any Extension, you do not have to reimplement these methods.