render_cell(value) plugin hook, closes #352

New plugin hook for customizing the way cells values are rendered in HTML.

The first full example of this hook in use is https://github.com/simonw/datasette-json-html
This commit is contained in:
Simon Willison 2018-08-04 17:14:56 -07:00 committed by GitHub
commit 4ac9132240
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 150 additions and 30 deletions

View file

@ -2,7 +2,6 @@ import asyncio
import click
import collections
import hashlib
import importlib
import itertools
import os
import sqlite3
@ -14,7 +13,6 @@ from concurrent import futures
from pathlib import Path
from markupsafe import Markup
import pluggy
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader
from sanic import Sanic, response
from sanic.exceptions import InvalidUsage, NotFound
@ -28,7 +26,6 @@ from .views.index import IndexView
from .views.special import JsonDataView
from .views.table import RowView, TableView
from . import hookspecs
from .utils import (
InterruptedError,
Results,
@ -40,26 +37,13 @@ from .utils import (
to_css_class
)
from .inspect import inspect_hash, inspect_views, inspect_tables
from .plugins import pm
from .version import __version__
default_plugins = (
"datasette.publish.heroku",
"datasette.publish.now",
)
app_root = Path(__file__).parent.parent
connections = threading.local()
pm = pluggy.PluginManager("datasette")
pm.add_hookspecs(hookspecs)
pm.load_setuptools_entrypoints("datasette")
# Load default plugins
for plugin in default_plugins:
mod = importlib.import_module(plugin)
pm.register(mod, plugin)
ConfigOption = collections.namedtuple(
"ConfigOption", ("name", "default", "help")

View file

@ -28,3 +28,8 @@ def extra_js_urls():
@hookspec
def publish_subcommand(publish):
"Subcommands for 'datasette publish'"
@hookspec(firstresult=True)
def render_cell(value):
"Customize rendering of HTML table cell values"

17
datasette/plugins.py Normal file
View file

@ -0,0 +1,17 @@
import importlib
import pluggy
from . import hookspecs
default_plugins = (
"datasette.publish.heroku",
"datasette.publish.now",
)
pm = pluggy.PluginManager("datasette")
pm.add_hookspecs(hookspecs)
pm.load_setuptools_entrypoints("datasette")
# Load default plugins
for plugin in default_plugins:
mod = importlib.import_module(plugin)
pm.register(mod, plugin)

View file

@ -16,7 +16,6 @@ import shutil
import urllib
import numbers
# From https://www.sqlite.org/lang_keywords.html
reserved_words = set((
'abort action add after all alter analyze and as asc attach autoincrement '

View file

@ -13,6 +13,7 @@ from sanic.exceptions import NotFound
from sanic.views import HTTPMethodView
from datasette import __version__
from datasette.plugins import pm
from datasette.utils import (
CustomJSONEncoder,
InterruptedError,
@ -493,14 +494,19 @@ class BaseView(RenderMixin):
display_row = []
for value in row:
display_value = value
if value in ("", None):
display_value = jinja2.Markup(" ")
elif is_url(str(value).strip()):
display_value = jinja2.Markup(
'<a href="{url}">{url}</a>'.format(
url=jinja2.escape(value.strip())
# Let the plugins have a go
plugin_value = pm.hook.render_cell(value=value)
if plugin_value is not None:
display_value = plugin_value
else:
if value in ("", None):
display_value = jinja2.Markup("&nbsp;")
elif is_url(str(display_value).strip()):
display_value = jinja2.Markup(
'<a href="{url}">{url}</a>'.format(
url=jinja2.escape(value.strip())
)
)
)
display_row.append(display_value)
display_rows.append(display_row)
return {

View file

@ -5,6 +5,7 @@ import jinja2
from sanic.exceptions import NotFound
from sanic.request import RequestParameters
from datasette.plugins import pm
from datasette.utils import (
CustomRow,
Filters,
@ -22,7 +23,6 @@ from datasette.utils import (
urlsafe_components,
value_as_boolean,
)
from .base import BaseView, DatasetteError, ureg
LINK_WITH_LABEL = '<a href="/{database}/{table}/{link_id}">{label}</a>&nbsp;<em>{id}</em>'
@ -166,7 +166,11 @@ class RowTableShared(BaseView):
# already shown in the link column.
continue
if isinstance(value, dict):
# First let the plugins have a go
plugin_display_value = pm.hook.render_cell(value=value)
if plugin_display_value is not None:
display_value = plugin_display_value
elif isinstance(value, dict):
# It's an expanded foreign key - display link to other row
label = value["label"]
value = value["value"]