kopia lustrzana https://github.com/simonw/datasette
Show more useful error message for SQL interrupted, closes #142
rodzic
98c8f0e728
commit
b0a95da963
|
@ -12,6 +12,7 @@ import urllib.parse
|
||||||
from concurrent import futures
|
from concurrent import futures
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from markupsafe import Markup
|
||||||
import pluggy
|
import pluggy
|
||||||
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader
|
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader
|
||||||
from sanic import Sanic, response
|
from sanic import Sanic, response
|
||||||
|
@ -461,6 +462,7 @@ class Datasette:
|
||||||
@app.exception(Exception)
|
@app.exception(Exception)
|
||||||
def on_exception(request, exception):
|
def on_exception(request, exception):
|
||||||
title = None
|
title = None
|
||||||
|
help = None
|
||||||
if isinstance(exception, NotFound):
|
if isinstance(exception, NotFound):
|
||||||
status = 404
|
status = 404
|
||||||
info = {}
|
info = {}
|
||||||
|
@ -473,6 +475,8 @@ class Datasette:
|
||||||
status = exception.status
|
status = exception.status
|
||||||
info = exception.error_dict
|
info = exception.error_dict
|
||||||
message = exception.message
|
message = exception.message
|
||||||
|
if exception.messagge_is_html:
|
||||||
|
message = Markup(message)
|
||||||
title = exception.title
|
title = exception.title
|
||||||
else:
|
else:
|
||||||
status = 500
|
status = 500
|
||||||
|
|
|
@ -27,11 +27,12 @@ HASH_LENGTH = 7
|
||||||
|
|
||||||
class DatasetteError(Exception):
|
class DatasetteError(Exception):
|
||||||
|
|
||||||
def __init__(self, message, title=None, error_dict=None, status=500, template=None):
|
def __init__(self, message, title=None, error_dict=None, status=500, template=None, messagge_is_html=False):
|
||||||
self.message = message
|
self.message = message
|
||||||
self.title = title
|
self.title = title
|
||||||
self.error_dict = error_dict or {}
|
self.error_dict = error_dict or {}
|
||||||
self.status = status
|
self.status = status
|
||||||
|
self.messagge_is_html = messagge_is_html
|
||||||
|
|
||||||
|
|
||||||
class RenderMixin(HTTPMethodView):
|
class RenderMixin(HTTPMethodView):
|
||||||
|
@ -154,7 +155,11 @@ class BaseView(RenderMixin):
|
||||||
else:
|
else:
|
||||||
data, extra_template_data, templates = response_or_template_contexts
|
data, extra_template_data, templates = response_or_template_contexts
|
||||||
except InterruptedError as e:
|
except InterruptedError as e:
|
||||||
raise DatasetteError(str(e), title="SQL Interrupted", status=400)
|
raise DatasetteError("""
|
||||||
|
SQL query took too long. The time limit is controlled by the
|
||||||
|
<a href="https://datasette.readthedocs.io/en/stable/config.html#sql-time-limit-ms">sql_time_limit_ms</a>
|
||||||
|
configuration option.
|
||||||
|
""", title="SQL Interrupted", status=400, messagge_is_html=True)
|
||||||
except (sqlite3.OperationalError, InvalidSql) as e:
|
except (sqlite3.OperationalError, InvalidSql) as e:
|
||||||
raise DatasetteError(str(e), title="Invalid SQL", status=400)
|
raise DatasetteError(str(e), title="Invalid SQL", status=400)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
from bs4 import BeautifulSoup as Soup
|
from bs4 import BeautifulSoup as Soup
|
||||||
from .fixtures import app_client
|
from .fixtures import app_client, app_client_shorter_time_limit
|
||||||
import pytest
|
import pytest
|
||||||
import re
|
import re
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
pytest.fixture(scope='session')(app_client)
|
pytest.fixture(scope='session')(app_client)
|
||||||
|
pytest.fixture(scope='session')(app_client_shorter_time_limit)
|
||||||
|
|
||||||
|
|
||||||
def test_homepage(app_client):
|
def test_homepage(app_client):
|
||||||
|
@ -29,6 +30,18 @@ def test_invalid_custom_sql(app_client):
|
||||||
assert 'Statement must be a SELECT' in response.text
|
assert 'Statement must be a SELECT' in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_sql_time_limit(app_client_shorter_time_limit):
|
||||||
|
response = app_client_shorter_time_limit.get(
|
||||||
|
'/test_tables?sql=select+sleep(0.5)',
|
||||||
|
gather_request=False
|
||||||
|
)
|
||||||
|
assert 400 == response.status
|
||||||
|
expected_html_fragment = """
|
||||||
|
<a href="https://datasette.readthedocs.io/en/stable/config.html#sql-time-limit-ms">sql_time_limit_ms</a>
|
||||||
|
""".strip()
|
||||||
|
assert expected_html_fragment in response.text
|
||||||
|
|
||||||
|
|
||||||
def test_view(app_client):
|
def test_view(app_client):
|
||||||
response = app_client.get('/test_tables/simple_view', gather_request=False)
|
response = app_client.get('/test_tables/simple_view', gather_request=False)
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
Ładowanie…
Reference in New Issue