mirror of
https://github.com/simonw/datasette.git
synced 2026-09-17 14:04:07 +02:00
Return CSV errors as plain text, closes #2129
This commit is contained in:
parent
4bf30aaf8e
commit
faff4c8820
4 changed files with 66 additions and 1 deletions
|
|
@ -59,6 +59,10 @@ def handle_exception(datasette, request, exception):
|
|||
body = dict(info)
|
||||
body.update(error_body(plain_message or message, status))
|
||||
return Response.json(body, status=status, headers=headers)
|
||||
if request.path.split("?")[0].endswith(".csv"):
|
||||
return Response.text(
|
||||
plain_message or message, status=status, headers=headers
|
||||
)
|
||||
info.update(
|
||||
{
|
||||
"ok": False,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class DatasetteError(Exception):
|
|||
self.error_dict = error_dict or {}
|
||||
self.status = status
|
||||
self.message_is_html = message_is_html
|
||||
# Plain text used for JSON error responses when message is HTML
|
||||
# Plain text used for JSON and CSV error responses when message is HTML
|
||||
self.plain_message = plain_message
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Datasette plugins can now use **background tasks** to run code independent of th
|
|||
Bug fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- CSV endpoints now return plain-text error messages for SQL errors. (:issue:`2129`)
|
||||
- The :ref:`render_cell() <plugin_hook_render_cell>` plugin hook now receives an empty ``pks`` list when rendering SQL views in HTML, matching the JSON ``?_extra=render_cell`` behavior. (:issue:`2639`)
|
||||
- Numeric comparison filters now correctly handle decimal values, negative numbers and scientific notation when filtering computed columns and SQL views. Thanks, `Rami Abdelrazzaq <https://github.com/RamiNoodle733>`__. (:issue:`1681`, :pr:`2876`)
|
||||
- Fixed CSV streaming with ``?_stream=on`` on SQL views repeating the second page of results until the CSV size limit was reached. Thanks, `Ankita Advitot <https://github.com/AnkitaAdvitot>`__. (:issue:`2902`, :pr:`2903`)
|
||||
|
|
|
|||
|
|
@ -166,6 +166,66 @@ async def test_custom_sql_csv(ds_client):
|
|||
assert response.text == EXPECTED_CUSTOM_CSV
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("download", (False, True))
|
||||
@pytest.mark.parametrize(
|
||||
"query_string,expected_error",
|
||||
(
|
||||
("sql=select+blah", "no such column: blah"),
|
||||
("sql=select+*+from+missing", "no such table: missing"),
|
||||
("sql=select+from", 'near "from": syntax error'),
|
||||
(
|
||||
"sql=delete+from+simple_primary_key",
|
||||
"Statement must be a SELECT",
|
||||
),
|
||||
("", "?sql= is required"),
|
||||
(
|
||||
"sql=select+sleep(0.01)&_timelimit=5",
|
||||
(
|
||||
"SQL query took too long. The time limit is"
|
||||
" controlled by the sql_time_limit_ms setting."
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
async def test_custom_sql_csv_errors(ds_client, query_string, expected_error, download):
|
||||
if download:
|
||||
query_string += "&_dl=1"
|
||||
response = await ds_client.get(f"/fixtures/-/query.csv?{query_string}")
|
||||
assert response.status_code == 400
|
||||
assert response.headers["content-type"] == "text/plain; charset=utf-8"
|
||||
assert "content-disposition" not in response.headers
|
||||
assert response.text == expected_error
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_custom_sql_csv_error_head(ds_client):
|
||||
response = await ds_client.head("/fixtures/-/query.csv?sql=select+blah")
|
||||
assert response.status_code == 400
|
||||
assert response.headers["content-type"] == "text/plain; charset=utf-8"
|
||||
assert response.content == b""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_custom_sql_csv_error_cors():
|
||||
ds = Datasette(cors=True)
|
||||
response = await ds.client.get("/_memory/-/query.csv?sql=select+blah")
|
||||
assert response.status_code == 400
|
||||
assert response.headers["content-type"] == "text/plain; charset=utf-8"
|
||||
assert response.headers["access-control-allow-origin"] == "*"
|
||||
assert response.text == "no such column: blah"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_table_csv_error(ds_client):
|
||||
response = await ds_client.get(
|
||||
"/fixtures/simple_primary_key.csv?_where=blah&_stream=1"
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert response.headers["content-type"] == "text/plain; charset=utf-8"
|
||||
assert response.text == "no such column: blah"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_table_csv_download(ds_client):
|
||||
response = await ds_client.get("/fixtures/simple_primary_key.csv?_dl=1")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue