diff --git a/datasette/app.py b/datasette/app.py index 353e4a10dd..e6ece8adb6 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -4,8 +4,8 @@ import datetime import glob import hashlib +import httpx import inspect -import itertools from itsdangerous import BadSignature import json import os @@ -18,7 +18,6 @@ from concurrent import futures from pathlib import Path -import click from markupsafe import Markup from itsdangerous import URLSafeSerializer import jinja2 @@ -62,7 +61,6 @@ Forbidden, NotFound, Request, - Response, asgi_static, asgi_send, asgi_send_html, @@ -312,6 +310,7 @@ def __init__( self._register_renderers() self._permission_checks = collections.deque(maxlen=200) self._root_token = secrets.token_hex(32) + self.client = DatasetteClient(self) async def invoke_startup(self): for hook in pm.hook.startup(datasette=self): @@ -1209,3 +1208,45 @@ def route_pattern_from_filepath(filepath): class NotFoundExplicit(NotFound): pass + + +class DatasetteClient: + def __init__(self, ds): + self.app = ds.app() + + def _fix(self, path): + if path.startswith("/"): + path = "http://localhost{}".format(path) + return path + + async def get(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.get(self._fix(path), **kwargs) + + async def options(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.options(self._fix(path), **kwargs) + + async def head(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.head(self._fix(path), **kwargs) + + async def post(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.post(self._fix(path), **kwargs) + + async def put(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.put(self._fix(path), **kwargs) + + async def patch(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.patch(self._fix(path), **kwargs) + + async def delete(self, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.delete(self._fix(path), **kwargs) + + async def request(self, method, path, **kwargs): + async with httpx.AsyncClient(app=self.app) as client: + return await client.request(method, self._fix(path), **kwargs) diff --git a/datasette/cli.py b/datasette/cli.py index ca02afad55..43e03f0ad4 100644 --- a/datasette/cli.py +++ b/datasette/cli.py @@ -450,7 +450,7 @@ def serve( asyncio.get_event_loop().run_until_complete(check_databases(ds)) if get: - client = TestClient(ds.app()) + client = TestClient(ds) response = client.get(get) click.echo(response.text) exit_code = 0 if response.status == 200 else 1 diff --git a/datasette/templates/_table.html b/datasette/templates/_table.html index 1dd9421248..657890456a 100644 --- a/datasette/templates/_table.html +++ b/datasette/templates/_table.html @@ -8,9 +8,9 @@ {{ column.name }} {% else %} {% if column.name == sort %} - {{ column.name }} ▼ + {{ column.name }} ▼ {% else %} - {{ column.name }}{% if column.name == sort_desc %} ▲{% endif %} + {{ column.name }}{% if column.name == sort_desc %} ▲{% endif %} {% endif %} {% endif %} diff --git a/datasette/templates/query.html b/datasette/templates/query.html index c6574f31b8..0add74a8c7 100644 --- a/datasette/templates/query.html +++ b/datasette/templates/query.html @@ -58,7 +58,7 @@
This data as {% for name, url in renderers.items() %}{{ name }}{{ ", " if not loop.last }}{% endfor %}, CSV
+This data as {% for name, url in renderers.items() %}{{ name }}{{ ", " if not loop.last }}{% endfor %}, CSV