write_wrapper plugin hook for intercepting write operations#2636
write_wrapper plugin hook for intercepting write operations#2636
Conversation
Add a new `wrap_write` 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). https://claude.ai/code/session_019hWsbmHqitdVNCNChN5aNJ
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. https://claude.ai/code/session_019hWsbmHqitdVNCNChN5aNJ
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2636 +/- ##
==========================================
+ Coverage 90.37% 90.39% +0.01%
==========================================
Files 52 52
Lines 7983 8017 +34
==========================================
+ Hits 7215 7247 +32
- Misses 768 770 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
I pitched Claude the idea of having the plugin function able to Quoting the response in full because it's worth recording somewhere:
|
|
Here's the plugin documentation Claude wrote: https://github.com/simonw/datasette/blob/ce1b4e509b39ae9b643640a1995b67e549cc13ea/docs/plugin_hooks.rst#write_wrapperdatasette-database-request-transaction |
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. https://claude.ai/code/session_019hWsbmHqitdVNCNChN5aNJ
simonw
left a comment
There was a problem hiding this comment.
After several iterations this all looks great to me.
Summary
This PR introduces a new
wrap_writeplugin hook that allows plugins to intercept and wrap database write operations. This enables use cases like transaction management, change tracking, audit logging, and other cross-cutting concerns around writes.Key Changes
New
wrap_writehookspec indatasette/hookspecs.py: Defines the plugin hook interface that acceptsdatasette,database,request, andtransactionparameters and returns a generator-based context manager wrapper.Request parameter propagation: Added optional
requestparameter toexecute_write(),execute_write_script(),execute_write_many(), andexecute_write_fn()methods to pass HTTP request context to plugins.Hook wrapping implementation in
datasette/database.py:_wrap_fn_with_hooks()method that collects and applies all registeredwrap_writewrappers_apply_wrap_write()utility function that properly handles generator-based context managers, including exception propagation and result passing via.send()View layer updates: Modified write operations in
datasette/views/database.py,datasette/views/row.py, anddatasette/views/table.pyto pass therequestobject to write methods.Comprehensive test coverage in new
tests/test_wrap_write.pywith 13 test cases covering:Implementation Details
The
wrap_writehook uses Python generators as context managers. Plugins return a generator function that:yieldyieldresult = yieldMultiple wrappers are nested in reverse order (LIFO) so the first registered plugin is the outermost wrapper, maintaining intuitive execution order.
https://claude.ai/code/session_019hWsbmHqitdVNCNChN5aNJ
📚 Documentation preview 📚: https://datasette--2636.org.readthedocs.build/en/2636/
https://gisthost.github.io/?c4c12079434e69677e4aa8ac664b21b8/index.html
Refs: