First working prototype of plugins, refs #14

Uses pluggy: https://pluggy.readthedocs.io/

Two example plugins - an uppercase template filter and a convert_units() SQL function.
This commit is contained in:
Simon Willison 2018-04-15 16:17:36 -07:00
commit f2720b0c6b
No known key found for this signature in database
GPG key ID: 17E2DEA2588B7F52
5 changed files with 47 additions and 1 deletions

View file

@ -1 +1,3 @@
from datasette.version import __version_info__, __version__ # noqa
from .hookspecs import hookimpl # noqa
from .hookspecs import hookspec # noqa

View file

@ -17,6 +17,7 @@ import jinja2
import hashlib
import time
import pint
import pluggy
import traceback
from .utils import (
Filters,
@ -38,6 +39,7 @@ from .utils import (
urlsafe_components,
validate_sql_select,
)
from . import hookspecs
from .version import __version__
app_root = Path(__file__).parent.parent
@ -49,6 +51,13 @@ connections = threading.local()
ureg = pint.UnitRegistry()
pm = pluggy.PluginManager('datasette')
pm.add_hookspecs(hookspecs)
import datasette.plugin_demo
pm.register(datasette.plugin_demo)
pm.load_setuptools_entrypoints('datasette')
class DatasetteError(Exception):
def __init__(self, message, title=None, error_dict=None, status=500, template=None):
self.message = message
@ -1100,6 +1109,7 @@ class Datasette:
conn.enable_load_extension(True)
for extension in self.sqlite_extensions:
conn.execute("SELECT load_extension('{}')".format(extension))
pm.hook.prepare_connection(conn=conn)
def inspect(self):
if not self._inspect:
@ -1226,6 +1236,7 @@ class Datasette:
self.jinja_env.filters['quote_plus'] = lambda u: urllib.parse.quote_plus(u)
self.jinja_env.filters['escape_sqlite'] = escape_sqlite
self.jinja_env.filters['to_css_class'] = to_css_class
pm.hook.prepare_jinja2_environment(env=self.jinja_env)
app.add_route(IndexView.as_view(self), '/<as_json:(\.jsono?)?$>')
# TODO: /favicon.ico and /-/static/ deserve far-future cache expires
app.add_route(favicon, '/favicon.ico')

15
datasette/hookspecs.py Normal file
View file

@ -0,0 +1,15 @@
from pluggy import HookimplMarker
from pluggy import HookspecMarker
hookspec = HookspecMarker('datasette')
hookimpl = HookimplMarker('datasette')
@hookspec
def prepare_connection(conn):
"Modify SQLite connection in some way e.g. register custom SQL functions"
@hookspec
def prepare_jinja2_environment(env):
"Modify Jinja2 template environment e.g. register custom template tags"

17
datasette/plugin_demo.py Normal file
View file

@ -0,0 +1,17 @@
from datasette import hookimpl
import pint
ureg = pint.UnitRegistry()
@hookimpl
def prepare_jinja2_environment(env):
env.filters['uppercase'] = lambda u: u.upper()
@hookimpl
def prepare_connection(conn):
def convert_units(amount, from_, to_):
"select convert_units(100, 'm', 'ft');"
return (amount * ureg(from_)).to(to_).to_tuple()[0]
conn.create_function('convert_units', 3, convert_units)

View file

@ -28,7 +28,8 @@ setup(
'Sanic==0.7.0',
'Jinja2==2.10',
'hupper==1.0',
'pint==0.8.1'
'pint==0.8.1',
'pluggy>=0.1.0,<1.0',
],
entry_points='''
[console_scripts]