datasette.urls.table(..., format="json"), closes #1035

Also improved tests for datasette.urls and added format= to some other methods
This commit is contained in:
Simon Willison 2020-10-31 11:16:28 -07:00
commit 11eb1e026f
7 changed files with 92 additions and 40 deletions

View file

@ -53,6 +53,7 @@ from .utils import (
format_bytes,
module_from_path,
parse_metadata,
path_with_format,
resolve_env_secrets,
sqlite3,
to_css_class,
@ -1285,13 +1286,16 @@ class Urls:
def __init__(self, ds):
self.ds = ds
def path(self, path):
def path(self, path, format=None):
if path.startswith("/"):
path = path[1:]
return self.ds.config("base_url") + path
path = self.ds.config("base_url") + path
if format is not None:
path = path_with_format(path=path, format=format)
return path
def instance(self):
return self.path("")
def instance(self, format=None):
return self.path("", format=format)
def static(self, path):
return self.path("-/static/{}".format(path))
@ -1302,21 +1306,33 @@ class Urls:
def logout(self):
return self.path("-/logout")
def database(self, database):
def database(self, database, format=None):
db = self.ds.databases[database]
if self.ds.config("hash_urls") and db.hash:
return self.path("{}-{}".format(database, db.hash[:HASH_LENGTH]))
path = self.path(
"{}-{}".format(database, db.hash[:HASH_LENGTH]), format=format
)
else:
return self.path(database)
path = self.path(database, format=format)
return path
def table(self, database, table):
return "{}/{}".format(self.database(database), urllib.parse.quote_plus(table))
def table(self, database, table, format=None):
path = "{}/{}".format(self.database(database), urllib.parse.quote_plus(table))
if format is not None:
path = path_with_format(path=path, format=format)
return path
def query(self, database, query):
return "{}/{}".format(self.database(database), urllib.parse.quote_plus(query))
def query(self, database, query, format=None):
path = "{}/{}".format(self.database(database), urllib.parse.quote_plus(query))
if format is not None:
path = path_with_format(path=path, format=format)
return path
def row(self, database, table, row_path):
return "{}/{}".format(self.table(database, table), row_path)
def row(self, database, table, row_path, format=None):
path = "{}/{}".format(self.table(database, table), row_path)
if format is not None:
path = path_with_format(path=path, format=format)
return path
def row_blob(self, database, table, row_path, column):
return self.table(database, table) + "/{}.blob?_blob_column={}".format(

View file

@ -678,9 +678,11 @@ async def resolve_table_and_format(
return table_and_format, None
def path_with_format(request, format, extra_qs=None, replace_format=None):
def path_with_format(
*, request=None, path=None, format=None, extra_qs=None, replace_format=None
):
qs = extra_qs or {}
path = request.path
path = request.path if request else path
if replace_format and path.endswith(".{}".format(replace_format)):
path = path[: -(1 + len(replace_format))]
if "." in path:
@ -689,11 +691,11 @@ def path_with_format(request, format, extra_qs=None, replace_format=None):
path = "{}.{}".format(path, format)
if qs:
extra = urllib.parse.urlencode(sorted(qs.items()))
if request.query_string:
if request and request.query_string:
path = "{}?{}&{}".format(path, request.query_string, extra)
else:
path = "{}?{}".format(path, extra)
elif request.query_string:
elif request and request.query_string:
path = "{}?{}".format(path, request.query_string)
return path

View file

@ -333,8 +333,8 @@ class DataView(BaseView):
cell = self.ds.absolute_url(
request,
path_with_format(
request,
"blob",
request=request,
format="blob",
extra_qs={
"_blob_column": column,
"_blob_hash": hashlib.sha256(
@ -535,11 +535,13 @@ class DataView(BaseView):
it_can_render = await await_me_maybe(it_can_render)
if it_can_render:
renderers[key] = path_with_format(
request, key, {**url_labels_extra}
request=request, format=key, extra_qs={**url_labels_extra}
)
url_csv_args = {"_size": "max", **url_labels_extra}
url_csv = path_with_format(request, "csv", url_csv_args)
url_csv = path_with_format(
request=request, format="csv", extra_qs=url_csv_args
)
url_csv_path = url_csv.split("?")[0]
context = {
**data,

View file

@ -346,8 +346,8 @@ class QueryView(DataView):
)
elif isinstance(display_value, bytes):
blob_url = path_with_format(
request,
"blob",
request=request,
format="blob",
extra_qs={
"_blob_column": column,
"_blob_hash": hashlib.sha256(