Plugins ======= Datasette's plugin system is currently under active development. It allows additional features to be implemented as Python code (or, soon, JavaScript) which can be wrapped up in a separate Python package. The underlying mechanism uses `pluggy `_. You can follow the development of plugins in `issue #14 `_. Using plugins ------------- If a plugin has been packaged for distribution using setuptools you can use the plugin by installing it alongside Datasette in the same virtual environment or Docker container. You can also define one-off per-project plugins by saving them as ``plugin_name.py`` functions in a ``plugins/`` folder and then passing that folder to ``datasette serve``. Writing plugins --------------- The easiest way to write a plugin is to create a ``my_plugin.py`` file and drop it into your ``plugins/`` directory. Here is an example plugin, which adds a new custom SQL function called ``hello_world()`` which takes no arguments and returns the string ``Hello world!``. .. code-block:: python from datasette import hookimpl @hookimpl def prepare_connection(conn): conn.create_function('hello_world', 0, lambda: 'Hello world!') If you save this in ``plugins/my_plugin.py`` you can then start Datasette like this:: datasette serve mydb.db --plugins-dir=plugins/ Now you can navigate to http://localhost:8001/mydb and run this SQL:: select hello_world(); To see the output of your plugin. Packaging a plugin ------------------ Plugins can be packaged using Python setuptools. You can see an example of a packaged plugin at https://github.com/simonw/datasette-plugin-demos The example consists of two files: a ``setup.py`` file that defines the plugin: .. code-block:: python from setuptools import setup VERSION = '0.1' setup( name='datasette-plugin-demos', description='Examples of plugins for Datasette', author='Simon Willison', url='https://github.com/simonw/datasette-plugin-demos', license='Apache License, Version 2.0', version=VERSION, py_modules=['datasette_plugin_demos'], entry_points={ 'datasette': [ 'plugin_demos = datasette_plugin_demos' ] }, install_requires=['datasette'] ) And a Python module file, ``datasette_plugin_demos.py``, that implements the plugin: .. code-block:: python from datasette import hookimpl import random @hookimpl def prepare_jinja2_environment(env): env.filters['uppercase'] = lambda u: u.upper() @hookimpl def prepare_connection(conn): conn.create_function('random_integer', 2, random.randint) Having built a plugin in this way you can turn it into an installable package using the following command:: python3 setup.py sdist This will create a ``.tar.gz`` file in the ``dist/`` directory. You can then install your new plugin into a Datasette virtual environment or Docker container using ``pip``:: pip install datasette-plugin-demos-0.1.tar.gz To learn how to upload your plugin to `PyPI `_ for use by other people, read the PyPA guide to `Packaging and distributing projects `_. Plugin hooks ------------ Datasette will eventually have many more plugin hooks. You can track and contribute to their development in `issue #14 `_. prepare_connection(conn) ~~~~~~~~~~~~~~~~~~~~~~~~ This hook is called when a new SQLite database connection is created. You can use it to `register custom SQL functions `_, aggregates and collations. For example: .. code-block:: python from datasette import hookimpl import random @hookimpl def prepare_connection(conn): conn.create_function('random_integer', 2, random.randint) This registers a SQL function called ``random_integer`` which takes two arguments and can be called like this:: select random_integer(1, 10); prepare_jinja2_environment(env) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This hook is called with the Jinja2 environment that is used to evaluate Datasette HTML templates. You can use it to do things like `register custom template filters `_, for example: .. code-block:: python from datasette import hookimpl @hookimpl def prepare_jinja2_environment(env): env.filters['uppercase'] = lambda u: u.upper() You can now use this filter in your custom templates like so:: Table name: {{ table|uppercase }}