escape_sqlite() wrapped identifiers in [brackets] without escaping any ]
characters inside the string. Since SQLite does not support escaping ]
within bracket quoting, an identifier containing ] could break out and
inject arbitrary SQL. Fall back to double-quote quoting (doubling any
embedded ") when the identifier contains ].
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Use the router-stripped route_path when building request-derived export
URLs, so table, row, and query JSON/CSV links do not apply base_url twice.
Keep urls.path() behavior unchanged, and add coverage for both /prefix/
exports and a /data/ base_url with a data database.
Closes#2759
* 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
* Fix flaky test_database_page test with deterministic ordering
- Add ORDER BY to table_names() query in database.py
- Sort foreign keys deterministically in get_all_foreign_keys()
- Refactor test_database_page to use property-based assertions instead of
500+ lines of hardcoded expected data
- Run blacken-docs on plugin_hooks.rst
* Update test_row_foreign_key_tables for new deterministic FK ordering
The foreign keys are now sorted by (other_table, column, other_column),
so complex_foreign_keys comes before foreign_key_references alphabetically.
* Update test_table_names for new alphabetical ordering
The table_names() method now returns tables sorted alphabetically.
* Fix for test that fails prior to SQLite 3.37
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Add keyset pagination to allowed_resources()
This replaces the unbounded list return with PaginatedResources,
which supports efficient keyset pagination for handling thousands
of resources.
Closes#2560
Changes:
- allowed_resources() now returns PaginatedResources instead of list
- Added limit (1-1000, default 100) and next (keyset token) parameters
- Added include_reasons parameter (replaces allowed_resources_with_reasons)
- Removed allowed_resources_with_reasons() method entirely
- PaginatedResources.all() async generator for automatic pagination
- Uses tilde-encoding for tokens (matching table pagination)
- Updated all callers to use .resources accessor
- Updated documentation with new API and examples
The PaginatedResources object has:
- resources: List of Resource objects for current page
- next: Token for next page (None if no more results)
- all(): Async generator that yields all resources across pages
Example usage:
page = await ds.allowed_resources("view-table", actor, limit=100)
for table in page.resources:
print(table.child)
# Iterate all pages automatically
async for table in page.all():
print(table.child)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* `asyncio_default_fixture_loop_scope = function`
* Fix a bunch of BeautifulSoup deprecation warnings
* Fix for PytestUnraisableExceptionWarning: Exception ignored in: <_io.FileIO [closed]>
* xfail for sql_time_limit tests (these can be flaky in CI)
Refs #2461
Table configuration that was incorrectly placed in metadata is now treated as if it was in config.
New await datasette.table_config() method.
Closes#2247