Keyword-only arguments for a bunch of internal methods, refs #1822

pull/1823/head
Simon Willison 2022-09-26 17:43:55 -07:00
rodzic 5f9f567acb
commit 49a11a6042
2 zmienionych plików z 38 dodań i 26 usunięć

Wyświetl plik

@ -190,6 +190,7 @@ class Datasette:
def __init__(
self,
files=None,
*,
immutables=None,
cache_headers=True,
cors=False,
@ -410,7 +411,7 @@ class Datasette:
def unsign(self, signed, namespace="default"):
return URLSafeSerializer(self._secret, namespace).loads(signed)
def get_database(self, name=None, route=None):
def get_database(self, name=None, *, route=None):
if route is not None:
matches = [db for db in self.databases.values() if db.route == route]
if not matches:
@ -421,7 +422,7 @@ class Datasette:
name = [key for key in self.databases.keys() if key != "_internal"][0]
return self.databases[name]
def add_database(self, db, name=None, route=None):
def add_database(self, db, name=None, *, route=None):
new_databases = self.databases.copy()
if name is None:
# Pick a unique name for this database
@ -466,7 +467,7 @@ class Datasette:
orig[key] = upd_value
return orig
def metadata(self, key=None, database=None, table=None, fallback=True):
def metadata(self, key=None, *, database=None, table=None, fallback=True):
"""
Looks up metadata, cascading backwards from specified level.
Returns None if metadata value is not found.
@ -518,7 +519,7 @@ class Datasette:
def _metadata(self):
return self.metadata()
def plugin_config(self, plugin_name, database=None, table=None, fallback=True):
def plugin_config(self, plugin_name, *, database=None, table=None, fallback=True):
"""Return config for plugin, falling back from specified database/table"""
plugins = self.metadata(
"plugins", database=database, table=table, fallback=fallback
@ -714,6 +715,7 @@ class Datasette:
db_name,
sql,
params=None,
*,
truncate=False,
custom_time_limit=None,
page_size=None,
@ -943,7 +945,7 @@ class Datasette:
)
async def render_template(
self, templates, context=None, request=None, view_name=None
self, templates, context=None, *, request=None, view_name=None
):
if not self._startup_invoked:
raise Exception("render_template() called before await ds.invoke_startup()")

Wyświetl plik

@ -118,7 +118,9 @@ 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 +206,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 +217,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 +228,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 +238,12 @@ async def asgi_send_redirect(send, location, status=302):
)
async def asgi_send(send, content, status, headers=None, content_type="text/plain"):
await asgi_start(send, status, headers, content_type)
async def asgi_send(send, content, status, *, headers=None, content_type="text/plain"):
await asgi_start(send, status=status, headers=headers, content_type=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 +261,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:
@ -270,9 +272,11 @@ async def asgi_send_file(
if first:
await asgi_start(
send,
200,
headers,
content_type or guess_type(str(filepath))[0] or "text/plain",
status=200,
headers=headers,
content_type=content_type
or guess_type(str(filepath))[0]
or "text/plain",
)
first = False
more_body = True
@ -284,7 +288,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):
@ -292,28 +296,32 @@ def asgi_static(root_path, chunk_size=4096, headers=None, content_type=None):
try:
full_path = (root_path / path).resolve().absolute()
except FileNotFoundError:
await asgi_send_html(send, "404: Directory not found", 404)
await asgi_send_html(send, "404: Directory not found", status=404)
return
if full_path.is_dir():
await asgi_send_html(send, "403: Directory listing is not allowed", 403)
await asgi_send_html(
send, "403: Directory listing is not allowed", status=403
)
return
# Ensure full_path is within root_path to avoid weird "../" tricks
try:
full_path.relative_to(root_path.resolve())
except ValueError:
await asgi_send_html(send, "404: Path not inside root path", 404)
await asgi_send_html(send, "404: Path not inside root path", status=404)
return
try:
await asgi_send_file(send, full_path, chunk_size=chunk_size)
except FileNotFoundError:
await asgi_send_html(send, "404: File not found", 404)
await asgi_send_html(send, "404: File not found", status=404)
return
return inner_static
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 +354,7 @@ class Response:
self,
key,
value="",
*,
max_age=None,
expires=None,
path="/",
@ -374,7 +383,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 +392,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 +401,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 +410,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 +421,7 @@ class AsgiFileDownload:
self,
filepath,
filename=None,
*,
content_type="application/octet-stream",
headers=None,
):