upgrade-1.0a20.md, refs #2564

And another Markdown conversion, refs #2565
This commit is contained in:
Simon Willison 2025-10-31 19:13:41 -07:00
commit 1f8995e776
4 changed files with 225 additions and 130 deletions

View file

@ -31,6 +31,10 @@ export DATASETTE_SECRET := "not_a_secret"
@docs: cog blacken-docs @docs: cog blacken-docs
uv sync --extra docs && cd docs && uv run make livehtml uv sync --extra docs && cd docs && uv run make livehtml
# Build docs as static HTML
@docs-build: cog blacken-docs
rm -rf docs/_build && cd docs && uv run make html
# Apply Black # Apply Black
@black: @black:
uv run black . uv run black .

105
docs/upgrade-1.0a20.md Normal file
View file

@ -0,0 +1,105 @@
---
orphan: true
---
# Datasette 1.0a20 plugin upgrade guide
<!-- START UPGRADE 1.0a20 -->
Datasette 1.0a20 makes some breaking changes to Datasette's permission system. Plugins need to be updated if they use any of the following:
- The `register_permissions()` plugin hook - this should be replaced with `register_actions`
- The `permission_allowed()` plugin hook - this should be upgraded to `permission_resources_sql()`.
- The `datasette.permission_allowed()` internal method - this should be replaced with `datasette.allowed()`
- Logic that grants access to the `"root"` actor can be removed.
## Permissions are now actions
The `register_permissions()` hook shoud be replaced with `register_actions()`.
Old code:
```python
@hookimpl
def register_permissions(datasette):
return [
Permission(
name="datasette-pins-write",
abbr=None,
description="Can pin, unpin, and re-order pins for datasette-pins",
takes_database=False,
takes_resource=False,
default=False,
),
Permission(
name="datasette-pins-read",
abbr=None,
description="Can read pinned items.",
takes_database=False,
takes_resource=False,
default=False,
),
]
```
The new `Action` does not have a `default=` parameter, and `takes_database` and `takes_resource` have been renamed to `takes_parent` and `takes_child. The new code would look like this:
```python
from datasette.permissions import Action
@hookimpl
def register_actions(datasette):
return [
Action(
name="datasette-pins-write",
abbr=None,
description="Can pin, unpin, and re-order pins for datasette-pins",
takes_parent=False,
takes_child=False,
default=False,
),
Action(
name="datasette-pins-read",
abbr=None,
description="Can read pinned items.",
takes_parent=False,
takes_child=False,
default=False,
),
]
```
## permission_allowed() hook is replaced by permission_resources_sql()
The following old code:
```python
@hookimpl
def permission_allowed(action):
if action == "permissions-debug":
return True
```
Can be replaced by:
```python
from datasette.permissions import PermissionSQL
@hookimpl
def permission_resources_sql(action):
return PermissionSQL.allow(reason="datasette-allow-permissions-debug")
```
A `.deny(reason="")` class method is also available.
For more complex permission checks consult the documentation for that plugin hook:
<https://docs.datasette.io/en/latest/plugin_hooks.html#permission-resources-sql-datasette-actor-action>
## Fixing async with httpx.AsyncClient(app=app)
Some older plugins may use the following pattern in their tests, which is no longer supported:
```python
app = Datasette([], memory=True).app()
async with httpx.AsyncClient(app=app) as client:
response = await client.get("http://localhost/path")
```
The new pattern is to use `ds.client` like this:
```python
ds = Datasette([], memory=True)
response = ds.client.get("/path")
```

View file

@ -1,90 +1,76 @@
.. _upgrade_guide: (upgrade_guide)=
# Upgrade guide
=============== (upgrade_guide_v1)=
Upgrade guide ## Datasette 0.X -> 1.0
===============
.. _upgrade_guide_v1:
Datasette 0.X -> 1.0
====================
This section reviews breaking changes Datasette ``1.0`` has when upgrading from a ``0.XX`` version. For new features that ``1.0`` offers, see the :ref:`changelog`. This section reviews breaking changes Datasette ``1.0`` has when upgrading from a ``0.XX`` version. For new features that ``1.0`` offers, see the :ref:`changelog`.
.. _upgrade_guide_v1_sql_queries: (upgrade_guide_v1_sql_queries)=
### New URL for SQL queries
New URL for SQL queries
-----------------------
Prior to ``1.0a14`` the URL for executing a SQL query looked like this: Prior to ``1.0a14`` the URL for executing a SQL query looked like this:
:: ```text
/databasename?sql=select+1
/databasename?sql=select+1 # Or for JSON:
# Or for JSON: /databasename.json?sql=select+1
/databasename.json?sql=select+1 ```
This endpoint served two purposes: without a ``?sql=`` it would list the tables in the database, but with that option it would return results of a query instead. This endpoint served two purposes: without a ``?sql=`` it would list the tables in the database, but with that option it would return results of a query instead.
The URL for executing a SQL query now looks like this:: The URL for executing a SQL query now looks like this:
/databasename/-/query?sql=select+1 ```text
# Or for JSON: /databasename/-/query?sql=select+1
/databasename/-/query.json?sql=select+1 # Or for JSON:
/databasename/-/query.json?sql=select+1
```
**This isn't a breaking change.** API calls to the older ``/databasename?sql=...`` endpoint will redirect to the new ``databasename/-/query?sql=...`` endpoint. Upgrading to the new URL is recommended to avoid the overhead of the additional redirect. **This isn't a breaking change.** API calls to the older ``/databasename?sql=...`` endpoint will redirect to the new ``databasename/-/query?sql=...`` endpoint. Upgrading to the new URL is recommended to avoid the overhead of the additional redirect.
.. _upgrade_guide_v1_metadata: (upgrade_guide_v1_metadata)=
### Metadata changes
Metadata changes Metadata was completely revamped for Datasette 1.0. There are a number of related breaking changes, from the ``metadata.yaml`` file to Python APIs, that you'll need to consider when upgrading.
----------------
Metadata was completely revamped for Datasette 1.0. There are a number of related breaking changes, from the ``metadata.yaml`` file to Python APIs, that you'll need to consider when upgrading. (upgrade_guide_v1_metadata_split)=
#### ``metadata.yaml`` split into ``datasette.yaml``
.. _upgrade_guide_v1_metadata_split: Before Datasette 1.0, the ``metadata.yaml`` file became a kitchen sink if a mix of metadata, configuration, and settings. Now ``metadata.yaml`` is strictly for metadata (ex title and descriptions of database and tables, licensing info, etc). Other settings have been moved to a ``datasette.yml`` configuration file, described in :ref:`configuration`.
``metadata.yaml`` split into ``datasette.yaml``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before Datasette 1.0, the ``metadata.yaml`` file became a kitchen sink if a mix of metadata, configuration, and settings. Now ``metadata.yaml`` is strictly for metaata (ex title and descriptions of database and tables, licensing info, etc). Other settings have been moved to a ``datasette.yml`` configuration file, described in :ref:`configuration`.
To start Datasette with both metadata and configuration files, run it like this: To start Datasette with both metadata and configuration files, run it like this:
.. code-block:: bash ```bash
datasette --metadata metadata.yaml --config datasette.yaml
# Or the shortened version:
datasette -m metadata.yml -c datasette.yml
```
datasette --metadata metadata.yaml --config datasette.yaml (upgrade_guide_v1_metadata_upgrade)=
# Or the shortened version: #### Upgrading an existing ``metadata.yaml`` file
datasette -m metadata.yml -c datasette.yml
.. _upgrade_guide_v1_metadata_upgrade: The [datasette-upgrade plugin](https://github.com/datasette/datasette-upgrade) can be used to split a Datasette 0.x.x ``metadata.yaml`` (or ``.json``) file into separate ``metadata.yaml`` and ``datasette.yaml`` files. First, install the plugin:
Upgrading an existing ``metadata.yaml`` file ```bash
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ datasette install datasette-upgrade
```
The `datasette-upgrade plugin <https://github.com/datasette/datasette-upgrade>`__ can be used to split a Datasette 0.x.x ``metadata.yaml`` (or ``.json``) file into separate ``metadata.yaml`` and ``datasette.yaml`` files. First, install the plugin:
.. code-block:: bash
datasette install datasette-upgrade
Then run it like this to produce the two new files: Then run it like this to produce the two new files:
.. code-block:: bash ```bash
datasette upgrade metadata-to-config metadata.json -m metadata.yml -c datasette.yml
```
datasette upgrade metadata-to-config metadata.json -m metadata.yml -c datasette.yml #### Metadata "fallback" has been removed
Metadata "fallback" has been removed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Certain keys in metadata like ``license`` used to "fallback" up the chain of ownership. Certain keys in metadata like ``license`` used to "fallback" up the chain of ownership.
For example, if you set an ``MIT`` to a database and a table within that database did not have a specified license, then that table would inherit an ``MIT`` license. For example, if you set an ``MIT`` to a database and a table within that database did not have a specified license, then that table would inherit an ``MIT`` license.
This behavior has been removed in Datasette 1.0. Now license fields must be placed on all items, including individual databases and tables. This behavior has been removed in Datasette 1.0. Now license fields must be placed on all items, including individual databases and tables.
.. _upgrade_guide_v1_metadata_removed: (upgrade_guide_v1_metadata_removed)=
#### The ``get_metadata()`` plugin hook has been removed
The ``get_metadata()`` plugin hook has been removed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Datasette ``0.x`` plugins could implement a ``get_metadata()`` plugin hook to customize how metadata was retrieved for different instances, databases and tables. In Datasette ``0.x`` plugins could implement a ``get_metadata()`` plugin hook to customize how metadata was retrieved for different instances, databases and tables.
@ -92,33 +78,29 @@ This hook could be inefficient, since some pages might load metadata for many di
As of Datasette ``1.0a14`` (2024-08-05), the ``get_metadata()`` hook has been deprecated: As of Datasette ``1.0a14`` (2024-08-05), the ``get_metadata()`` hook has been deprecated:
.. code-block:: python ```python
# ❌ DEPRECATED in Datasette 1.0
# ❌ DEPRECATED in Datasette 1.0 @hookimpl
@hookimpl def get_metadata(datasette, key, database, table):
def get_metadata(datasette, key, database, table): pass
pass ```
Instead, plugins are encouraged to interact directly with Datasette's in-memory metadata tables in SQLite using the following methods on the :ref:`internals_datasette`: Instead, plugins are encouraged to interact directly with Datasette's in-memory metadata tables in SQLite using the following methods on the :ref:`internals_datasette`:
- :ref:`get_instance_metadata() <datasette_get_instance_metadata>` and :ref:`set_instance_metadata() <datasette_set_instance_metadata>` - :ref:`get_instance_metadata() <datasette_get_instance_metadata>` and :ref:`set_instance_metadata() <datasette_set_instance_metadata>`
- :ref:`get_database_metadata() <datasette_get_database_metadata>` and :ref:`set_database_metadata() <datasette_set_database_metadata>` - :ref:`get_database_metadata() <datasette_get_database_metadata>` and :ref:`set_database_metadata() <datasette_set_database_metadata>`
- :ref:`get_resource_metadata() <datasette_get_resource_metadata>` and :ref:`set_resource_metadata() <datasette_set_resource_metadata>` - :ref:`get_resource_metadata() <datasette_get_resource_metadata>` and :ref:`set_resource_metadata() <datasette_set_resource_metadata>`
- :ref:`get_column_metadata() <datasette_get_column_metadata>` and :ref:`set_column_metadata() <datasette_set_column_metadata>` - :ref:`get_column_metadata() <datasette_get_column_metadata>` and :ref:`set_column_metadata() <datasette_set_column_metadata>`
A plugin that stores or calculates its own metadata can implement the :ref:`plugin_hook_startup` hook to populate those items on startup, and then call those methods while it is running to persist any new metadata changes. A plugin that stores or calculates its own metadata can implement the :ref:`plugin_hook_startup` hook to populate those items on startup, and then call those methods while it is running to persist any new metadata changes.
.. _upgrade_guide_v1_metadata_json_removed: (upgrade_guide_v1_metadata_json_removed)=
#### The ``/metadata.json`` endpoint has been removed
The ``/metadata.json`` endpoint has been removed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of Datasette ``1.0a14``, the root level ``/metadata.json`` endpoint has been removed. Metadata for tables will become available through currently in-development extras in a future alpha. As of Datasette ``1.0a14``, the root level ``/metadata.json`` endpoint has been removed. Metadata for tables will become available through currently in-development extras in a future alpha.
.. _upgrade_guide_v1_metadata_method_removed: (upgrade_guide_v1_metadata_method_removed)=
#### The ``metadata()`` method on the Datasette class has been removed
The ``metadata()`` method on the Datasette class has been removed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of Datasette ``1.0a14``, the ``.metadata()`` method on the Datasette Python API has been removed. As of Datasette ``1.0a14``, the ``.metadata()`` method on the Datasette Python API has been removed.
@ -128,3 +110,7 @@ Instead, one should use the following methods on a Datasette class:
- :ref:`get_database_metadata() <datasette_get_database_metadata>` - :ref:`get_database_metadata() <datasette_get_database_metadata>`
- :ref:`get_resource_metadata() <datasette_get_resource_metadata>` - :ref:`get_resource_metadata() <datasette_get_resource_metadata>`
- :ref:`get_column_metadata() <datasette_get_column_metadata>` - :ref:`get_column_metadata() <datasette_get_column_metadata>`
```{include} upgrade-1.0a20.md
:heading-offset: 1
```