diff --git a/tests/fixtures.py b/tests/fixtures.py
index a3b75f9f..1eaa1dfe 100644
--- a/tests/fixtures.py
+++ b/tests/fixtures.py
@@ -19,6 +19,8 @@ from urllib.parse import unquote, quote
# This temp file is used by one of the plugin config tests
TEMP_PLUGIN_SECRET_FILE = os.path.join(tempfile.gettempdir(), "plugin-secret")
+PLUGINS_DIR = str(pathlib.Path(__file__).parent / "plugins")
+
class TestResponse:
def __init__(self, status, headers, body):
@@ -109,7 +111,6 @@ def make_app_client(
inspect_data=None,
static_mounts=None,
template_dir=None,
- extra_plugins=None,
):
with tempfile.TemporaryDirectory() as tmpdir:
filepath = os.path.join(tmpdir, filename)
@@ -130,12 +131,6 @@ def make_app_client(
sqlite3.connect(extra_filepath).executescript(extra_sql)
files.append(extra_filepath)
os.chdir(os.path.dirname(filepath))
- plugins_dir = os.path.join(tmpdir, "plugins")
- os.mkdir(plugins_dir)
- open(os.path.join(plugins_dir, "my_plugin.py"), "w").write(PLUGIN1)
- open(os.path.join(plugins_dir, "my_plugin_2.py"), "w").write(PLUGIN2)
- for filename, content in (extra_plugins or {}).items():
- open(os.path.join(plugins_dir, filename), "w").write(content)
config = config or {}
config.update(
{
@@ -150,7 +145,7 @@ def make_app_client(
memory=memory,
cors=cors,
metadata=METADATA,
- plugins_dir=plugins_dir,
+ plugins_dir=PLUGINS_DIR,
config=config,
inspect_data=inspect_data,
static_mounts=static_mounts,
@@ -334,177 +329,6 @@ METADATA = {
},
}
-PLUGIN1 = """
-from datasette import hookimpl
-import base64
-import pint
-import json
-
-ureg = pint.UnitRegistry()
-
-
-@hookimpl
-def prepare_connection(conn, database, datasette):
- 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)
- def prepare_connection_args():
- return 'database={}, datasette.plugin_config("name-of-plugin")={}'.format(
- database, datasette.plugin_config("name-of-plugin")
- )
- conn.create_function('prepare_connection_args', 0, prepare_connection_args)
-
-
-@hookimpl
-def extra_css_urls(template, database, table, datasette):
- return ['https://plugin-example.com/{}/extra-css-urls-demo.css'.format(
- base64.b64encode(json.dumps({
- "template": template,
- "database": database,
- "table": table,
- }).encode("utf8")).decode("utf8")
- )]
-
-
-@hookimpl
-def extra_js_urls():
- return [{
- 'url': 'https://plugin-example.com/jquery.js',
- 'sri': 'SRIHASH',
- }, 'https://plugin-example.com/plugin1.js']
-
-
-@hookimpl
-def extra_body_script(template, database, table, datasette):
- return 'var extra_body_script = {};'.format(
- json.dumps({
- "template": template,
- "database": database,
- "table": table,
- "config": datasette.plugin_config(
- "name-of-plugin",
- database=database,
- table=table,
- )
- })
- )
-
-
-@hookimpl
-def render_cell(value, column, table, database, datasette):
- # Render some debug output in cell with value RENDER_CELL_DEMO
- if value != "RENDER_CELL_DEMO":
- return None
- return json.dumps({
- "column": column,
- "table": table,
- "database": database,
- "config": datasette.plugin_config(
- "name-of-plugin",
- database=database,
- table=table,
- )
- })
-
-
-@hookimpl
-def extra_template_vars(template, database, table, view_name, request, datasette):
- return {
- "extra_template_vars": json.dumps({
- "template": template,
- "scope_path": request.scope["path"] if request else None
- }, default=lambda b: b.decode("utf8"))
- }
-"""
-
-PLUGIN2 = """
-from datasette import hookimpl
-from functools import wraps
-import jinja2
-import json
-
-
-@hookimpl
-def extra_js_urls():
- return [{
- 'url': 'https://plugin-example.com/jquery.js',
- 'sri': 'SRIHASH',
- }, 'https://plugin-example.com/plugin2.js']
-
-
-@hookimpl
-def render_cell(value, database):
- # Render {"href": "...", "label": "..."} as link
- if not isinstance(value, str):
- return None
- stripped = value.strip()
- if not stripped.startswith("{") and stripped.endswith("}"):
- return None
- try:
- 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"]
- if not (
- href.startswith("/") or href.startswith("http://")
- or href.startswith("https://")
- ):
- return None
- return jinja2.Markup(
- '{label}'.format(
- database=database,
- href=jinja2.escape(data["href"]),
- label=jinja2.escape(data["label"] or "") or " "
- )
- )
-
-
-@hookimpl
-def extra_template_vars(template, database, table, view_name, request, datasette):
- async def query_database(sql):
- first_db = list(datasette.databases.keys())[0]
- return (
- await datasette.execute(first_db, sql)
- ).rows[0][0]
- async def inner():
- return {
- "extra_template_vars_from_awaitable": json.dumps({
- "template": template,
- "scope_path": request.scope["path"] if request else None,
- "awaitable": True,
- }, default=lambda b: b.decode("utf8")),
- "query_database": query_database,
- }
- return inner
-
-
-@hookimpl
-def asgi_wrapper(datasette):
- def wrap_with_databases_header(app):
- @wraps(app)
- async def add_x_databases_header(scope, recieve, send):
- async def wrapped_send(event):
- if event["type"] == "http.response.start":
- original_headers = event.get("headers") or []
- event = {
- "type": event["type"],
- "status": event["status"],
- "headers": original_headers + [
- [b"x-databases",
- ", ".join(datasette.databases.keys()).encode("utf-8")]
- ],
- }
- await send(event)
- await app(scope, recieve, wrapped_send)
- return add_x_databases_header
- return wrap_with_databases_header
-"""
-
TABLES = (
"""
CREATE TABLE simple_primary_key (
diff --git a/tests/plugins/my_plugin.py b/tests/plugins/my_plugin.py
new file mode 100644
index 00000000..e55a0a32
--- /dev/null
+++ b/tests/plugins/my_plugin.py
@@ -0,0 +1,89 @@
+from datasette import hookimpl
+import base64
+import pint
+import json
+
+ureg = pint.UnitRegistry()
+
+
+@hookimpl
+def prepare_connection(conn, database, datasette):
+ 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)
+
+ def prepare_connection_args():
+ return 'database={}, datasette.plugin_config("name-of-plugin")={}'.format(
+ database, datasette.plugin_config("name-of-plugin")
+ )
+
+ conn.create_function("prepare_connection_args", 0, prepare_connection_args)
+
+
+@hookimpl
+def extra_css_urls(template, database, table, datasette):
+ return [
+ "https://plugin-example.com/{}/extra-css-urls-demo.css".format(
+ base64.b64encode(
+ json.dumps(
+ {"template": template, "database": database, "table": table,}
+ ).encode("utf8")
+ ).decode("utf8")
+ )
+ ]
+
+
+@hookimpl
+def extra_js_urls():
+ return [
+ {"url": "https://plugin-example.com/jquery.js", "sri": "SRIHASH",},
+ "https://plugin-example.com/plugin1.js",
+ ]
+
+
+@hookimpl
+def extra_body_script(template, database, table, datasette):
+ return "var extra_body_script = {};".format(
+ json.dumps(
+ {
+ "template": template,
+ "database": database,
+ "table": table,
+ "config": datasette.plugin_config(
+ "name-of-plugin", database=database, table=table,
+ ),
+ }
+ )
+ )
+
+
+@hookimpl
+def render_cell(value, column, table, database, datasette):
+ # Render some debug output in cell with value RENDER_CELL_DEMO
+ if value != "RENDER_CELL_DEMO":
+ return None
+ return json.dumps(
+ {
+ "column": column,
+ "table": table,
+ "database": database,
+ "config": datasette.plugin_config(
+ "name-of-plugin", database=database, table=table,
+ ),
+ }
+ )
+
+
+@hookimpl
+def extra_template_vars(template, database, table, view_name, request, datasette):
+ return {
+ "extra_template_vars": json.dumps(
+ {
+ "template": template,
+ "scope_path": request.scope["path"] if request else None,
+ },
+ default=lambda b: b.decode("utf8"),
+ )
+ }
diff --git a/tests/plugins/my_plugin_2.py b/tests/plugins/my_plugin_2.py
new file mode 100644
index 00000000..fdc6956d
--- /dev/null
+++ b/tests/plugins/my_plugin_2.py
@@ -0,0 +1,94 @@
+from datasette import hookimpl
+from functools import wraps
+import jinja2
+import json
+
+
+@hookimpl
+def extra_js_urls():
+ return [
+ {"url": "https://plugin-example.com/jquery.js", "sri": "SRIHASH",},
+ "https://plugin-example.com/plugin2.js",
+ ]
+
+
+@hookimpl
+def render_cell(value, database):
+ # Render {"href": "...", "label": "..."} as link
+ if not isinstance(value, str):
+ return None
+ stripped = value.strip()
+ if not stripped.startswith("{") and stripped.endswith("}"):
+ return None
+ try:
+ 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"]
+ if not (
+ href.startswith("/")
+ or href.startswith("http://")
+ or href.startswith("https://")
+ ):
+ return None
+ return jinja2.Markup(
+ '{label}'.format(
+ database=database,
+ href=jinja2.escape(data["href"]),
+ label=jinja2.escape(data["label"] or "") or " ",
+ )
+ )
+
+
+@hookimpl
+def extra_template_vars(template, database, table, view_name, request, datasette):
+ async def query_database(sql):
+ first_db = list(datasette.databases.keys())[0]
+ return (await datasette.execute(first_db, sql)).rows[0][0]
+
+ async def inner():
+ return {
+ "extra_template_vars_from_awaitable": json.dumps(
+ {
+ "template": template,
+ "scope_path": request.scope["path"] if request else None,
+ "awaitable": True,
+ },
+ default=lambda b: b.decode("utf8"),
+ ),
+ "query_database": query_database,
+ }
+
+ return inner
+
+
+@hookimpl
+def asgi_wrapper(datasette):
+ def wrap_with_databases_header(app):
+ @wraps(app)
+ async def add_x_databases_header(scope, recieve, send):
+ async def wrapped_send(event):
+ if event["type"] == "http.response.start":
+ original_headers = event.get("headers") or []
+ event = {
+ "type": event["type"],
+ "status": event["status"],
+ "headers": original_headers
+ + [
+ [
+ b"x-databases",
+ ", ".join(datasette.databases.keys()).encode("utf-8"),
+ ]
+ ],
+ }
+ await send(event)
+
+ await app(scope, recieve, wrapped_send)
+
+ return add_x_databases_header
+
+ return wrap_with_databases_header
diff --git a/tests/plugins/view_name.py b/tests/plugins/view_name.py
new file mode 100644
index 00000000..4d29ab67
--- /dev/null
+++ b/tests/plugins/view_name.py
@@ -0,0 +1,9 @@
+from datasette import hookimpl
+
+
+@hookimpl
+def extra_template_vars(view_name, request):
+ return {
+ "view_name": view_name,
+ "request": request,
+ }
diff --git a/tests/test_api.py b/tests/test_api.py
index 7edd7ee6..260d399b 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -1267,6 +1267,7 @@ def test_plugins_json(app_client):
"templates": False,
"version": None,
},
+ {"name": "view_name.py", "static": False, "templates": False, "version": None},
] == sorted(response.json, key=lambda p: p["name"])
diff --git a/tests/test_custom_pages.py b/tests/test_custom_pages.py
index 8ac75ec8..c69facb5 100644
--- a/tests/test_custom_pages.py
+++ b/tests/test_custom_pages.py
@@ -1,22 +1,10 @@
import pytest
from .fixtures import make_app_client
-VIEW_NAME_PLUGIN = """
-from datasette import hookimpl
-
-@hookimpl
-def extra_template_vars(view_name, request):
- return {
- "view_name": view_name,
- "request": request,
- }
-"""
-
@pytest.fixture(scope="session")
def custom_pages_client(tmp_path_factory):
template_dir = tmp_path_factory.mktemp("page-templates")
- extra_plugins = {"view_name.py": VIEW_NAME_PLUGIN}
pages_dir = template_dir / "pages"
pages_dir.mkdir()
(pages_dir / "about.html").write_text("ABOUT! view_name:{{ view_name }}", "utf-8")
@@ -39,9 +27,7 @@ def custom_pages_client(tmp_path_factory):
nested_dir = pages_dir / "nested"
nested_dir.mkdir()
(nested_dir / "nest.html").write_text("Nest!", "utf-8")
- for client in make_app_client(
- template_dir=str(template_dir), extra_plugins=extra_plugins
- ):
+ for client in make_app_client(template_dir=str(template_dir)):
yield client