Commit graph

2,987 commits

Author SHA1 Message Date
Simon Willison
0df6555ef3 Release 1.0a28
Refs #2691, #2692, #2693
2026-04-16 20:59:21 -07:00
Simon Willison
630e557cdb Ran black 2026-04-16 20:44:21 -07:00
Simon Willison
b3001c1e5a Drop redundant _ds_client global now that ds_client is session-scoped
Session-scoped fixtures are cached per worker by pytest itself, so the
manual _ds_client module global is no longer needed.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:41:58 -07:00
Simon Willison
c9a7dc9be2 Declare ds_client as session-scoped so auto-close plugin spares it
ds_client already caches a single Datasette for the whole session via a
module-level _ds_client global, so the declared fixture scope should
match. With function scope the auto-close plugin correctly closes it
after the first test that uses it, which then breaks every subsequent
test that reuses the cached (now-closed) instance — as seen in the CI
coverage job, which runs serially rather than under pytest-xdist.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:40:51 -07:00
Simon Willison
03eeeb9d92 Docs: auto-close plugin now handles function-scoped fixtures
Describe the updated scoping rule: instances from test bodies and
function-scoped fixtures are closed automatically; session-, module-,
class- and package-scoped fixtures are exempt.

Refs #2692
2026-04-16 20:38:08 -07:00
Simon Willison
ede942a32e Fix ruff lints in close-related tests
Drop unused `bad = ...` assignment and unused `import pytest`.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:34:48 -07:00
Simon Willison
df96e12737 Auto-close Datasette instances from function-scoped fixtures too
The plugin now tracks instances across the full test protocol (setup,
call, teardown) and closes all of them at the end — including ones
created inside function-scoped pytest fixtures. Session-, module-,
class- and package-scoped fixtures are still exempted by subtracting
any instances their setup adds from the tracking list.

This makes downstream projects like datasette-alerts work at low FD
limits without every fixture needing an explicit ds.close() call.

Refs #2692
See https://github.com/simonw/datasette/issues/2692#issuecomment-4265072230

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:32:19 -07:00
Simon Willison
d23b32c3e5 Call ds.close() in more places in tests
Refs #2692
2026-04-16 20:25:58 -07:00
Simon Willison
c0153386ef FD-leak regression test for Datasette.close()
Creates and disposes 50 Datasette instances in a loop and asserts that
the number of open file descriptors and live threads does not grow,
exercising the full close() path end to end.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:18:05 -07:00
Simon Willison
34cc320eab Pytest auto-close plugin for Datasette instances
Installs a pytest11 entry point so that every Datasette() constructed
inside a pytest_runtest_call phase is auto-closed at the end of the test.
Fixture-scoped instances are untouched. Opt out via the
datasette_autoclose = false ini option.

This gives large test suites a safety net against FD exhaustion and leaked
write threads from the now-default temp-disk internal database without
requiring every existing test to be rewritten.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:15:50 -07:00
Simon Willison
d72dd35378 Wire Datasette.close into ASGI lifespan shutdown
AsgiLifespan now receives an on_shutdown callback that invokes
Datasette.close(), so resources are released cleanly when the ASGI server
delivers a lifespan.shutdown message (SIGTERM / SIGINT for uvicorn).

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:11:02 -07:00
Simon Willison
290f27158f Datasette.close() closes databases, shuts down executor, unlinks temp file
Datasette.close() iterates over every attached Database (including the
internal database), calls Database.close() on each, then shuts down the
ThreadPoolExecutor. Exceptions raised by one Database don't prevent the
others from being closed; the first exception is re-raised afterwards.
Idempotent.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:10:18 -07:00
Simon Willison
dabf8e4199 Database.close() shuts down write thread and raises DatasetteClosedError
After this commit, Database.close() sends a sentinel to the write queue so
the background write thread exits cleanly, closes cached read/write
connections, and marks the instance closed. Subsequent calls to execute*()
raise DatasetteClosedError. close() remains idempotent and one-way.

Refs #2692

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:09:47 -07:00
Simon Willison
ade0ef8a60 Restore compatibility with existing execute_write_fn() callbacks
Closes #2691
2026-04-16 19:14:32 -07:00
Simon Willison
2638200d26
Link to datasette.io preview tool 2026-04-15 17:19:43 -07:00
Simon Willison
1f99d5dd20 Release 1.0a27 1.0a27
Refs #1936, #2678, #2681, #2682, #2683, #2684, #2688, #2689
2026-04-15 16:11:54 -07:00
Simon Willison
67349e0e02 New :pr:ID shortcut for docs 2026-04-15 16:04:17 -07:00
Simon Willison
1a7030d668 API explorer special case for rowid in /-/upsert
Refs #1936
2026-04-15 15:47:48 -07:00
Simon Willison
5f39036b9b ok: true in /db.json for consistency 2026-04-15 15:44:06 -07:00
Simon Willison
73f338b9f3 Better example in API explorer for /-/upsert, closes #1936 2026-04-15 15:29:59 -07:00
Simon Willison
4922fc2e39 Disallow null primary keys in upsert
Refs https://github.com/simonw/datasette/issues/1936#issuecomment-1341849496
2026-04-15 15:11:33 -07:00
Simon Willison
a973e3ffa1 Normalize headers in CSRF checks, refs #2689 2026-04-14 19:24:38 -07:00
Simon Willison
028cc2446f Don't allow cookies with Authorization: Bearer to bypass CSRF
Refs #2689
2026-04-14 19:23:21 -07:00
Simon Willison
f02484c3de From 409 warnings down to 52 warnings.
By closing unclosed database connections.

Refs #2614
2026-04-14 18:46:47 -07:00
Simon Willison
9c164572d3
Add actor= parameter to datasette.client methods (#2688)
`datasette.client.get(path, actor={"id": "root"}` now makes the internal request with that actor as `request.actor` - same for the other HTTP verb methods on `datasette.client`.

Upgraded relevant tests to use the new `actor=` mechanism.
2026-04-14 18:31:57 -07:00
Simon Willison
0b639a8122
Replace token-based CSRF with Sec-Fetch-Site header protection (#2689)
- New CSRF protection middleware inspired by Go 1.25 and research by Filippo Valsorda - https://words.filippo.io/csrf/ - this replaces the old CSRF token based protection.
- Removes all instances of `<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">` in the templates - they are no longer needed.
- Removes the `def skip_csrf(datasette, scope):` plugin hook defined in `datasette/hookspecs.py` and its documentation and tests.
- Updated CSRF protection documentation to describe the new approach.
- Upgrade guide now describes the CSRF change.
2026-04-14 17:11:36 -07:00
Simon Willison
fc1794719a
Database(is_temp_disk=True) option, used for internal database (#2684)
Closes #2683

* Add is_temp_disk option to Database for temp file-backed databases

Replace the default in-memory internal database with a temporary
file-backed database using WAL mode. This fixes concurrent read/write
locking errors that occur with named in-memory SQLite databases.

The new is_temp_disk parameter on Database creates a temp file via
tempfile.mkstemp, connects to it as a regular file-based database
with WAL mode enabled, and cleans it up on close() and via atexit.

https://claude.ai/code/session_01TteLrUjpDcARjnP1GMRqz2
2026-03-30 21:03:21 -07:00
Simon Willison
94d14e3d37 Warning note about VACUUM and RenameTableEvent
I noticed that VACUUM can update the rootpage for tables in a way that
could confuse our rename table detection logic - but using the
execute_isolated_fn() method to run VACUUM avoids this problem.

Refs #2681
2026-03-30 16:11:06 -07:00
Simon Willison
312f41b0c2
RenameTableEvent, plus write connection track_event() mechanism (#2682)
* Add track_event callback to execute_write_fn and write_wrapper

Allows write functions and write_wrapper generators to queue events
during a write operation that are dispatched after successful commit.
The fn or wrapper can optionally accept a `track_event` parameter
(detected via call_with_supported_arguments). Events are discarded
if the write raises an exception.

Does not yet handle the block=False (non-blocking) case - events
queued during non-blocking writes are currently silently discarded.

Refs https://github.com/simonw/datasette/issues/2681

* Dispatch track_event events for non-blocking (block=False) writes

Spawns a background asyncio task that awaits the write thread's reply
queue and dispatches pending events after a successful non-blocking
write. Events are still discarded if the write raises an exception.

Refs https://github.com/simonw/datasette/issues/2681

* Warn that events won't fire for other processes

Refs https://github.com/simonw/datasette/issues/2681#issuecomment-4157118662
2026-03-30 11:20:46 -07:00
dependabot[bot]
9b5cb1347c
Bump rollup from 3.29.5 to 3.30.0 (#2651)
Bumps [rollup](https://github.com/rollup/rollup) from 3.29.5 to 3.30.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/v3.30.0/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v3.29.5...v3.30.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-version: 3.30.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:54:48 -07:00
dependabot[bot]
1a64d5e55e
Bump picomatch from 2.3.1 to 2.3.2 (#2679)
Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:54:34 -07:00
Simon Willison
c479e7dec9
Document call_with_supported_arguments as a supported public API (#2678)
* Document call_with_supported_arguments as a supported public API

Mark both call_with_supported_arguments and async_call_with_supported_arguments
with the @documented decorator and add documentation to docs/internals.rst
so plugin authors can use these dependency injection utilities in their own code.

https://claude.ai/code/session_01DKogZpHwzCTrbeG4XjXmNc
2026-03-30 10:44:10 -07:00
Simon Willison
4fcf474088 Release 1.0a26 1.0a26
Refs #1592, #2661, #2664, #2666, #2669, #2670, #2671, #2672
2026-03-18 15:13:37 -07:00
Simon Willison
c673ee9819 Update docs for async def resources_sql(cls, datasette, actor=None) signature 2026-03-18 15:08:52 -07:00
Simon Willison
cb293572c4 UI for setting custom column types, refs #2671 2026-03-18 14:08:44 -07:00
Simon Willison
cb5cc0cc22 Fixed some broken docs/ references, refs #2671 2026-03-18 13:02:31 -07:00
Simon Willison
611b8ad463 blacken-docs 2026-03-18 12:33:09 -07:00
Simon Willison
2b06da29a1 Rename set-column-types action to et-column-type
Refs https://github.com/simonw/datasette/pull/2674#issuecomment-4085015792
2026-03-18 12:33:09 -07:00
Simon Willison
d440c20984 /db/table/-/set-column-type JSON API, refs #2671 2026-03-18 12:33:09 -07:00
Simon Willison
fa1d8f0fa5 set-column-types permission, refs #2671 2026-03-18 12:33:09 -07:00
Simon Willison
feaba9b18b
Optionally limit ColumnType subclasses to specific SQLite types (#2673)
* ColumnTypes now have optional SQLite column types

Refs #2672
2026-03-18 11:37:09 -07:00
Simon Willison
0f81553b3f No hide this column on last remaining column 2026-03-18 10:47:05 -07:00
Simon Willison
68966880c2
Fix mobile column actions not showing items for SQL views (#2670)
* Fix mobile column actions not showing items for SQL views

The previous fix to exclude the Link column from mobile column actions
(d02072b) used .dropdown-menu-icon presence as a proxy, but dropdown
icons are only added to sortable columns (those with <a> tags). This
caused all non-sortable columns to be excluded too.

Instead, explicitly mark the Link column with a data-is-link-column
attribute and filter by that in mobileColumnHeaders, so non-sortable
columns on views and tables still appear in the mobile column actions.

* Prettier formatting for mobile-column-actions.js

https://claude.ai/code/session_01CG545gLcZxet7dS5nMzfCd
2026-03-18 09:46:36 -07:00
Simon Willison
d02072bc9d Do not show mobile column actions for Link column
Refs #2669
2026-03-18 09:08:00 -07:00
Simon Willison
e800312b54 allowed_resources(view-query, actor) fix
Previously we could not filter for canned queries that a
specific actor could view.
2026-03-18 09:05:23 -07:00
Simon Willison
fd016f7986
Column actions panel on mobile (#2669)
On mobile widths the column actions were no longer available.

This adds a new modal to help with that.

https://gisthost.github.io/?ec60eb27e22cf5d96642eec1715586b6
2026-03-18 09:04:28 -07:00
Simon Willison
63d73a806f
Move table configuration docs from metadata.rst to configuration.rst (#2668)
https://claude.ai/code/session_01UqboRB5Wt52BKPhxexUBEn
2026-03-17 08:47:04 -07:00
Simon Willison
bc7a19b39d
Column types system
Closes #2664
2026-03-16 22:29:51 -07:00
Claude
b7578a4884
Remove pointless test_column_type_with_config test
https://claude.ai/code/session_01SvPEPqHgURTWESRp28pTC3
2026-03-17 05:24:09 +00:00
Claude
c73a1c907a
Use 'subclass' instead of 'class' in ColumnType docs
https://claude.ai/code/session_01SvPEPqHgURTWESRp28pTC3
2026-03-17 05:22:53 +00:00