html_url,issue_url,id,node_id,user,created_at,updated_at,author_association,body,reactions,issue,performed_via_github_app https://github.com/simonw/datasette/issues/1822#issuecomment-1258760299,https://api.github.com/repos/simonw/datasette/issues/1822,1258760299,IC_kwDOBm6k_c5LByhr,9599,2022-09-26T23:25:12Z,2022-09-26T23:25:55Z,OWNER,"A start: ```diff diff --git a/datasette/utils/asgi.py b/datasette/utils/asgi.py index 8a2fa060..41ade961 100644 --- a/datasette/utils/asgi.py +++ b/datasette/utils/asgi.py @@ -118,7 +118,7 @@ class Request: return dict(parse_qsl(body.decode(""utf-8""), keep_blank_values=True)) @classmethod - def fake(cls, path_with_query_string, method=""GET"", scheme=""http"", url_vars=None): + def fake(cls, path_with_query_string, *, method=""GET"", scheme=""http"", url_vars=None): """"""Useful for constructing Request objects for tests"""""" path, _, query_string = path_with_query_string.partition(""?"") scope = { @@ -204,7 +204,7 @@ class AsgiWriter: ) -async def asgi_send_json(send, info, status=200, headers=None): +async def asgi_send_json(send, info, *, status=200, headers=None): headers = headers or {} await asgi_send( send, @@ -215,7 +215,7 @@ async def asgi_send_json(send, info, status=200, headers=None): ) -async def asgi_send_html(send, html, status=200, headers=None): +async def asgi_send_html(send, html, *, status=200, headers=None): headers = headers or {} await asgi_send( send, @@ -226,7 +226,7 @@ async def asgi_send_html(send, html, status=200, headers=None): ) -async def asgi_send_redirect(send, location, status=302): +async def asgi_send_redirect(send, location, *, status=302): await asgi_send( send, """", @@ -236,12 +236,12 @@ async def asgi_send_redirect(send, location, status=302): ) -async def asgi_send(send, content, status, headers=None, content_type=""text/plain""): +async def asgi_send(send, content, status, *, headers=None, content_type=""text/plain""): await asgi_start(send, status, headers, content_type) await send({""type"": ""http.response.body"", ""body"": content.encode(""utf-8"")}) -async def asgi_start(send, status, headers=None, content_type=""text/plain""): +async def asgi_start(send, status, *, headers=None, content_type=""text/plain""): headers = headers or {} # Remove any existing content-type header headers = {k: v for k, v in headers.items() if k.lower() != ""content-type""} @@ -259,7 +259,7 @@ async def asgi_start(send, status, headers=None, content_type=""text/plain""): async def asgi_send_file( - send, filepath, filename=None, content_type=None, chunk_size=4096, headers=None + send, filepath, filename=None, *, content_type=None, chunk_size=4096, headers=None ): headers = headers or {} if filename: @@ -284,7 +284,7 @@ async def asgi_send_file( ) -def asgi_static(root_path, chunk_size=4096, headers=None, content_type=None): +def asgi_static(root_path, *, chunk_size=4096, headers=None, content_type=None): root_path = Path(root_path) async def inner_static(request, send): @@ -313,7 +313,7 @@ def asgi_static(root_path, chunk_size=4096, headers=None, content_type=None): class Response: - def __init__(self, body=None, status=200, headers=None, content_type=""text/plain""): + def __init__(self, body=None, *, status=200, headers=None, content_type=""text/plain""): self.body = body self.status = status self.headers = headers or {} @@ -346,6 +346,7 @@ class Response: self, key, value="""", + *, max_age=None, expires=None, path=""/"", @@ -374,7 +375,7 @@ class Response: self._set_cookie_headers.append(cookie.output(header="""").strip()) @classmethod - def html(cls, body, status=200, headers=None): + def html(cls, body, *, status=200, headers=None): return cls( body, status=status, @@ -383,7 +384,7 @@ class Response: ) @classmethod - def text(cls, body, status=200, headers=None): + def text(cls, body, *, status=200, headers=None): return cls( str(body), status=status, @@ -392,7 +393,7 @@ class Response: ) @classmethod - def json(cls, body, status=200, headers=None, default=None): + def json(cls, body, *, status=200, headers=None, default=None): return cls( json.dumps(body, default=default), status=status, @@ -401,7 +402,7 @@ class Response: ) @classmethod - def redirect(cls, path, status=302, headers=None): + def redirect(cls, path, *, status=302, headers=None): headers = headers or {} headers[""Location""] = path return cls("""", status=status, headers=headers) @@ -412,6 +413,7 @@ class AsgiFileDownload: self, filepath, filename=None, + *, content_type=""application/octet-stream"", headers=None, ): ``` ```diff diff --git a/datasette/app.py b/datasette/app.py index 03d1dacc..4d4e5584 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -190,6 +190,7 @@ class Datasette: def __init__( self, files=None, + *, immutables=None, cache_headers=True, cors=False, ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1386854246, https://github.com/simonw/datasette/issues/1822#issuecomment-1258757544,https://api.github.com/repos/simonw/datasette/issues/1822,1258757544,IC_kwDOBm6k_c5LBx2o,9599,2022-09-26T23:21:23Z,2022-09-26T23:21:23Z,OWNER,Everything on https://docs.datasette.io/en/stable/internals.html that uses keyword arguments should do this I think.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1386854246,