sections
21 rows where breadcrumbs contains "Upgrade guide", page = "upgrade_guide" and references = "[]"
This data as json, CSV (advanced)
Suggested facets: title, breadcrumbs, breadcrumbs (array)
| id ▼ | page | ref | title | content | breadcrumbs | references |
|---|---|---|---|---|---|---|
| upgrade_guide:fixing-async-with-httpx-asyncclient-app-app | upgrade_guide | fixing-async-with-httpx-asyncclient-app-app | Fixing async with httpx.AsyncClient(app=app) | Some older plugins may use the following pattern in their tests, which is no longer supported: 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: ds = Datasette([], memory=True) response = await ds.client.get("/path") | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
| upgrade_guide:metadata-fallback-has-been-removed | upgrade_guide | metadata-fallback-has-been-removed | Metadata "fallback" has been removed | 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. 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", "Datasette 0.X -> 1.0", "Metadata changes"] | [] |
| upgrade_guide:migrating-from-metadata-to-config | upgrade_guide | migrating-from-metadata-to-config | Migrating from metadata= to config= | Datasette 1.0 separates metadata (titles, descriptions, licenses) from configuration (settings, plugins, queries, permissions). Plugin tests and code need to be updated accordingly. | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
| upgrade_guide:permissions-are-now-actions | upgrade_guide | permissions-are-now-actions | Permissions are now actions | The register_permissions() hook shoud be replaced with register_actions() . Old code: @hookimpl def register_permissions(datasette): return [ Permission( name="explain-sql", abbr=None, description="Can explain SQL queries", takes_database=True, takes_resource=False, default=False, ), Permission( name="annotate-rows", abbr=None, description="Can annotate rows", takes_database=True, takes_resource=True, default=False, ), Permission( name="view-debug-info", abbr=None, description="Can view debug information", takes_database=False, takes_resource=False, default=False, ), ] The new Action does not have a default= parameter. Here's the equivalent new code: from datasette import hookimpl from datasette.permissions import Action from datasette.resources import DatabaseResource, TableResource @hookimpl def register_actions(datasette): return [ Action( name="explain-sql", description="Explain SQL queries", resource_class=DatabaseResource, ), Action( name="annotate-rows", description="Annotate rows", resource_class=TableResource, ), Action( name="view-debug-info", description="View debug information", ), ] The abbr= is now optional and defaults to None . For actions that apply to specific resources (like databases or tables), specify the resource_class instead of takes_parent and takes_child . Note that view-debug-info does not specify a resource_class because it applies globally. | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
| upgrade_guide:root-enabled-instances-during-testing | upgrade_guide | root-enabled-instances-during-testing | Root-enabled instances during testing | When writing tests that exercise root-only functionality, make sure to set datasette.root_enabled = True on the Datasette instance. Root permissions are only granted automatically when Datasette is started with datasette --root or when the flag is enabled directly in tests. | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide", "Root user checks are no longer necessary"] | [] |
| upgrade_guide:root-user-checks-are-no-longer-necessary | upgrade_guide | root-user-checks-are-no-longer-necessary | Root user checks are no longer necessary | Some plugins would introduce their own custom permission and then ensure the "root" actor had access to it using a pattern like this: @hookimpl def register_permissions(datasette): return [ Permission( name="upload-dbs", abbr=None, description="Upload SQLite database files", takes_database=False, takes_resource=False, default=False, ) ] @hookimpl def permission_allowed(actor, action): if action == "upload-dbs" and actor and actor.get("id") == "root": return True This is no longer necessary in Datasette 1.0a20 - the "root" actor automatically has all permissions when Datasette is started with the datasette --root option. The permission_allowed() hook in this example can be entirely removed. | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
| upgrade_guide:target-the-new-apis-exclusively | upgrade_guide | target-the-new-apis-exclusively | Target the new APIs exclusively | Datasette 1.0a20’s permission system is substantially different from previous releases. Attempting to keep plugin code compatible with both the old permission_allowed() and the new allowed() interfaces leads to brittle workarounds. Prefer to adopt the 1.0a20 APIs ( register_actions , permission_resources_sql() , and datasette.allowed() ) outright and drop legacy fallbacks. | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
| upgrade_guide:update-datasette-metadata-calls | upgrade_guide | update-datasette-metadata-calls | Update datasette.metadata() calls | The datasette.metadata() method has been removed. Use these methods instead: Old code: try: title = datasette.metadata(database=database)["queries"][query_name]["title"] except (KeyError, TypeError): pass New code: try: query_info = await datasette.get_canned_query(database, query_name, request.actor) if query_info and "title" in query_info: title = query_info["title"] except (KeyError, TypeError): pass | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide", "Migrating from metadata= to config="] | [] |
| upgrade_guide:update-query-urls-in-tests | upgrade_guide | update-query-urls-in-tests | Update query URLs in tests | Datasette now redirects ?sql= parameters from database pages to the query view: Old code: response = await ds.client.get("/_memory.atom?sql=select+1") New code: response = await ds.client.get("/_memory/-/query.atom?sql=select+1") | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide", "Migrating from metadata= to config="] | [] |
| upgrade_guide:update-render-functions-to-async | upgrade_guide | update-render-functions-to-async | Update render functions to async | If your plugin's render function needs to call datasette.get_canned_query() or other async Datasette methods, it must be declared as async: Old code: def render_atom(datasette, request, sql, columns, rows, database, table, query_name, view_name, data): # ... if query_name: title = datasette.metadata(database=database)["queries"][query_name]["title"] New code: async def render_atom(datasette, request, sql, columns, rows, database, table, query_name, view_name, data): # ... if query_name: query_info = await datasette.get_canned_query(database, query_name, request.actor) if query_info and "title" in query_info: title = query_info["title"] | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide", "Migrating from metadata= to config="] | [] |
| upgrade_guide:update-test-constructors | upgrade_guide | update-test-constructors | Update test constructors | Old code: ds = Datasette( memory=True, metadata={ "databases": { "_memory": {"queries": {"my_query": {"sql": "select 1", "title": "My Query"}}} }, "plugins": { "my-plugin": {"setting": "value"} } } ) New code: ds = Datasette( memory=True, config={ "databases": { "_memory": {"queries": {"my_query": {"sql": "select 1", "title": "My Query"}}} }, "plugins": { "my-plugin": {"setting": "value"} } } ) | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide", "Migrating from metadata= to config="] | [] |
| upgrade_guide:upgrade-guide-v1 | upgrade_guide | 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 Changelog . | ["Upgrade guide"] | [] |
| upgrade_guide:upgrade-guide-v1-a20 | upgrade_guide | upgrade-guide-v1-a20 | Datasette 1.0a20 plugin upgrade guide | 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 use 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. | ["Upgrade guide"] | [] |
| upgrade_guide:upgrade-guide-v1-a25 | upgrade_guide | upgrade-guide-v1-a25 | Datasette 1.0a25: | datasette.create_token() is now an async method (previously it was synchronous). The restrict_all , restrict_database , and restrict_resource keyword arguments have been replaced by a single restrictions parameter that accepts a TokenRestrictions object. Old code: token = datasette.create_token( actor_id="user1", restrict_all=["view-instance", "view-table"], restrict_database={"docs": ["view-query"]}, restrict_resource={ "docs": { "attachments": ["insert-row", "update-row"] } }, ) New code: from datasette.tokens import TokenRestrictions token = await datasette.create_token( actor_id="user1", restrictions=( TokenRestrictions() .allow_all("view-instance") .allow_all("view-table") .allow_database("docs", "view-query") .allow_resource("docs", "attachments", "insert-row") .allow_resource("docs", "attachments", "update-row") ), ) The datasette create-token CLI command is unchanged. | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
| upgrade_guide:upgrade-guide-v1-metadata | upgrade_guide | upgrade-guide-v1-metadata | 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. | ["Upgrade guide", "Datasette 0.X -> 1.0"] | [] |
| upgrade_guide:upgrade-guide-v1-metadata-json-removed | upgrade_guide | upgrade-guide-v1-metadata-json-removed | The | 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", "Datasette 0.X -> 1.0", "Metadata changes"] | [] |
| upgrade_guide:upgrade-guide-v1-metadata-method-removed | upgrade_guide | upgrade-guide-v1-metadata-method-removed | The | As of Datasette 1.0a14 , the .metadata() method on the Datasette Python API has been removed. Instead, one should use the following methods on a Datasette class: get_instance_metadata() get_database_metadata() get_resource_metadata() get_column_metadata() | ["Upgrade guide", "Datasette 0.X -> 1.0", "Metadata changes"] | [] |
| upgrade_guide:upgrade-guide-v1-metadata-removed | upgrade_guide | upgrade-guide-v1-metadata-removed | The | In Datasette 0.x plugins could implement a get_metadata() plugin hook to customize how metadata was retrieved for different instances, databases and tables. This hook could be inefficient, since some pages might load metadata for many different items (to list a large number of tables, for example) which could result in a large number of calls to potentially expensive plugin hook implementations. As of Datasette 1.0a14 (2024-08-05), the get_metadata() hook has been deprecated: # ❌ DEPRECATED in Datasette 1.0 @hookimpl def get_metadata(datasette, key, database, table): pass Instead, plugins are encouraged to interact directly with Datasette's in-memory metadata tables in SQLite using the following methods on the Datasette class : get_instance_metadata() and set_instance_metadata() get_database_metadata() and set_database_metadata() get_resource_metadata() and set_resource_metadata() get_column_metadata() and set_column_metadata() A plugin that stores or calculates its own metadata can implement the startup(datasette) hook to populate those items on startup, and then call those methods while it is running to persist any new metadata changes. | ["Upgrade guide", "Datasette 0.X -> 1.0", "Metadata changes"] | [] |
| upgrade_guide:upgrade-guide-v1-metadata-split | upgrade_guide | 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 Configuration . To start Datasette with both metadata and configuration files, run it like this: datasette --metadata metadata.yaml --config datasette.yaml # Or the shortened version: datasette -m metadata.yml -c datasette.yml | ["Upgrade guide", "Datasette 0.X -> 1.0", "Metadata changes"] | [] | |
| upgrade_guide:upgrade-guide-v1-sql-queries | upgrade_guide | upgrade-guide-v1-sql-queries | New URL for SQL queries | Prior to 1.0a14 the URL for executing a SQL query looked like this: /databasename?sql=select+1 # Or for JSON: /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. The URL for executing a SQL query now looks like this: /databasename/-/query?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. | ["Upgrade guide", "Datasette 0.X -> 1.0"] | [] |
| upgrade_guide:using-datasette-allowed-to-check-permissions-instead-of-datasette-permission-allowed | upgrade_guide | using-datasette-allowed-to-check-permissions-instead-of-datasette-permission-allowed | Using datasette.allowed() to check permissions instead of datasette.permission_allowed() | The internal method datasette.permission_allowed() has been replaced by datasette.allowed() . The old method looked like this: can_debug = await datasette.permission_allowed( request.actor, "view-debug-info", ) can_explain_sql = await datasette.permission_allowed( request.actor, "explain-sql", resource="database_name", ) can_annotate_rows = await datasette.permission_allowed( request.actor, "annotate-rows", resource=(database_name, table_name), ) Note the confusing design here where resource could be either a string or a tuple depending on the permission being checked. The new keyword-only design makes this a lot more clear: from datasette.resources import DatabaseResource, TableResource can_debug = await datasette.allowed( actor=request.actor, action="view-debug-info", ) can_explain_sql = await datasette.allowed( actor=request.actor, action="explain-sql", resource=DatabaseResource(database_name), ) can_annotate_rows = await datasette.allowed( actor=request.actor, action="annotate-rows", resource=TableResource(database_name, table_name), ) | ["Upgrade guide", "Datasette 1.0a20 plugin upgrade guide"] | [] |
Advanced export
JSON shape: default, array, newline-delimited, object
CREATE TABLE [sections] ( [id] TEXT PRIMARY KEY, [page] TEXT, [ref] TEXT, [title] TEXT, [content] TEXT, [breadcrumbs] TEXT, [references] TEXT );