datasette/tests
Simon Willison 80b7f987ca
write_wrapper plugin hook for intercepting write operations (#2636)
* Implement write_wrapper plugin hook for intercepting database writes

Add a new `write_wrapper` plugin hook that lets plugins wrap write
operations with before/after logic using a generator-based context
manager pattern. The hook receives (datasette, database, request,
transaction) and returns a generator function that takes a conn,
yields once to let the write execute, and can run cleanup after.

The write result is sent back via `generator.send()` and exceptions
are thrown via `generator.throw()`, giving plugins full visibility.

Also adds `request=None` parameter to execute_write, execute_write_fn,
execute_write_script, and execute_write_many, and threads request
through all view-layer call sites (insert, upsert, update, delete,
drop, create table, canned queries).

* Add documentation for wrap_write hook, fix lint issues

Document the wrap_write plugin hook in plugin_hooks.rst with
parameter descriptions and two examples: a simple logging wrapper
and an advanced SQLite authorizer-based table protection pattern.

Also fix black formatting and remove unused variable flagged by ruff.

* Rename wrap_write hook to write_wrapper for consistency with asgi_wrapper
* Move write_wrapper docs to just below prepare_connection
* Refactor write_wrapper tests to use pytest.parametrize

Consolidate duplicate test cases: merge before/after tests for
execute_write_fn and execute_write into one parametrized test, and
merge three parameter-passing tests into one parametrized test.

Claude Code transcript: https://gisthost.github.io/?c4c12079434e69677e4aa8ac664b21b8/index.html
2026-02-09 13:20:33 -08:00
..
plugins Remove permission_allowed hook docs, closes #2588 2025-11-07 16:50:00 -08:00
test_templates Fix handling of nested custom page wildcard paths, closes #996 2020-10-07 15:51:11 -07:00
__init__.py Broke up test_app into test_api and test_html 2017-12-15 04:08:24 -08:00
build_small_spatialite_db.py New run_sanity_checks mechanism, for SpatiLite 2019-05-11 15:55:30 -07:00
conftest.py facet_suggest_time_limit_ms 200ms in tests, closes #2574 2025-11-03 11:52:12 -08:00
ext.c Add new entrypoint option to --load-extensions. (#1789) 2022-08-23 11:34:30 -07:00
fixtures.py Switch searchable_fts test table to FTS5, closes #2613 2025-12-12 22:18:35 -08:00
spatialite.db New run_sanity_checks mechanism, for SpatiLite 2019-05-11 15:55:30 -07:00
test-datasette-load-plugins.sh fix (typo): Corrected spelling of 'environments' (#2268) 2024-02-19 14:41:32 -08:00
test_actions_sql.py datasette.pm property, closes #2595 2025-11-13 10:31:03 -08:00
test_actor_restriction_bug.py New PermissionSQL.restriction_sql mechanism for actor restrictions 2025-11-03 14:17:51 -08:00
test_allowed_resources.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_api.py Fix flaky test_database_page test with deterministic ordering (#2628) 2026-01-23 20:57:25 -08:00
test_api_write.py Close more connections in test suite 2026-01-28 09:55:25 -08:00
test_auth.py Fix type annotation bugs and remove unused imports 2025-10-26 16:03:13 -07:00
test_base_view.py New View base class (#2080) 2023-05-25 17:18:43 -07:00
test_canned_queries.py Fix type annotation bugs and remove unused imports 2025-10-26 16:03:13 -07:00
test_cli.py Fix test isolation bug in test_startup_error_from_plugin_is_click_exception (#2627) 2026-01-22 07:03:05 -08:00
test_cli_serve_get.py Made test_serve_with_get_headers a bit more forgiving 2025-11-04 18:39:25 -08:00
test_cli_serve_server.py Move HTTPS test to a bash script 2022-12-17 18:33:07 -08:00
test_config_dir.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_config_permission_rules.py Run black formatter 2025-10-25 15:38:07 -07:00
test_crossdb.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_csv.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_custom_pages.py Move open redirect fix to asgi_send_redirect, refs #2429 2025-11-04 17:08:06 -08:00
test_datasette_https_server.sh Detect server start/stop more reliably. 2022-12-18 08:01:51 -08:00
test_default_deny.py datasette serve --default-deny option (#2593) 2025-11-12 16:14:21 -08:00
test_docs.py Use subtests in tests/test_docs.py (#2609) 2025-12-04 21:36:39 -08:00
test_docs_plugins.py datasette.pm property, closes #2595 2025-11-13 10:31:03 -08:00
test_facets.py Consider just 1000 rows for suggest facet, closes #2406 2024-08-21 13:36:42 -07:00
test_filters.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_html.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_internal_db.py Fix for stale internal database bug, closes #2605 2025-12-02 16:22:42 -08:00
test_internals_database.py Fix flaky test_database_page test with deterministic ordering (#2628) 2026-01-23 20:57:25 -08:00
test_internals_datasette.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_internals_datasette_client.py datasette.pm property, closes #2595 2025-11-13 10:31:03 -08:00
test_internals_request.py Request.fake(... url_vars), plus .fake() is now documented 2022-03-31 19:01:58 -07:00
test_internals_response.py response.set_cookie(), closes #795 2020-06-09 15:19:37 -07:00
test_internals_urls.py Remove hashed URL mode 2022-03-18 17:12:03 -07:00
test_label_column_for_table.py Detect single unique text column in label_column_for_table, closes #2458 2025-02-01 17:02:49 -08:00
test_load_extensions.py Introduce new /$DB/-/query endpoint, soft replaces /$DB?sql=... (#2363) 2024-07-15 10:33:51 -07:00
test_messages.py Introduce new /$DB/-/query endpoint, soft replaces /$DB?sql=... (#2363) 2024-07-15 10:33:51 -07:00
test_multipart.py Add request.form() for multipart form data and file uploads 2026-01-28 18:41:03 -08:00
test_package.py Upgrade Docker images to Python 3.11, closes #1853 2022-10-25 12:04:53 -07:00
test_permission_endpoints.py datasette.pm property, closes #2595 2025-11-13 10:31:03 -08:00
test_permissions.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_plugins.py write_wrapper plugin hook for intercepting write operations (#2636) 2026-02-09 13:20:33 -08:00
test_publish_cloudrun.py Get publish cloudrun working with latest Cloud Run (#2581) 2025-11-05 09:28:41 -08:00
test_publish_heroku.py Upgrade to Python 3.11 on Heroku, refs #1905 2022-11-18 16:44:46 -08:00
test_restriction_sql.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_routes.py Introduce new /$DB/-/query endpoint, soft replaces /$DB?sql=... (#2363) 2024-07-15 10:33:51 -07:00
test_schema_endpoints.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_search_tables.py Rename test_tables_endpoint.py and remove outdated tests 2025-10-25 17:32:48 -07:00
test_spatialite.py Skip SpatiaLite test if no conn.enable_load_extension() 2022-09-05 17:09:57 -07:00
test_table_api.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_table_html.py Switch to ruff and fix all lint errors, refs #2630 2026-01-23 20:43:16 -08:00
test_tracer.py Tracer now catches errors, closes #2405 2024-08-21 12:19:18 -07:00
test_utils.py Fix bug where -s could reset settings to defaults, closes #2389 2024-08-14 14:28:48 -07:00
test_utils_check_callable.py Rename callable.py to check_callable.py, refs #2078 2023-05-25 11:49:40 -07:00
test_utils_permissions.py Permissions SQL API improvements (#2558) 2025-10-30 15:48:46 -07:00
test_write_wrapper.py write_wrapper plugin hook for intercepting write operations (#2636) 2026-02-09 13:20:33 -08:00
utils.py Test improvements and fixed deprecation warnings (#2464) 2025-02-04 14:49:52 -08:00