diff --git a/datasette/app.py b/datasette/app.py
index 052131d0..e263cc48 100644
--- a/datasette/app.py
+++ b/datasette/app.py
@@ -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")
diff --git a/datasette/utils.py b/datasette/utils.py
index 8ecd9025..29360b35 100644
--- a/datasette/utils.py
+++ b/datasette/utils.py
@@ -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 '
diff --git a/datasette/views/base.py b/datasette/views/base.py
index fbb9b173..f376c327 100644
--- a/datasette/views/base.py
+++ b/datasette/views/base.py
@@ -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,
@@ -494,7 +495,6 @@ class BaseView(RenderMixin):
for value in row:
display_value = value
# Let the plugins have a go
- from datasette.app import pm
plugin_value = pm.hook.render_cell(value=value)
if plugin_value is not None:
display_value = plugin_value
diff --git a/datasette/views/table.py b/datasette/views/table.py
index 654e60fa..ae71d33d 100644
--- a/datasette/views/table.py
+++ b/datasette/views/table.py
@@ -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 = '{label} {id}'
@@ -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"]
diff --git a/tests/fixtures.py b/tests/fixtures.py
index 955b155d..ffacfa51 100644
--- a/tests/fixtures.py
+++ b/tests/fixtures.py
@@ -223,6 +223,8 @@ def extra_js_urls():
@hookimpl
def render_cell(value):
# Render {"href": "...", "label": "..."} as link
+ if not isinstance(value, str):
+ return None
stripped = value.strip()
if not stripped.startswith("{") and stripped.endswith("}"):
return None
@@ -230,6 +232,8 @@ def render_cell(value):
data = json.loads(value)
except ValueError:
return None
+ if not isinstance(data, dict):
+ return None
if set(data.keys()) != {"href", "label"}:
return None
href = data["href"]
@@ -389,9 +393,12 @@ INSERT INTO "searchable_fts" (rowid, text1, text2, [name with . and spaces])
CREATE TABLE [select] (
[group] text,
[having] text,
- [and] text
+ [and] text,
+ [json] text
+);
+INSERT INTO [select] VALUES ('group', 'having', 'and',
+ '{"href": "http://example.com/", "label":"Example"}'
);
-INSERT INTO [select] VALUES ('group', 'having', 'and');
CREATE TABLE infinity (
value REAL
diff --git a/tests/test_api.py b/tests/test_api.py
index 8f67a9eb..f76795fe 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -231,7 +231,7 @@ def test_database_page(app_client):
],
},
}, {
- 'columns': ['group', 'having', 'and'],
+ 'columns': ['group', 'having', 'and', 'json'],
'name': 'select',
'count': 1,
'hidden': False,
@@ -599,6 +599,7 @@ def test_table_with_reserved_word_name(app_client):
'group': 'group',
'having': 'having',
'and': 'and',
+ 'json': '{"href": "http://example.com/", "label":"Example"}'
}]