Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion datasette/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,11 @@ async def stream_csv(datasette, fetch_data, request, database):

async def stream_fn(r):
nonlocal data, trace
limited_writer = LimitedWriter(r, datasette.setting("max_csv_mb"))
# Table exports should not be constrained by max_csv_mb - that limit
# is intended for arbitrary query exports.
is_table_export = request.url_vars.get("table") is not None
max_csv_mb = 0 if is_table_export else datasette.setting("max_csv_mb")
limited_writer = LimitedWriter(r, max_csv_mb)
if trace:
await limited_writer.write(preamble)
writer = csv.writer(EscapeHtmlWriter(limited_writer))
Expand Down
19 changes: 19 additions & 0 deletions docs/plugin_hooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,25 @@ The fields of the ``Action`` dataclass are as follows:
- Implement a ``resources_sql()`` classmethod that returns SQL returning all resources as ``(parent, child)`` columns
- Have an ``__init__`` method that accepts appropriate parameters and calls ``super().__init__(parent=..., child=...)``

Checking a registered action
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To check one of these actions in your plugin code, call
``datasette.allowed()`` with both the action name and a resource instance.
For example, this checks if the current actor can view a specific
``DocumentResource``:

.. code-block:: python

async def can_view_document(
datasette, actor, collection, document_id
):
return await datasette.allowed(
actor,
"view-document",
resource=DocumentResource(collection, document_id),
)

The ``resources_sql()`` method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
17 changes: 17 additions & 0 deletions tests/test_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ async def test_csv_with_non_ascii_characters(ds_client):
assert response.text == "text,number\r\n𝐜𝐢𝐭𝐢𝐞𝐬,1\r\nbob,2\r\n"


@pytest.mark.asyncio
async def test_table_csv_ignores_max_csv_mb():
ds = Datasette(settings={"max_csv_mb": 1})
await ds.invoke_startup()
db = ds.add_memory_database("max_csv")
await db.execute_write("create table t (id integer primary key, content text)")
await db.execute_write(
"insert into t (content) values (?)",
["a" * (2 * 1024 * 1024)],
)

response = await ds.client.get("/max_csv/t.csv")
assert response.status_code == 200
assert "CSV contains more than" not in response.text
assert len([line for line in response.text.split("\r\n") if line]) == 2


@pytest.mark.xfail(reason="Flaky, see https://github.com/simonw/datasette/issues/2355")
def test_max_csv_mb(app_client_csv_max_mb_one):
# This query deliberately generates a really long string
Expand Down