kopia lustrzana https://github.com/simonw/datasette
Replaced sanic.response and finished removing Sanic entirely in favour of ASGI
rodzic
eba15fb5a8
commit
b794554a26
|
@ -168,23 +168,7 @@ class AsgiView:
|
||||||
response = await self.dispatch_request(
|
response = await self.dispatch_request(
|
||||||
request, **scope["url_route"]["kwargs"]
|
request, **scope["url_route"]["kwargs"]
|
||||||
)
|
)
|
||||||
if hasattr(response, "asgi_send"):
|
await response.asgi_send(send)
|
||||||
await response.asgi_send(send)
|
|
||||||
else:
|
|
||||||
headers = {}
|
|
||||||
headers.update(response.headers)
|
|
||||||
headers["content-type"] = response.content_type
|
|
||||||
await send(
|
|
||||||
{
|
|
||||||
"type": "http.response.start",
|
|
||||||
"status": response.status,
|
|
||||||
"headers": [
|
|
||||||
[key.encode("utf-8"), value.encode("utf-8")]
|
|
||||||
for key, value in headers.items()
|
|
||||||
],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
await send({"type": "http.response.body", "body": response.body})
|
|
||||||
|
|
||||||
view.view_class = cls
|
view.view_class = cls
|
||||||
view.__doc__ = cls.__doc__
|
view.__doc__ = cls.__doc__
|
||||||
|
@ -330,6 +314,57 @@ def asgi_static(root_path, chunk_size=4096, headers=None, content_type=None):
|
||||||
return inner_static
|
return inner_static
|
||||||
|
|
||||||
|
|
||||||
|
class Response:
|
||||||
|
def __init__(self, body=None, status=200, headers=None, content_type="text/plain"):
|
||||||
|
self.body = body
|
||||||
|
self.status = status
|
||||||
|
self.headers = headers or {}
|
||||||
|
self.content_type = content_type
|
||||||
|
|
||||||
|
async def asgi_send(self, send):
|
||||||
|
headers = {}
|
||||||
|
headers.update(self.headers)
|
||||||
|
headers["content-type"] = self.content_type
|
||||||
|
await send(
|
||||||
|
{
|
||||||
|
"type": "http.response.start",
|
||||||
|
"status": self.status,
|
||||||
|
"headers": [
|
||||||
|
[key.encode("utf-8"), value.encode("utf-8")]
|
||||||
|
for key, value in headers.items()
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
body = self.body
|
||||||
|
if not isinstance(body, bytes):
|
||||||
|
body = body.encode("utf-8")
|
||||||
|
await send({"type": "http.response.body", "body": body})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def html(cls, body, status=200, headers=None):
|
||||||
|
return cls(
|
||||||
|
body,
|
||||||
|
status=status,
|
||||||
|
headers=headers,
|
||||||
|
content_type="text/html; charset=utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def text(cls, body, status=200, headers=None):
|
||||||
|
return cls(
|
||||||
|
body,
|
||||||
|
status=status,
|
||||||
|
headers=headers,
|
||||||
|
content_type="text/plain; charset=utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def redirect(cls, path, status=302, headers=None):
|
||||||
|
headers = headers or {}
|
||||||
|
headers["Location"] = path
|
||||||
|
return cls("", status=status, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
class AsgiFileDownload:
|
class AsgiFileDownload:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, filepath, filename=None, content_type="application/octet-stream"
|
self, filepath, filename=None, content_type="application/octet-stream"
|
||||||
|
|
|
@ -7,7 +7,6 @@ import urllib
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
import pint
|
import pint
|
||||||
from sanic import response
|
|
||||||
|
|
||||||
from html import escape
|
from html import escape
|
||||||
|
|
||||||
|
@ -26,7 +25,14 @@ from datasette.utils import (
|
||||||
sqlite3,
|
sqlite3,
|
||||||
to_css_class,
|
to_css_class,
|
||||||
)
|
)
|
||||||
from datasette.utils.asgi import AsgiStream, AsgiWriter, AsgiRouter, AsgiView, NotFound
|
from datasette.utils.asgi import (
|
||||||
|
AsgiStream,
|
||||||
|
AsgiWriter,
|
||||||
|
AsgiRouter,
|
||||||
|
AsgiView,
|
||||||
|
NotFound,
|
||||||
|
Response,
|
||||||
|
)
|
||||||
|
|
||||||
ureg = pint.UnitRegistry()
|
ureg = pint.UnitRegistry()
|
||||||
|
|
||||||
|
@ -112,7 +118,7 @@ class BaseView(AsgiView):
|
||||||
datasette=self.ds,
|
datasette=self.ds,
|
||||||
):
|
):
|
||||||
body_scripts.append(jinja2.Markup(script))
|
body_scripts.append(jinja2.Markup(script))
|
||||||
return response.html(
|
return Response.html(
|
||||||
template.render(
|
template.render(
|
||||||
{
|
{
|
||||||
**context,
|
**context,
|
||||||
|
@ -144,7 +150,7 @@ class DataView(BaseView):
|
||||||
self.ds = datasette
|
self.ds = datasette
|
||||||
|
|
||||||
def options(self, request, *args, **kwargs):
|
def options(self, request, *args, **kwargs):
|
||||||
r = response.text("ok")
|
r = Response.text("ok")
|
||||||
if self.ds.cors:
|
if self.ds.cors:
|
||||||
r.headers["Access-Control-Allow-Origin"] = "*"
|
r.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
return r
|
return r
|
||||||
|
@ -154,7 +160,7 @@ class DataView(BaseView):
|
||||||
path = "{}?{}".format(path, request.query_string)
|
path = "{}?{}".format(path, request.query_string)
|
||||||
if remove_args:
|
if remove_args:
|
||||||
path = path_with_removed_args(request, remove_args, path=path)
|
path = path_with_removed_args(request, remove_args, path=path)
|
||||||
r = response.redirect(path)
|
r = Response.redirect(path)
|
||||||
r.headers["Link"] = "<{}>; rel=preload".format(path)
|
r.headers["Link"] = "<{}>; rel=preload".format(path)
|
||||||
if self.ds.cors:
|
if self.ds.cors:
|
||||||
r.headers["Access-Control-Allow-Origin"] = "*"
|
r.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
|
@ -254,7 +260,7 @@ class DataView(BaseView):
|
||||||
response_or_template_contexts = await self.data(
|
response_or_template_contexts = await self.data(
|
||||||
request, database, hash, **kwargs
|
request, database, hash, **kwargs
|
||||||
)
|
)
|
||||||
if isinstance(response_or_template_contexts, response.HTTPResponse):
|
if isinstance(response_or_template_contexts, Response):
|
||||||
return response_or_template_contexts
|
return response_or_template_contexts
|
||||||
else:
|
else:
|
||||||
data, _, _ = response_or_template_contexts
|
data, _, _ = response_or_template_contexts
|
||||||
|
@ -371,7 +377,7 @@ class DataView(BaseView):
|
||||||
response_or_template_contexts = await self.data(
|
response_or_template_contexts = await self.data(
|
||||||
request, database, hash, **kwargs
|
request, database, hash, **kwargs
|
||||||
)
|
)
|
||||||
if isinstance(response_or_template_contexts, response.HTTPResponse):
|
if isinstance(response_or_template_contexts, Response):
|
||||||
return response_or_template_contexts
|
return response_or_template_contexts
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -422,17 +428,11 @@ class DataView(BaseView):
|
||||||
if result is None:
|
if result is None:
|
||||||
raise NotFound("No data")
|
raise NotFound("No data")
|
||||||
|
|
||||||
response_args = {
|
r = Response(
|
||||||
"content_type": result.get("content_type", "text/plain"),
|
body=result.get("body"),
|
||||||
"status": result.get("status_code", 200),
|
status=result.get("status_code", 200),
|
||||||
}
|
content_type=result.get("content_type", "text/plain"),
|
||||||
|
)
|
||||||
if type(result.get("body")) == bytes:
|
|
||||||
response_args["body_bytes"] = result.get("body")
|
|
||||||
else:
|
|
||||||
response_args["body"] = result.get("body")
|
|
||||||
|
|
||||||
r = response.HTTPResponse(**response_args)
|
|
||||||
else:
|
else:
|
||||||
extras = {}
|
extras = {}
|
||||||
if callable(extra_template_data):
|
if callable(extra_template_data):
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from sanic import response
|
|
||||||
|
|
||||||
from datasette.utils import to_css_class, validate_sql_select
|
from datasette.utils import to_css_class, validate_sql_select
|
||||||
from datasette.utils.asgi import AsgiFileDownload
|
from datasette.utils.asgi import AsgiFileDownload
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from sanic import response
|
|
||||||
|
|
||||||
from datasette.utils import CustomJSONEncoder
|
from datasette.utils import CustomJSONEncoder
|
||||||
|
from datasette.utils.asgi import Response
|
||||||
from datasette.version import __version__
|
from datasette.version import __version__
|
||||||
|
|
||||||
from .base import BaseView
|
from .base import BaseView
|
||||||
|
@ -104,7 +103,7 @@ class IndexView(BaseView):
|
||||||
headers = {}
|
headers = {}
|
||||||
if self.ds.cors:
|
if self.ds.cors:
|
||||||
headers["Access-Control-Allow-Origin"] = "*"
|
headers["Access-Control-Allow-Origin"] = "*"
|
||||||
return response.HTTPResponse(
|
return Response(
|
||||||
json.dumps({db["name"]: db for db in databases}, cls=CustomJSONEncoder),
|
json.dumps({db["name"]: db for db in databases}, cls=CustomJSONEncoder),
|
||||||
content_type="application/json; charset=utf-8",
|
content_type="application/json; charset=utf-8",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import json
|
import json
|
||||||
from sanic import response
|
from datasette.utils.asgi import Response
|
||||||
from .base import BaseView
|
from .base import BaseView
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class JsonDataView(BaseView):
|
||||||
headers = {}
|
headers = {}
|
||||||
if self.ds.cors:
|
if self.ds.cors:
|
||||||
headers["Access-Control-Allow-Origin"] = "*"
|
headers["Access-Control-Allow-Origin"] = "*"
|
||||||
return response.HTTPResponse(
|
return Response(
|
||||||
json.dumps(data),
|
json.dumps(data),
|
||||||
content_type="application/json; charset=utf-8",
|
content_type="application/json; charset=utf-8",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -43,7 +43,6 @@ setup(
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"click>=6.7",
|
"click>=6.7",
|
||||||
"click-default-group==1.2",
|
"click-default-group==1.2",
|
||||||
"Sanic==0.7.0",
|
|
||||||
"Jinja2==2.10.1",
|
"Jinja2==2.10.1",
|
||||||
"hupper==1.0",
|
"hupper==1.0",
|
||||||
"pint==0.8.1",
|
"pint==0.8.1",
|
||||||
|
|
Ładowanie…
Reference in New Issue