# repos

node_id: R_kgDOKx8XZg
name: datasette-enrichments-opencage
full_name: datasette/datasette-enrichments-opencage
html_url: https://github.com/datasette/datasette-enrichments-opencage
description: Geocoding and reverse geocoding using OpenCage
created_at: 2023-11-25T18:21:47Z
updated_at: 2025-11-12T23:14:56Z
pushed_at: 2025-11-12T23:14:51Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
readme:
  # datasette-enrichments-opencage

  [![PyPI](https://img.shields.io/pypi/v/datasette-enrichments-opencage.svg)](https://pypi.org/project/datasette-enrichments-opencage/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-enrichments-opencage?include_prereleases&label=changelog)](https://github.com/datasette/datasette-enrichments-opencage/releases)
  [![Tests](https://github.com/datasette/datasette-enrichments-opencage/workflows/Test/badge.svg)](https://github.com/datasette/datasette-enrichments-opencage/actions?query=workflow%3ATest)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-enrichments-opencage/blob/main/LICENSE)

  Geocoding enrichment using OpenCage

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-enrichments-opencage
  ```
  ## Usage

  This plugin adds an enrichment for geocoding using the [OpenCage Geocoder](https://opencagedata.com/).

  You will need an API key from OpenCage - you can sign up for a free trial at https://opencagedata.com/users/sign_up.

  Filter for data that you wish to geocode, then apply the OpenCage geocoder enrichment.

  You'll need to specify a template to be passed to the geocoder, specifying which templates should be used as the input.

  If you have a single column containing the address, you can use this:

      {{ address }}

  If you have separate columns for the street, city, state and country, you can use this:

      {{ street }}, {{ city }}, {{ state }}, {{ country }}

  If your address column is missing the country, but all of the addresses are in the USA, you could use this:

      {{ address }}, USA

  See the [OpenCage guide](https://opencagedata.com/guides/how-to-format-your-geocoding-query) for tips on how to get the best results.

  By default only the latitude and longitude from the geocoder will be stored, in the `latitude` and `longitude` columns on your table. These columns will be created if they do not yet exist.

  You can optionally specify a column to store the full JSON output of the geocoder. This column will also be created if it does not exist.

  The full JSON format is [described here](https://opencagedata.com/api#response).

  ## Configuration

  You can use this plugin without configuration, but you'll need to enter your API key every time you run an enrichment.

  To avoid that, you can set your API key as plugin configuration like this:

  ```bash
  export OPENCAGE_API_KEY="your-api-key"
  ```
  Then in `metadata.yml`:
  ```yaml
  plugins:
    datasette-enrichments-opencage:
      api_key:
        $env: OPENCAGE_API_KEY
  ```
  Then run Datasette like this:
  ```bash
  datasette mydatabase.db -m metadata.yml --root
  ```
  This well give you a URL to sign in as the "root" user, which grants you access to the enrichment.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-enrichments-opencage
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-enrichments-opencage</h1><a id="user-content-datasette-enrichments-opencage" class="anchor" aria-label="Permalink: datasette-enrichments-opencage" href="#datasette-enrichments-opencage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-enrichments-opencage/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-enrichments-opencage.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/49b209c436a69afcd809e03319dbc319b5dcb60a0332111cb5c146b0472ba06d/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d656e726963686d656e74732d6f70656e636167652e737667"></a>
  <a href="https://github.com/datasette/datasette-enrichments-opencage/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-enrichments-opencage?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/f96e46812dbcf574eb070f17efc37c78c85ce74b438c1f0e6bcba0d5cff77f7d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d656e726963686d656e74732d6f70656e636167653f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-enrichments-opencage/actions?query=workflow%3ATest"><img src="https://github.com/datasette/datasette-enrichments-opencage/workflows/Test/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-enrichments-opencage/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Geocoding enrichment using OpenCage</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-enrichments-opencage"><pre>datasette install datasette-enrichments-opencage</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin adds an enrichment for geocoding using the <a href="https://opencagedata.com/" rel="nofollow">OpenCage Geocoder</a>.</p>
  <p dir="auto">You will need an API key from OpenCage - you can sign up for a free trial at <a href="https://opencagedata.com/users/sign_up" rel="nofollow">https://opencagedata.com/users/sign_up</a>.</p>
  <p dir="auto">Filter for data that you wish to geocode, then apply the OpenCage geocoder enrichment.</p>
  <p dir="auto">You'll need to specify a template to be passed to the geocoder, specifying which templates should be used as the input.</p>
  <p dir="auto">If you have a single column containing the address, you can use this:</p>
  <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{{ address }}"><pre class="notranslate"><code>{{ address }}
  </code></pre></div>
  <p dir="auto">If you have separate columns for the street, city, state and country, you can use this:</p>
  <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{{ street }}, {{ city }}, {{ state }}, {{ country }}"><pre class="notranslate"><code>{{ street }}, {{ city }}, {{ state }}, {{ country }}
  </code></pre></div>
  <p dir="auto">If your address column is missing the country, but all of the addresses are in the USA, you could use this:</p>
  <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{{ address }}, USA"><pre class="notranslate"><code>{{ address }}, USA
  </code></pre></div>
  <p dir="auto">See the <a href="https://opencagedata.com/guides/how-to-format-your-geocoding-query" rel="nofollow">OpenCage guide</a> for tips on how to get the best results.</p>
  <p dir="auto">By default only the latitude and longitude from the geocoder will be stored, in the <code>latitude</code> and <code>longitude</code> columns on your table. These columns will be created if they do not yet exist.</p>
  <p dir="auto">You can optionally specify a column to store the full JSON output of the geocoder. This column will also be created if it does not exist.</p>
  <p dir="auto">The full JSON format is <a href="https://opencagedata.com/api#response" rel="nofollow">described here</a>.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Configuration</h2><a id="user-content-configuration" class="anchor" aria-label="Permalink: Configuration" href="#configuration"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">You can use this plugin without configuration, but you'll need to enter your API key every time you run an enrichment.</p>
  <p dir="auto">To avoid that, you can set your API key as plugin configuration like this:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export OPENCAGE_API_KEY="your-api-key""><pre><span class="pl-k">export</span> OPENCAGE_API_KEY=<span class="pl-s"><span class="pl-pds">"</span>your-api-key<span class="pl-pds">"</span></span></pre></div>
  <p dir="auto">Then in <code>metadata.yml</code>:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plugins:
    datasette-enrichments-opencage:
      api_key:
        $env: OPENCAGE_API_KEY"><pre><span class="pl-ent">plugins</span>:
    <span class="pl-ent">datasette-enrichments-opencage</span>:
      <span class="pl-ent">api_key</span>:
        <span class="pl-ent">$env</span>: <span class="pl-s">OPENCAGE_API_KEY</span></pre></div>
  <p dir="auto">Then run Datasette like this:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette mydatabase.db -m metadata.yml --root"><pre>datasette mydatabase.db -m metadata.yml --root</pre></div>
  <p dir="auto">This well give you a URL to sign in as the "root" user, which grants you access to the enrichment.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-enrichments-opencage
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-enrichments-opencage
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOKyy0cA
name: datasette-enrichments-re2
full_name: datasette/datasette-enrichments-re2
html_url: https://github.com/datasette/datasette-enrichments-re2
description: Enrich data using regular expressions powered by re2
created_at: 2023-11-27T22:39:11Z
updated_at: 2023-12-12T21:59:08Z
pushed_at: 2023-11-30T02:12:47Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-enrichments-re2

  [![PyPI](https://img.shields.io/pypi/v/datasette-enrichments-re2.svg)](https://pypi.org/project/datasette-enrichments-re2/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-enrichments-re2?include_prereleases&label=changelog)](https://github.com/datasette/datasette-enrichments-re2/releases)
  [![Tests](https://github.com/datasette/datasette-enrichments-re2/workflows/Test/badge.svg)](https://github.com/datasette/datasette-enrichments-re2/actions?query=workflow%3ATest)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-enrichments-re2/blob/main/LICENSE)

  Enrich data using regular expressions

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-enrichments-re2
  ```
  ## Usage

  This enrichment allows you to run a regular expression against a column and perform one of the following:

  - Execute a search and replace against that column
  - Extract the first matching result and store that in the specified column (adding a column if necessary)
  - Extract all matching results and store them as a JSON array in the specified column. If the regular expression uses named capture groups this will be an array of objects, otherwise it will be an array of strings.
  - Execute a regular expression with named capture groups and store the results in multiple columns, one for each of those named groups

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-enrichments-re2
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-enrichments-re2</h1><a id="user-content-datasette-enrichments-re2" class="anchor" aria-label="Permalink: datasette-enrichments-re2" href="#datasette-enrichments-re2"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-enrichments-re2/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-enrichments-re2.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/b81de04d192f05823a3a1ea4ddab8fe9ecbf5b6f1657af32d465009652d11b1a/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d656e726963686d656e74732d7265322e737667"></a>
  <a href="https://github.com/datasette/datasette-enrichments-re2/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-enrichments-re2?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/1f3171aabe56c3c2e876627af7162ae3f591f406274f4d8f1b7b6c2169113fca/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d656e726963686d656e74732d7265323f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-enrichments-re2/actions?query=workflow%3ATest"><img src="https://github.com/datasette/datasette-enrichments-re2/workflows/Test/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-enrichments-re2/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Enrich data using regular expressions</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-enrichments-re2"><pre>datasette install datasette-enrichments-re2</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This enrichment allows you to run a regular expression against a column and perform one of the following:</p>
  <ul dir="auto">
  <li>Execute a search and replace against that column</li>
  <li>Extract the first matching result and store that in the specified column (adding a column if necessary)</li>
  <li>Extract all matching results and store them as a JSON array in the specified column. If the regular expression uses named capture groups this will be an array of objects, otherwise it will be an array of strings.</li>
  <li>Execute a regular expression with named capture groups and store the results in multiple columns, one for each of those named groups</li>
  </ul>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-enrichments-re2
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-enrichments-re2
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOK2ToCw
name: datasette-chronicle
full_name: datasette/datasette-chronicle
html_url: https://github.com/datasette/datasette-chronicle
description: Enable sqlite-chronicle against tables in Datasette
created_at: 2023-12-06T04:46:49Z
updated_at: 2025-05-13T18:19:48Z
pushed_at: 2025-05-13T18:21:37Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-chronicle

  [![PyPI](https://img.shields.io/pypi/v/datasette-chronicle.svg)](https://pypi.org/project/datasette-chronicle/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-chronicle?include_prereleases&label=changelog)](https://github.com/datasette/datasette-chronicle/releases)
  [![Tests](https://github.com/datasette/datasette-chronicle/workflows/Test/badge.svg)](https://github.com/datasette/datasette-chronicle/actions?query=workflow%3ATest)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-chronicle/blob/main/LICENSE)

  Use [sqlite-chronicle](https://github.com/simonw/sqlite-chronicle) with tables in Datasette

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-chronicle
  ```
  ## Usage

  Once installed, users with the `enable-chronicle` and `disable-chronicle` permissions (granted to the `root` user by default) will have access to new table action menu options for enabling and disabling row version tracking for a table.

  Tables that have had row version tracking enabled will now support a new `?_since=X` query string parameter on the table page, which will filter for just rows that have been inserted or updated since the specified chronicle version.

  See the [sqlite-chronicle documentation](https://github.com/simonw/sqlite-chronicle/blob/main/README.md) for more details on what this is and how it works.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-chronicle
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-chronicle</h1><a id="user-content-datasette-chronicle" class="anchor" aria-label="Permalink: datasette-chronicle" href="#datasette-chronicle"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-chronicle/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-chronicle.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/a2ecb0705c015c421043c028c2ccb9c6c404f6ba0b92b2bd6f5c482ba3e7a70e/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d6368726f6e69636c652e737667"></a>
  <a href="https://github.com/datasette/datasette-chronicle/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-chronicle?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/b132c90e5a117346436f4ca8790f76784698908653f4a0fd6f87c151faee41a9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d6368726f6e69636c653f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-chronicle/actions?query=workflow%3ATest"><img src="https://github.com/datasette/datasette-chronicle/workflows/Test/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-chronicle/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Use <a href="https://github.com/simonw/sqlite-chronicle">sqlite-chronicle</a> with tables in Datasette</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-chronicle"><pre>datasette install datasette-chronicle</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Once installed, users with the <code>enable-chronicle</code> and <code>disable-chronicle</code> permissions (granted to the <code>root</code> user by default) will have access to new table action menu options for enabling and disabling row version tracking for a table.</p>
  <p dir="auto">Tables that have had row version tracking enabled will now support a new <code>?_since=X</code> query string parameter on the table page, which will filter for just rows that have been inserted or updated since the specified chronicle version.</p>
  <p dir="auto">See the <a href="https://github.com/simonw/sqlite-chronicle/blob/main/README.md">sqlite-chronicle documentation</a> for more details on what this is and how it works.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-chronicle
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-chronicle
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLIwk4A
name: datasette-proxy-url
full_name: datasette/datasette-proxy-url
html_url: https://github.com/datasette/datasette-proxy-url
description: Proxy a URL through a Datasette instance
created_at: 2024-01-23T20:19:30Z
updated_at: 2024-02-03T06:50:37Z
pushed_at: 2024-01-23T20:34:46Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-proxy-url

  [![PyPI](https://img.shields.io/pypi/v/datasette-proxy-url.svg)](https://pypi.org/project/datasette-proxy-url/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-proxy-url?include_prereleases&label=changelog)](https://github.com/datasette/datasette-proxy-url/releases)
  [![Tests](https://github.com/datasette/datasette-proxy-url/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-proxy-url/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-proxy-url/blob/main/LICENSE)

  Proxy a URL through a Datasette instance

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-proxy-url
  ```
  ## Usage

  This plugin can be configured to set specific paths within Datasette to proxy content from another URL.

  Configure the plugin like this:
  ```json
  {
      "plugins": {
          "datasette-proxy-url": {
              "paths": [
                  {"path": "/proxy", "backend": "http://example.com/"},
              ]
          }
      }
  }
  ```
  Now any request to `/proxy` will serve the HTML content from `http://example.com/`.

  The `content-type` response header and the content body will be passed through. All other headers are currently ignored.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-proxy-url
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-proxy-url</h1><a id="user-content-datasette-proxy-url" class="anchor" aria-label="Permalink: datasette-proxy-url" href="#datasette-proxy-url"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-proxy-url/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-proxy-url.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/69c5e74befce2c23709ddbeb23c5e888bfbc9af7ce2d5ba8d751b63d7f28dae6/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d70726f78792d75726c2e737667"></a>
  <a href="https://github.com/datasette/datasette-proxy-url/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-proxy-url?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/1dbb8605d6e0ecb3ba5d9c3e5d3eb5084bfed93a37bc96add328b3eb065d4b3a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d70726f78792d75726c3f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-proxy-url/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-proxy-url/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-proxy-url/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Proxy a URL through a Datasette instance</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-proxy-url"><pre>datasette install datasette-proxy-url</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin can be configured to set specific paths within Datasette to proxy content from another URL.</p>
  <p dir="auto">Configure the plugin like this:</p>
  <div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
      "plugins": {
          "datasette-proxy-url": {
              "paths": [
                  {"path": "/proxy", "backend": "http://example.com/"},
              ]
          }
      }
  }"><pre>{
      <span class="pl-ent">"plugins"</span>: {
          <span class="pl-ent">"datasette-proxy-url"</span>: {
              <span class="pl-ent">"paths"</span>: [
                  {<span class="pl-ent">"path"</span>: <span class="pl-s"><span class="pl-pds">"</span>/proxy<span class="pl-pds">"</span></span>, <span class="pl-ent">"backend"</span>: <span class="pl-s"><span class="pl-pds">"</span>http://example.com/<span class="pl-pds">"</span></span>},
              ]
          }
      }
  }</pre></div>
  <p dir="auto">Now any request to <code>/proxy</code> will serve the HTML content from <code>http://example.com/</code>.</p>
  <p dir="auto">The <code>content-type</code> response header and the content body will be passed through. All other headers are currently ignored.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-proxy-url
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-proxy-url
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLL5HMg
name: datasette-homepage-table
full_name: datasette/datasette-homepage-table
html_url: https://github.com/datasette/datasette-homepage-table
description: Show a specific Datasette table on the homepage
created_at: 2024-01-31T04:31:00Z
updated_at: 2024-02-13T22:53:29Z
pushed_at: 2024-01-31T18:50:48Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-homepage-table

  [![PyPI](https://img.shields.io/pypi/v/datasette-homepage-table.svg)](https://pypi.org/project/datasette-homepage-table/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-homepage-table?include_prereleases&label=changelog)](https://github.com/datasette/datasette-homepage-table/releases)
  [![Tests](https://github.com/datasette/datasette-homepage-table/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-homepage-table/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-homepage-table/blob/main/LICENSE)

  Show a specific Datasette table on the homepage

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-homepage-table
  ```
  ## Usage

  This plugin changes the Datasette homepage to display a table instead of the default list of databases.

  Without configuration, it will take the first table in the first attached database.

  Alternatively you can configure it like this:

  ```json
  {
      "plugins": {
          "datasette-homepage-table": {
              "database": "mydatabase",
              "table": "mytable"
          }
      }
  }
  ```
  Both keys are optional: if you omit `database` it will use the first attached database, and if you omit `table` it will use the first table in the database.

  You can customize the `table.html` template to [change the appearance of the table](https://docs.datasette.io/en/stable/custom_templates.html#custom-templates).

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-homepage-table
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-homepage-table</h1><a id="user-content-datasette-homepage-table" class="anchor" aria-label="Permalink: datasette-homepage-table" href="#datasette-homepage-table"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-homepage-table/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-homepage-table.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/2073089da3f89364d41ecc49957d73269cad352d0b86a6ce9de0dd17aa33ccf9/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d686f6d65706167652d7461626c652e737667"></a>
  <a href="https://github.com/datasette/datasette-homepage-table/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-homepage-table?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/1a1417197b33a87ef996bbe333dfd989af6c9199b30ec460d1f110b9197133ba/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d686f6d65706167652d7461626c653f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-homepage-table/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-homepage-table/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-homepage-table/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Show a specific Datasette table on the homepage</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-homepage-table"><pre>datasette install datasette-homepage-table</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin changes the Datasette homepage to display a table instead of the default list of databases.</p>
  <p dir="auto">Without configuration, it will take the first table in the first attached database.</p>
  <p dir="auto">Alternatively you can configure it like this:</p>
  <div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
      "plugins": {
          "datasette-homepage-table": {
              "database": "mydatabase",
              "table": "mytable"
          }
      }
  }"><pre>{
      <span class="pl-ent">"plugins"</span>: {
          <span class="pl-ent">"datasette-homepage-table"</span>: {
              <span class="pl-ent">"database"</span>: <span class="pl-s"><span class="pl-pds">"</span>mydatabase<span class="pl-pds">"</span></span>,
              <span class="pl-ent">"table"</span>: <span class="pl-s"><span class="pl-pds">"</span>mytable<span class="pl-pds">"</span></span>
          }
      }
  }</pre></div>
  <p dir="auto">Both keys are optional: if you omit <code>database</code> it will use the first attached database, and if you omit <code>table</code> it will use the first table in the database.</p>
  <p dir="auto">You can customize the <code>table.html</code> template to <a href="https://docs.datasette.io/en/stable/custom_templates.html#custom-templates" rel="nofollow">change the appearance of the table</a>.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-homepage-table
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-homepage-table
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLMquvQ
name: datasette-events-db
full_name: datasette/datasette-events-db
html_url: https://github.com/datasette/datasette-events-db
description: Log Datasette events to a database table
created_at: 2024-02-01T17:36:58Z
updated_at: 2025-11-08T00:30:47Z
pushed_at: 2025-11-08T00:31:08Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
template_repository:
  {"id": 400878073, "node_id": "MDEwOlJlcG9zaXRvcnk0MDA4NzgwNzM=", "name": "datasette-plugin-template-repository", "full_name": "simonw/datasette-plugin-template-repository", "private": false, "owner": {"login": "simonw", "id": 9599, "node_id": "MDQ6VXNlcjk1OTk=", "avatar_url": "https://avatars.githubusercontent.com/u/9599?v=4", "gravatar_id": "", "url": "https://api.github.com/users/simonw", "html_url": "https://github.com/simonw", "followers_url": "https://api.github.com/users/simonw/followers", "following_url": "https://api.github.com/users/simonw/following{/other_user}", "gists_url": "https://api.github.com/users/simonw/gists{/gist_id}", "starred_url": "https://api.github.com/users/simonw/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/simonw/subscriptions", "organizations_url": "https://api.github.com/users/simonw/orgs", "repos_url": "https://api.github.com/users/simonw/repos", "events_url": "https://api.github.com/users/simonw/events{/privacy}", "received_events_url": "https://api.github.com/users/simonw/received_events", "type": "User", "user_view_type": "public", "site_admin": false}, "html_url": "https://github.com/simonw/datasette-plugin-template-repository", "description": "GitHub template repository for creating new Datasette plugins, using the simonw/datasette-plugin cookiecutter template", "fork": false, "url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository", "forks_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/forks", "keys_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/teams", "hooks_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/hooks", "issue_events_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues/events{/number}", "events_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/events", "assignees_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/assignees{/user}", "branches_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/branches{/branch}", "tags_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/tags", "blobs_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/refs{/sha}", "trees_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/statuses/{sha}", "languages_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/languages", "stargazers_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/stargazers", "contributors_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/contributors", "subscribers_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/subscribers", "subscription_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/subscription", "commits_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/commits{/sha}", "git_commits_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/commits{/sha}", "comments_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/comments{/number}", "issue_comment_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues/comments{/number}", "contents_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/contents/{+path}", "compare_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/merges", "archive_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/downloads", "issues_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues{/number}", "pulls_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/pulls{/number}", "milestones_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/milestones{/number}", "notifications_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/labels{/name}", "releases_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/releases{/id}", "deployments_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/deployments", "created_at": "2021-08-28T19:50:28Z", "updated_at": "2026-03-03T05:49:18Z", "pushed_at": "2026-01-03T22:42:16Z", "git_url": "git://github.com/simonw/datasette-plugin-template-repository.git", "ssh_url": "git@github.com:simonw/datasette-plugin-template-repository.git", "clone_url": "https://github.com/simonw/datasette-plugin-template-repository.git", "svn_url": "https://github.com/simonw/datasette-plugin-template-repository", "homepage": "", "size": 27, "stargazers_count": 26, "watchers_count": 26, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": false, "has_discussions": false, "forks_count": 0, "mirror_url": null, "archived": false, "disabled": false, "open_issues_count": 0, "license": null, "allow_forking": true, "is_template": true, "web_commit_signoff_required": false, "has_pull_requests": true, "pull_request_creation_policy": "all", "topics": [], "visibility": "public", "forks": 0, "open_issues": 0, "watchers": 26, "default_branch": "main", "permissions": {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}, "temp_clone_token": ""}

readme:
  # datasette-events-db

  [![PyPI](https://img.shields.io/pypi/v/datasette-events-db.svg)](https://pypi.org/project/datasette-events-db/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-events-db?include_prereleases&label=changelog)](https://github.com/datasette/datasette-events-db/releases)
  [![Tests](https://github.com/datasette/datasette-events-db/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-events-db/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-events-db/blob/main/LICENSE)

  Log Datasette events to a database table

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-events-db
  ```
  This plugin depends on [Datasette 1.0a8](https://docs.datasette.io/en/latest/changelog.html#a8-2024-02-07) or higher.
  ## Usage

  Once installed, all [Datasette events](https://docs.datasette.io/en/latest/events.html) will be logged to a table called `datasette_events`. This table will be created in the `_internal` database, but can be moved to another database using the following plugin configuration option:

  ```yaml
  plugins:
    datasette-events-db:
      database: my_database
  ```

  The table will be created when Datasette starts up, if it does not already exist.

  ## Table schema

  ```sql
  create table if not exists datasette_events (
      id integer primary key,
      event text,
      created text,
      actor_id text,
      database_name text,
      table_name text,
      properties text -- JSON other properties
  )
  ```
  - `event` is the text name of the event, for example `create-table`
  - `created` is an ISO formatted UTC timestamp
  - `actor_id` will be populated with the ID of the responsible actor, or `null` if not available
  - `database_name` will be the `database` property recorded by the event, if present
  - `table_name` will be the `table` property recorded by the event, if present
  - `properties` will be a JSON object containing any other properties recorded by the event

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-events-db
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-events-db</h1><a id="user-content-datasette-events-db" class="anchor" aria-label="Permalink: datasette-events-db" href="#datasette-events-db"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-events-db/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-events-db.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/473789e3beac2ebe7a56bc946f4d98df4d5ba2300cfaf2643e4584e583cda299/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d6576656e74732d64622e737667"></a>
  <a href="https://github.com/datasette/datasette-events-db/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-events-db?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/07c7bfa2d15614ff37dc88b8c06871aacf615bc951d4bf6bfaf52d15430283ac/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d6576656e74732d64623f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-events-db/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-events-db/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-events-db/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Log Datasette events to a database table</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-events-db"><pre>datasette install datasette-events-db</pre></div>
  <p dir="auto">This plugin depends on <a href="https://docs.datasette.io/en/latest/changelog.html#a8-2024-02-07" rel="nofollow">Datasette 1.0a8</a> or higher.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Once installed, all <a href="https://docs.datasette.io/en/latest/events.html" rel="nofollow">Datasette events</a> will be logged to a table called <code>datasette_events</code>. This table will be created in the <code>_internal</code> database, but can be moved to another database using the following plugin configuration option:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plugins:
    datasette-events-db:
      database: my_database"><pre><span class="pl-ent">plugins</span>:
    <span class="pl-ent">datasette-events-db</span>:
      <span class="pl-ent">database</span>: <span class="pl-s">my_database</span></pre></div>
  <p dir="auto">The table will be created when Datasette starts up, if it does not already exist.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Table schema</h2><a id="user-content-table-schema" class="anchor" aria-label="Permalink: Table schema" href="#table-schema"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <div class="highlight highlight-source-sql notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="create table if not exists datasette_events (
      id integer primary key,
      event text,
      created text,
      actor_id text,
      database_name text,
      table_name text,
      properties text -- JSON other properties
  )"><pre><span class="pl-k">create</span> <span class="pl-k">table</span> <span class="pl-en">if</span> not exists datasette_events (
      id <span class="pl-k">integer</span> <span class="pl-k">primary key</span>,
      event <span class="pl-k">text</span>,
      created <span class="pl-k">text</span>,
      actor_id <span class="pl-k">text</span>,
      database_name <span class="pl-k">text</span>,
      table_name <span class="pl-k">text</span>,
      properties <span class="pl-k">text</span> <span class="pl-c"><span class="pl-c">--</span> JSON other properties</span>
  )</pre></div>
  <ul dir="auto">
  <li><code>event</code> is the text name of the event, for example <code>create-table</code></li>
  <li><code>created</code> is an ISO formatted UTC timestamp</li>
  <li><code>actor_id</code> will be populated with the ID of the responsible actor, or <code>null</code> if not available</li>
  <li><code>database_name</code> will be the <code>database</code> property recorded by the event, if present</li>
  <li><code>table_name</code> will be the <code>table</code> property recorded by the event, if present</li>
  <li><code>properties</code> will be a JSON object containing any other properties recorded by the event</li>
  </ul>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-events-db
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-events-db
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLQOkPw
name: datasette-enrichments-quickjs
full_name: datasette/datasette-enrichments-quickjs
html_url: https://github.com/datasette/datasette-enrichments-quickjs
description: Enrich data with a custom JavaScript function
created_at: 2024-02-09T16:58:21Z
updated_at: 2024-02-10T03:36:29Z
pushed_at: 2024-04-05T22:07:16Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-enrichments-quickjs

  [![PyPI](https://img.shields.io/pypi/v/datasette-enrichments-quickjs.svg)](https://pypi.org/project/datasette-enrichments-quickjs/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-enrichments-quickjs?include_prereleases&label=changelog)](https://github.com/datasette/datasette-enrichments-quickjs/releases)
  [![Tests](https://github.com/datasette/datasette-enrichments-quickjs/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-enrichments-quickjs/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-enrichments-quickjs/blob/main/LICENSE)

  [Datasette enrichment](https://github.com/simonw/datasette-enrichments) for enriching data with a custom JavaScript function

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-enrichments-quickjs
  ```
  ## Usage

  This enrichment allows you to select rows from a table and specify a custom JavaScript function to use to generate a value for each of those rows, storing that value in a specified column and creating that column if it does not exist.

  Code runs in a [QuickJS sandbox](https://github.com/PetterS/quickjs) with a 0.1s time limit for the execution of each function and a 4MB memory limit.

  Enrichment JavaScript functions look like this:

  ```javascript
  function enrich(row) {
      return row["title"] + "!";
  }
  ```
  The return value of your function will be stored in the output column of your choice.

  Instead of picking an output column, you can have your function return an object with keys and values.

  This example takes a `point` column with values like `37.7749,-122.4194 and splits it into `latitude` and `longitude` columns:

  ```javascript
  function enrich(row) {
      const bits = row.point.split(",");
      return {
          "latitude": parseFloat(bits[0]),
          "longitude": parseFloat(bits[1])
      }
  }
  ```
  The enrichment will then create new columns in the table for each key in the object returned by that function.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-enrichments-quickjs
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-enrichments-quickjs</h1><a id="user-content-datasette-enrichments-quickjs" class="anchor" aria-label="Permalink: datasette-enrichments-quickjs" href="#datasette-enrichments-quickjs"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-enrichments-quickjs/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-enrichments-quickjs.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/69fa9b7345c24341fb003b6b8522a9226676279c6107eb1567e615f5420fdc9f/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d656e726963686d656e74732d717569636b6a732e737667"></a>
  <a href="https://github.com/datasette/datasette-enrichments-quickjs/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-enrichments-quickjs?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/159aa3acf1d4e6a894cf4eecddfddb5180820745f62a57e5561769cdfa6bfbf1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d656e726963686d656e74732d717569636b6a733f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-enrichments-quickjs/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-enrichments-quickjs/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-enrichments-quickjs/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto"><a href="https://github.com/simonw/datasette-enrichments">Datasette enrichment</a> for enriching data with a custom JavaScript function</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-enrichments-quickjs"><pre>datasette install datasette-enrichments-quickjs</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This enrichment allows you to select rows from a table and specify a custom JavaScript function to use to generate a value for each of those rows, storing that value in a specified column and creating that column if it does not exist.</p>
  <p dir="auto">Code runs in a <a href="https://github.com/PetterS/quickjs">QuickJS sandbox</a> with a 0.1s time limit for the execution of each function and a 4MB memory limit.</p>
  <p dir="auto">Enrichment JavaScript functions look like this:</p>
  <div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function enrich(row) {
      return row["title"] + "!";
  }"><pre><span class="pl-k">function</span> <span class="pl-en">enrich</span><span class="pl-kos">(</span><span class="pl-s1">row</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-k">return</span> <span class="pl-s1">row</span><span class="pl-kos">[</span><span class="pl-s">"title"</span><span class="pl-kos">]</span> <span class="pl-c1">+</span> <span class="pl-s">"!"</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span></pre></div>
  <p dir="auto">The return value of your function will be stored in the output column of your choice.</p>
  <p dir="auto">Instead of picking an output column, you can have your function return an object with keys and values.</p>
  <p dir="auto">This example takes a <code>point</code> column with values like <code>37.7749,-122.4194 and splits it into </code>latitude<code>and</code>longitude` columns:</p>
  <div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function enrich(row) {
      const bits = row.point.split(",");
      return {
          "latitude": parseFloat(bits[0]),
          "longitude": parseFloat(bits[1])
      }
  }"><pre><span class="pl-k">function</span> <span class="pl-en">enrich</span><span class="pl-kos">(</span><span class="pl-s1">row</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-k">const</span> <span class="pl-s1">bits</span> <span class="pl-c1">=</span> <span class="pl-s1">row</span><span class="pl-kos">.</span><span class="pl-c1">point</span><span class="pl-kos">.</span><span class="pl-en">split</span><span class="pl-kos">(</span><span class="pl-s">","</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
      <span class="pl-k">return</span> <span class="pl-kos">{</span>
          <span class="pl-s">"latitude"</span>: <span class="pl-en">parseFloat</span><span class="pl-kos">(</span><span class="pl-s1">bits</span><span class="pl-kos">[</span><span class="pl-c1">0</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
          <span class="pl-s">"longitude"</span>: <span class="pl-en">parseFloat</span><span class="pl-kos">(</span><span class="pl-s1">bits</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">]</span><span class="pl-kos">)</span>
      <span class="pl-kos">}</span>
  <span class="pl-kos">}</span></pre></div>
  <p dir="auto">The enrichment will then create new columns in the table for each key in the object returned by that function.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-enrichments-quickjs
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-enrichments-quickjs
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLUUhXg
name: datasette-unsafe-actor-debug
full_name: datasette/datasette-unsafe-actor-debug
html_url: https://github.com/datasette/datasette-unsafe-actor-debug
description: Debug plugin that lets you imitate any actor
created_at: 2024-02-18T19:15:02Z
updated_at: 2024-02-18T19:21:14Z
pushed_at: 2024-02-18T20:20:13Z
language: Python
license: apache-2.0
topics: ["datasette-plugin"]
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-unsafe-actor-debug

  [![PyPI](https://img.shields.io/pypi/v/datasette-unsafe-actor-debug.svg)](https://pypi.org/project/datasette-unsafe-actor-debug/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-unsafe-actor-debug?include_prereleases&label=changelog)](https://github.com/datasette/datasette-unsafe-actor-debug/releases)
  [![Tests](https://github.com/datasette/datasette-unsafe-actor-debug/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-unsafe-actor-debug/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-unsafe-actor-debug/blob/main/LICENSE)

  Debug plugin that lets you imitate any actor. **Only use this for debugging purposes.**

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-unsafe-actor-debug
  ```
  ## Configuration

  You need to set the following plugin configuration to enable this tool:

  ```yaml
  plugins:
    datasette-unsafe-actor-debug:
      enabled: true
  ```

  With Datasette 1.0 alpha you can enable it like this:
  ```bash
  datasette -s plugins.datasette-unsafe-actor-debug.enabled 1
  ```

  ## Usage

  This plugin adds a public page at `/-/unsafe-actor` that lets you sign into Datasette as _any_ actor.

  This option will also be available through the Datasette global navigation menu.

  **Do not enable this tool in production!**

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-unsafe-actor-debug
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-unsafe-actor-debug</h1><a id="user-content-datasette-unsafe-actor-debug" class="anchor" aria-label="Permalink: datasette-unsafe-actor-debug" href="#datasette-unsafe-actor-debug"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-unsafe-actor-debug/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-unsafe-actor-debug.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/afcf7fe1d356eabe2f04b723a62df1e7cc1c894a2728c064cc7eb32945abeafd/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d756e736166652d6163746f722d64656275672e737667"></a>
  <a href="https://github.com/datasette/datasette-unsafe-actor-debug/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-unsafe-actor-debug?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/ce35dc1b25246c2f0e8acfd7d44e0fb1c4417a3ed24ee45b8a5241255ad2203f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d756e736166652d6163746f722d64656275673f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-unsafe-actor-debug/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-unsafe-actor-debug/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-unsafe-actor-debug/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Debug plugin that lets you imitate any actor. <strong>Only use this for debugging purposes.</strong></p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-unsafe-actor-debug"><pre>datasette install datasette-unsafe-actor-debug</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Configuration</h2><a id="user-content-configuration" class="anchor" aria-label="Permalink: Configuration" href="#configuration"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">You need to set the following plugin configuration to enable this tool:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plugins:
    datasette-unsafe-actor-debug:
      enabled: true"><pre><span class="pl-ent">plugins</span>:
    <span class="pl-ent">datasette-unsafe-actor-debug</span>:
      <span class="pl-ent">enabled</span>: <span class="pl-c1">true</span></pre></div>
  <p dir="auto">With Datasette 1.0 alpha you can enable it like this:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette -s plugins.datasette-unsafe-actor-debug.enabled 1"><pre>datasette -s plugins.datasette-unsafe-actor-debug.enabled 1</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin adds a public page at <code>/-/unsafe-actor</code> that lets you sign into Datasette as <em>any</em> actor.</p>
  <p dir="auto">This option will also be available through the Datasette global navigation menu.</p>
  <p dir="auto"><strong>Do not enable this tool in production!</strong></p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-unsafe-actor-debug
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-unsafe-actor-debug
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLU-JCQ
name: datasette-events-forward
full_name: datasette/datasette-events-forward
html_url: https://github.com/datasette/datasette-events-forward
description: Forward Datasette analytical events on to another Datasette instance
created_at: 2024-02-20T00:13:09Z
updated_at: 2025-11-10T23:45:50Z
pushed_at: 2025-11-10T23:46:42Z
homepage: https://datasette.io/plugins/datasette-events-forward
language: Python
license: apache-2.0
topics: ["datasette-plugin"]
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
readme:
  # datasette-events-forward

  [![PyPI](https://img.shields.io/pypi/v/datasette-events-forward.svg)](https://pypi.org/project/datasette-events-forward/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-events-forward?include_prereleases&label=changelog)](https://github.com/datasette/datasette-events-forward/releases)
  [![Tests](https://github.com/datasette/datasette-events-forward/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-events-forward/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-events-forward/blob/main/LICENSE)

  Forward Datasette events to another instance

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-events-forward
  ```

  ## Configuration

  Configure the plugin like so:

  ```json
  {
      "plugins": {
          "datasette-events-forward": {
              "api_token": "***",
              "api_url": "https://stats.datasette.cloud/data/-/create",
              "instance": "localhost"
          }
      }
  }
  ```
  The plugin will then gather all events and forward them to the specified instance, adding them to a table called `datasette_events` which will be created if it does not exist.

  The `instance` key can be used to differentiate different instances that report to the same backend. Events are identified with a ULID to ensure they are unique even across different instances.

  Events are forwarded in batches of up to 10, no more than once every 10 seconds.

  Full list of configuration settings:

  - `api_url`: The write API URL of a Datasette instance to forward the events to.
  - `api_token`: The API token to use when sending events. Use `{"$env": "FORWARD_TOKEN"}` to read the token from the `FORWARD_TOKEN` environment variable.
  - `instance`: A string to identify the instance that is sending the events.

  The `api_url` can be either a `https://datasette.example.com/data/datasette_events/-/insert` endpoint for inserting rows, or a `https://datasette.example.com/data/-/create` endpoint for creating a table and inserting rows into it. If the table does not yet exist you should use the `/-/create` variant, otherwise use the `/-/insert` variant.

  If you use `/-/insert` your API token just needs `insert-row` permissions. For `/-/create` you will need `create-table` permissions as well.

  And to control the rate at which batches of events are sent to the Datasette write API:

  - `batch_limit`: The number of events to send in each batch, defaults to 10. The Datasette write API has a 100 row limit by default so this should be set to a value less than that.
  - `max_rate`: The maximum number of deliver HTTP requests to send in the specified time period, defaults to 1.
  - `time_period`: The time period for the rate limiting in seconds, defaults to 10.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-events-forward
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-events-forward</h1><a id="user-content-datasette-events-forward" class="anchor" aria-label="Permalink: datasette-events-forward" href="#datasette-events-forward"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-events-forward/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-events-forward.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/610218897a9c436647d3bd02404c2237ba45001088a41b1288f2675ca6fd83e9/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d6576656e74732d666f72776172642e737667"></a>
  <a href="https://github.com/datasette/datasette-events-forward/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-events-forward?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/82f69fa40df33b6e62d539f6b487028a908096a502d1d63473761104267c6692/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d6576656e74732d666f72776172643f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-events-forward/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-events-forward/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-events-forward/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Forward Datasette events to another instance</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-events-forward"><pre>datasette install datasette-events-forward</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Configuration</h2><a id="user-content-configuration" class="anchor" aria-label="Permalink: Configuration" href="#configuration"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Configure the plugin like so:</p>
  <div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
      "plugins": {
          "datasette-events-forward": {
              "api_token": "***",
              "api_url": "https://stats.datasette.cloud/data/-/create",
              "instance": "localhost"
          }
      }
  }"><pre>{
      <span class="pl-ent">"plugins"</span>: {
          <span class="pl-ent">"datasette-events-forward"</span>: {
              <span class="pl-ent">"api_token"</span>: <span class="pl-s"><span class="pl-pds">"</span>***<span class="pl-pds">"</span></span>,
              <span class="pl-ent">"api_url"</span>: <span class="pl-s"><span class="pl-pds">"</span>https://stats.datasette.cloud/data/-/create<span class="pl-pds">"</span></span>,
              <span class="pl-ent">"instance"</span>: <span class="pl-s"><span class="pl-pds">"</span>localhost<span class="pl-pds">"</span></span>
          }
      }
  }</pre></div>
  <p dir="auto">The plugin will then gather all events and forward them to the specified instance, adding them to a table called <code>datasette_events</code> which will be created if it does not exist.</p>
  <p dir="auto">The <code>instance</code> key can be used to differentiate different instances that report to the same backend. Events are identified with a ULID to ensure they are unique even across different instances.</p>
  <p dir="auto">Events are forwarded in batches of up to 10, no more than once every 10 seconds.</p>
  <p dir="auto">Full list of configuration settings:</p>
  <ul dir="auto">
  <li><code>api_url</code>: The write API URL of a Datasette instance to forward the events to.</li>
  <li><code>api_token</code>: The API token to use when sending events. Use <code>{"$env": "FORWARD_TOKEN"}</code> to read the token from the <code>FORWARD_TOKEN</code> environment variable.</li>
  <li><code>instance</code>: A string to identify the instance that is sending the events.</li>
  </ul>
  <p dir="auto">The <code>api_url</code> can be either a <code>https://datasette.example.com/data/datasette_events/-/insert</code> endpoint for inserting rows, or a <code>https://datasette.example.com/data/-/create</code> endpoint for creating a table and inserting rows into it. If the table does not yet exist you should use the <code>/-/create</code> variant, otherwise use the <code>/-/insert</code> variant.</p>
  <p dir="auto">If you use <code>/-/insert</code> your API token just needs <code>insert-row</code> permissions. For <code>/-/create</code> you will need <code>create-table</code> permissions as well.</p>
  <p dir="auto">And to control the rate at which batches of events are sent to the Datasette write API:</p>
  <ul dir="auto">
  <li><code>batch_limit</code>: The number of events to send in each batch, defaults to 10. The Datasette write API has a 100 row limit by default so this should be set to a value less than that.</li>
  <li><code>max_rate</code>: The maximum number of deliver HTTP requests to send in the specified time period, defaults to 1.</li>
  <li><code>time_period</code>: The time period for the rate limiting in seconds, defaults to 10.</li>
  </ul>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-events-forward
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-events-forward
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLZ-KRA
name: datasette-column-sum
full_name: datasette/datasette-column-sum
html_url: https://github.com/datasette/datasette-column-sum
description: Sum the values in numeric Datasette columns
created_at: 2024-02-29T22:44:02Z
updated_at: 2025-10-21T22:32:52Z
pushed_at: 2025-10-21T22:32:49Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
readme:
  # datasette-column-sum

  [![PyPI](https://img.shields.io/pypi/v/datasette-column-sum.svg)](https://pypi.org/project/datasette-column-sum/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-column-sum?include_prereleases&label=changelog)](https://github.com/datasette/datasette-column-sum/releases)
  [![Tests](https://github.com/datasette/datasette-column-sum/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-column-sum/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-column-sum/blob/main/LICENSE)

  Sum the values in numeric Datasette columns

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-column-sum
  ```
  ## Usage

  Numeric columns (float and integer) will have a new "Sum this column" menu item in their column action menu (accessible via the cog icon).

  Text columns get options to calculate sums for those numeric columns grouped by the text column.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-column-sum
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-column-sum</h1><a id="user-content-datasette-column-sum" class="anchor" aria-label="Permalink: datasette-column-sum" href="#datasette-column-sum"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-column-sum/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-column-sum.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/9a8e00d4ac8a38d74c38f9c6190bd05376e45589f2ebc6ce6ecfb7eedc2de802/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d636f6c756d6e2d73756d2e737667"></a>
  <a href="https://github.com/datasette/datasette-column-sum/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-column-sum?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/30d89eadf4da2ef37c42aad38af1957bd75c036dc6bc52f865cf3b80cdedcb90/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d636f6c756d6e2d73756d3f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-column-sum/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-column-sum/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-column-sum/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Sum the values in numeric Datasette columns</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-column-sum"><pre>datasette install datasette-column-sum</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Numeric columns (float and integer) will have a new "Sum this column" menu item in their column action menu (accessible via the cog icon).</p>
  <p dir="auto">Text columns get options to calculate sums for those numeric columns grouped by the text column.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-column-sum
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-column-sum
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLaT5Gw
name: datasette-tail
full_name: datasette/datasette-tail
html_url: https://github.com/datasette/datasette-tail
description: Tools for tailing your database
created_at: 2024-03-01T16:03:13Z
updated_at: 2025-11-04T01:32:42Z
pushed_at: 2025-11-04T01:34:02Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
readme:
  # datasette-tail

  [![PyPI](https://img.shields.io/pypi/v/datasette-tail.svg)](https://pypi.org/project/datasette-tail/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-tail?include_prereleases&label=changelog)](https://github.com/datasette/datasette-tail/releases)
  [![Tests](https://github.com/datasette/datasette-tail/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-tail/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-tail/blob/main/LICENSE)

  Tools for tailing your database

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-tail
  ```
  ## Usage

  This plugin provides a simple debugging tool. Visit `/dbname/-/tail` to see a JSON representation of changes to your database. The first time you visit that page it will represent everything in the specified database. Refreshing the page will show any changes since the last time you loaded that page.

  Use `/dbname/-/tail.json` to get the raw JSON.

  The plugin obeys the `view-database` permission.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-tail
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-tail</h1><a id="user-content-datasette-tail" class="anchor" aria-label="Permalink: datasette-tail" href="#datasette-tail"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-tail/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-tail.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/a751f82a26c7a5e98ae6035820d2a61555da03b818f281aa01625eda5cb54401/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d7461696c2e737667"></a>
  <a href="https://github.com/datasette/datasette-tail/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-tail?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/31133512376e0a793e2b237c40bb1d0bde444a7516fb2ebb53c24711589e336a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d7461696c3f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-tail/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-tail/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-tail/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Tools for tailing your database</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-tail"><pre>datasette install datasette-tail</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin provides a simple debugging tool. Visit <code>/dbname/-/tail</code> to see a JSON representation of changes to your database. The first time you visit that page it will represent everything in the specified database. Refreshing the page will show any changes since the last time you loaded that page.</p>
  <p dir="auto">Use <code>/dbname/-/tail.json</code> to get the raw JSON.</p>
  <p dir="auto">The plugin obeys the <code>view-database</code> permission.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-tail
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-tail
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLcU1eA
name: datasette-uptime
full_name: datasette/datasette-uptime
html_url: https://github.com/datasette/datasette-uptime
description: Datasette plugin showing uptime at /-/uptime
created_at: 2024-03-06T05:10:08Z
updated_at: 2024-06-19T21:57:49Z
pushed_at: 2024-03-06T05:19:17Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
readme:
  # datasette-uptime

  [![PyPI](https://img.shields.io/pypi/v/datasette-uptime.svg)](https://pypi.org/project/datasette-uptime/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-uptime?include_prereleases&label=changelog)](https://github.com/datasette/datasette-uptime/releases)
  [![Tests](https://github.com/datasette/datasette-uptime/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-uptime/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-uptime/blob/main/LICENSE)

  Datasette plugin showing uptime at /-/uptime

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-uptime
  ```
  ## Usage

  Adds an endpint at `/-/uptime` returning JSON that looks like this:
  ```json
  {
      "started": 355764.709263208,
      "now": 355824.192608208,
      "uptime_seconds": 59.483345208049286,
      "uptime_hours": 0.0165231515625136
  }
  ```
  This shows how long the server has been running.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-uptime
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-uptime</h1><a id="user-content-datasette-uptime" class="anchor" aria-label="Permalink: datasette-uptime" href="#datasette-uptime"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-uptime/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-uptime.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/9208b118b6ae62e4bea498a2420eb50713f759e4bfbcaf4a2d13dc9b4d16d67a/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d757074696d652e737667"></a>
  <a href="https://github.com/datasette/datasette-uptime/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-uptime?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/be41ba611b31e7706439d9ccdcba2b8e68e6880a08b703befba2d620dcda6111/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d757074696d653f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-uptime/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-uptime/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-uptime/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Datasette plugin showing uptime at /-/uptime</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-uptime"><pre>datasette install datasette-uptime</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Adds an endpint at <code>/-/uptime</code> returning JSON that looks like this:</p>
  <div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
      "started": 355764.709263208,
      "now": 355824.192608208,
      "uptime_seconds": 59.483345208049286,
      "uptime_hours": 0.0165231515625136
  }"><pre>{
      <span class="pl-ent">"started"</span>: <span class="pl-c1">355764.709263208</span>,
      <span class="pl-ent">"now"</span>: <span class="pl-c1">355824.192608208</span>,
      <span class="pl-ent">"uptime_seconds"</span>: <span class="pl-c1">59.483345208049286</span>,
      <span class="pl-ent">"uptime_hours"</span>: <span class="pl-c1">0.0165231515625136</span>
  }</pre></div>
  <p dir="auto">This shows how long the server has been running.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-uptime
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-uptime
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLc0adA
name: datasette-create-view
full_name: datasette/datasette-create-view
html_url: https://github.com/datasette/datasette-create-view
description: Create a SQL view from a query
created_at: 2024-03-07T03:22:29Z
updated_at: 2025-11-11T01:53:56Z
pushed_at: 2025-11-11T01:54:18Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
readme:
  # datasette-create-view

  [![PyPI](https://img.shields.io/pypi/v/datasette-create-view.svg)](https://pypi.org/project/datasette-create-view/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-create-view?include_prereleases&label=changelog)](https://github.com/datasette/datasette-create-view/releases)
  [![Tests](https://github.com/datasette/datasette-create-view/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-create-view/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-create-view/blob/main/LICENSE)

  Create a SQL view from a query

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-create-view
  ```
  This plugin requires [Datasette 1.0a12](https://docs.datasette.io/en/latest/changelog.html#a12-2024-02-29) or later.

  ## Usage

  Users with the `create-table` permission will get a new menu item on the query results page offering to save the query as a view.

  This option will only show for SQL queries that do not use `:named` parameters.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-create-view
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-create-view</h1><a id="user-content-datasette-create-view" class="anchor" aria-label="Permalink: datasette-create-view" href="#datasette-create-view"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-create-view/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-create-view.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/ed471c8cc15dabbc0da9dda1efcedd93fdd1505fdce1658b6893bb58b0a2985b/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d6372656174652d766965772e737667"></a>
  <a href="https://github.com/datasette/datasette-create-view/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-create-view?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/12200870da504c0dc274ffae9a664dee2f7a1405c6396a4c2b07b9f39df67e0b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d6372656174652d766965773f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-create-view/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-create-view/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-create-view/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Create a SQL view from a query</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-create-view"><pre>datasette install datasette-create-view</pre></div>
  <p dir="auto">This plugin requires <a href="https://docs.datasette.io/en/latest/changelog.html#a12-2024-02-29" rel="nofollow">Datasette 1.0a12</a> or later.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Users with the <code>create-table</code> permission will get a new menu item on the query results page offering to save the query as a view.</p>
  <p dir="auto">This option will only show for SQL queries that do not use <code>:named</code> parameters.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-create-view
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-create-view
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLd-PcQ
name: datasette-export-database
full_name: datasette/datasette-export-database
html_url: https://github.com/datasette/datasette-export-database
description: Export a copy of a mutable SQLite database on demand
created_at: 2024-03-09T15:53:50Z
updated_at: 2026-04-15T23:51:36Z
pushed_at: 2026-04-15T23:52:34Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
readme:
  # datasette-export-database

  [![PyPI](https://img.shields.io/pypi/v/datasette-export-database.svg)](https://pypi.org/project/datasette-export-database/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-export-database?include_prereleases&label=changelog)](https://github.com/datasette/datasette-export-database/releases)
  [![Tests](https://github.com/datasette/datasette-export-database/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-export-database/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-export-database/blob/main/LICENSE)

  Export a copy of a SQLite database on demand

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-export-database
  ```
  ## Usage

  Users with the `export-database` permission will be able to download a fresh snapshot of any on-disk (not in-memory) database using a new option in the database action menu.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-export-database
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-export-database</h1><a id="user-content-datasette-export-database" class="anchor" aria-label="Permalink: datasette-export-database" href="#datasette-export-database"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-export-database/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-export-database.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/859396be7d93b5167b8ca36ce7a8861b40aac93c2cd3946d0dd04a78a878b7f1/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d6578706f72742d64617461626173652e737667"></a>
  <a href="https://github.com/datasette/datasette-export-database/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-export-database?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/3cd99e6bd12f61a9bdbaa4925de044cb31c3e56457752b18206eba547719b696/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d6578706f72742d64617461626173653f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-export-database/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-export-database/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-export-database/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Export a copy of a SQLite database on demand</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-export-database"><pre>datasette install datasette-export-database</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Users with the <code>export-database</code> permission will be able to download a fresh snapshot of any on-disk (not in-memory) database using a new option in the database action menu.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-export-database
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-export-database
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLk9FxA
name: datasette-embeddings
full_name: datasette/datasette-embeddings
html_url: https://github.com/datasette/datasette-embeddings
description: Store and query embedding vectors in Datasette tables
created_at: 2024-03-24T21:45:24Z
updated_at: 2024-04-22T13:41:14Z
pushed_at: 2024-11-15T21:29:24Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": true}
custom_properties: {}
template_repository:
[cell repeats an earlier one in this file: 6377 characters]

readme:
  # datasette-embeddings

  [![PyPI](https://img.shields.io/pypi/v/datasette-embeddings.svg)](https://pypi.org/project/datasette-embeddings/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-embeddings?include_prereleases&label=changelog)](https://github.com/datasette/datasette-embeddings/releases)
  [![Tests](https://github.com/datasette/datasette-embeddings/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-embeddings/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-embeddings/blob/main/LICENSE)

  Store and query embedding vectors in Datasette tables

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-embeddings
  ```
  ## Usage

  Adds an [enrichment](https://enrichments.datasette.io/) for calculating and storing OpenAI embedding vectors for content in a table.

  Users get to select the embedding model and the template (e.g. `{{ title }} {{ body }}`) for the columns they would like to embed.

  Embeddings are stored as binary values in columns in a new table called `_embeddings_NAME`, where `NAME` is the name of the original source table.

  The vectors are stored in columns that match the name of the embedding model, for example `emb_text_embedding_3_large_256` for the `text-embedding-3-large-256` model.

  If you do not configure an OpenAI API key users will be asked for one any time they run the enrichment.

  You can set an API key with plugin configuration like this:

  ```yaml
  plugins:
    datasette-embeddings:
      api_key:
        $env: OPENAI_API_KEY
  ```
  Then set the `OPENAI_API_KEY` environment variable before you start Datasette.

  This plugin adds a "Semantic search against this table" table action item for tables with embeddings, but only if the API key environment variable has been configured as the key is needed to calculate embeddings for the user's search query.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-embeddings
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```
  The tests use captured examples of embedding APIs. The easiest way to re-generate these is to do the following:

  - `rm -rf tests/cassettes` to remove the previous recordings
  - `export OPENAPI_API_KEY='...'` to set an OpenAI API key
  - `pytest --record-mode once` to recreate the cassettes

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-embeddings</h1><a id="user-content-datasette-embeddings" class="anchor" aria-label="Permalink: datasette-embeddings" href="#datasette-embeddings"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-embeddings/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-embeddings.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/8e6060e57719dd18935f9cd160c13acf64d1b8852a7672bc128d42d64e715c1d/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d656d62656464696e67732e737667"></a>
  <a href="https://github.com/datasette/datasette-embeddings/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-embeddings?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/98034d19f601790ec2b3211fb86ae50a4de0036d7e82131a014be6916e36069e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d656d62656464696e67733f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-embeddings/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-embeddings/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-embeddings/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Store and query embedding vectors in Datasette tables</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-embeddings"><pre>datasette install datasette-embeddings</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Adds an <a href="https://enrichments.datasette.io/" rel="nofollow">enrichment</a> for calculating and storing OpenAI embedding vectors for content in a table.</p>
  <p dir="auto">Users get to select the embedding model and the template (e.g. <code>{{ title }} {{ body }}</code>) for the columns they would like to embed.</p>
  <p dir="auto">Embeddings are stored as binary values in columns in a new table called <code>_embeddings_NAME</code>, where <code>NAME</code> is the name of the original source table.</p>
  <p dir="auto">The vectors are stored in columns that match the name of the embedding model, for example <code>emb_text_embedding_3_large_256</code> for the <code>text-embedding-3-large-256</code> model.</p>
  <p dir="auto">If you do not configure an OpenAI API key users will be asked for one any time they run the enrichment.</p>
  <p dir="auto">You can set an API key with plugin configuration like this:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plugins:
    datasette-embeddings:
      api_key:
        $env: OPENAI_API_KEY"><pre><span class="pl-ent">plugins</span>:
    <span class="pl-ent">datasette-embeddings</span>:
      <span class="pl-ent">api_key</span>:
        <span class="pl-ent">$env</span>: <span class="pl-s">OPENAI_API_KEY</span></pre></div>
  <p dir="auto">Then set the <code>OPENAI_API_KEY</code> environment variable before you start Datasette.</p>
  <p dir="auto">This plugin adds a "Semantic search against this table" table action item for tables with embeddings, but only if the API key environment variable has been configured as the key is needed to calculate embeddings for the user's search query.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-embeddings
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-embeddings
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  <p dir="auto">The tests use captured examples of embedding APIs. The easiest way to re-generate these is to do the following:</p>
  <ul dir="auto">
  <li><code>rm -rf tests/cassettes</code> to remove the previous recordings</li>
  <li><code>export OPENAPI_API_KEY='...'</code> to set an OpenAI API key</li>
  <li><code>pytest --record-mode once</code> to recreate the cassettes</li>
  </ul>
  </article></div>


node_id: R_kgDOLl8JfA
name: datasette-query-assistant
full_name: datasette/datasette-query-assistant
html_url: https://github.com/datasette/datasette-query-assistant
description: Query databases and tables with AI assistance
created_at: 2024-03-26T21:23:42Z
updated_at: 2026-03-31T21:33:27Z
pushed_at: 2026-03-31T21:54:34Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
readme:
  # datasette-query-assistant

  [![PyPI](https://img.shields.io/pypi/v/datasette-query-assistant.svg)](https://pypi.org/project/datasette-query-assistant/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-query-assistant?include_prereleases&label=changelog)](https://github.com/datasette/datasette-query-assistant/releases)
  [![Tests](https://github.com/datasette/datasette-query-assistant/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-query-assistant/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-query-assistant/blob/main/LICENSE)

  Query databases and tables with AI assistance

  **Early alpha**.

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-query-assistant
  ```

  ## Configuration

  Set the model ID to be used by this plugin by adding this to your Datasette configuration:

  ```yaml
  plugins:
    datasette-query-assistant:
      model: openai/gpt-4.1-mini
      key_env_var: OPENAI_API_KEY
  ```
  To use the `openai/gpt-4.1-mini` model you'll need to install `llm-openai-plugin` in addition to `datasette-query-assistant`.

  If the model needs an API key, set the `key_env_var` to the name of an environment variable and ensure that environment variable is correctly set.

  You can use any model that is available via an [LLM plugin](https://llm.datasette.io/en/stable/plugins/directory.html)

  ## Usage

  Users with `execute-sql` permission will gain a database action menu item for "Query this database with AI assistance" which will let them ask a question and be redirected to a commented SQL query that will hopefully answer it.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-query-assistant
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```
  To re-generate the tests with refreshed examples from the API:
  ```bash
  pytest -x --record-mode=rewrite --inline-snapshot=fix
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-query-assistant</h1><a id="user-content-datasette-query-assistant" class="anchor" aria-label="Permalink: datasette-query-assistant" href="#datasette-query-assistant"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-query-assistant/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-query-assistant.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/0956ff5e1308d0bfef3b135e69e0d8cf7a71bbfc0097be5853370912b1ea1436/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d71756572792d617373697374616e742e737667"></a>
  <a href="https://github.com/datasette/datasette-query-assistant/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-query-assistant?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/cfd1d657100ae43b80c5d2562c912eec9c05aea5567ca618b97016eb4cbb55a0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d71756572792d617373697374616e743f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-query-assistant/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-query-assistant/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-query-assistant/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Query databases and tables with AI assistance</p>
  <p dir="auto"><strong>Early alpha</strong>.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-query-assistant"><pre>datasette install datasette-query-assistant</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Configuration</h2><a id="user-content-configuration" class="anchor" aria-label="Permalink: Configuration" href="#configuration"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Set the model ID to be used by this plugin by adding this to your Datasette configuration:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plugins:
    datasette-query-assistant:
      model: openai/gpt-4.1-mini
      key_env_var: OPENAI_API_KEY"><pre><span class="pl-ent">plugins</span>:
    <span class="pl-ent">datasette-query-assistant</span>:
      <span class="pl-ent">model</span>: <span class="pl-s">openai/gpt-4.1-mini</span>
      <span class="pl-ent">key_env_var</span>: <span class="pl-s">OPENAI_API_KEY</span></pre></div>
  <p dir="auto">To use the <code>openai/gpt-4.1-mini</code> model you'll need to install <code>llm-openai-plugin</code> in addition to <code>datasette-query-assistant</code>.</p>
  <p dir="auto">If the model needs an API key, set the <code>key_env_var</code> to the name of an environment variable and ensure that environment variable is correctly set.</p>
  <p dir="auto">You can use any model that is available via an <a href="https://llm.datasette.io/en/stable/plugins/directory.html" rel="nofollow">LLM plugin</a></p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Users with <code>execute-sql</code> permission will gain a database action menu item for "Query this database with AI assistance" which will let them ask a question and be redirected to a commented SQL query that will hopefully answer it.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-query-assistant
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-query-assistant
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  <p dir="auto">To re-generate the tests with refreshed examples from the API:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest -x --record-mode=rewrite --inline-snapshot=fix"><pre>pytest -x --record-mode=rewrite --inline-snapshot=fix</pre></div>
  </article></div>


node_id: R_kgDOLqtkrQ
name: datasette-import
full_name: datasette/datasette-import
html_url: https://github.com/datasette/datasette-import
description: Tools for importing data into Datasette
created_at: 2024-04-06T15:57:38Z
updated_at: 2025-10-21T20:46:11Z
pushed_at: 2025-10-21T20:46:08Z
language: HTML
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
template_repository:
  {"id": 400878073, "node_id": "MDEwOlJlcG9zaXRvcnk0MDA4NzgwNzM=", "name": "datasette-plugin-template-repository", "full_name": "simonw/datasette-plugin-template-repository", "private": false, "owner": {"login": "simonw", "id": 9599, "node_id": "MDQ6VXNlcjk1OTk=", "avatar_url": "https://avatars.githubusercontent.com/u/9599?v=4", "gravatar_id": "", "url": "https://api.github.com/users/simonw", "html_url": "https://github.com/simonw", "followers_url": "https://api.github.com/users/simonw/followers", "following_url": "https://api.github.com/users/simonw/following{/other_user}", "gists_url": "https://api.github.com/users/simonw/gists{/gist_id}", "starred_url": "https://api.github.com/users/simonw/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/simonw/subscriptions", "organizations_url": "https://api.github.com/users/simonw/orgs", "repos_url": "https://api.github.com/users/simonw/repos", "events_url": "https://api.github.com/users/simonw/events{/privacy}", "received_events_url": "https://api.github.com/users/simonw/received_events", "type": "User", "user_view_type": "public", "site_admin": false}, "html_url": "https://github.com/simonw/datasette-plugin-template-repository", "description": "GitHub template repository for creating new Datasette plugins, using the simonw/datasette-plugin cookiecutter template", "fork": false, "url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository", "forks_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/forks", "keys_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/teams", "hooks_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/hooks", "issue_events_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues/events{/number}", "events_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/events", "assignees_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/assignees{/user}", "branches_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/branches{/branch}", "tags_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/tags", "blobs_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/refs{/sha}", "trees_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/statuses/{sha}", "languages_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/languages", "stargazers_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/stargazers", "contributors_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/contributors", "subscribers_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/subscribers", "subscription_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/subscription", "commits_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/commits{/sha}", "git_commits_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/commits{/sha}", "comments_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/comments{/number}", "issue_comment_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues/comments{/number}", "contents_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/contents/{+path}", "compare_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/merges", "archive_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/downloads", "issues_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues{/number}", "pulls_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/pulls{/number}", "milestones_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/milestones{/number}", "notifications_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/labels{/name}", "releases_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/releases{/id}", "deployments_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/deployments", "created_at": "2021-08-28T19:50:28Z", "updated_at": "2025-02-18T20:42:29Z", "pushed_at": "2025-02-18T20:42:25Z", "git_url": "git://github.com/simonw/datasette-plugin-template-repository.git", "ssh_url": "git@github.com:simonw/datasette-plugin-template-repository.git", "clone_url": "https://github.com/simonw/datasette-plugin-template-repository.git", "svn_url": "https://github.com/simonw/datasette-plugin-template-repository", "homepage": "", "size": 24, "stargazers_count": 24, "watchers_count": 24, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": false, "has_discussions": false, "forks_count": 0, "mirror_url": null, "archived": false, "disabled": false, "open_issues_count": 0, "license": null, "allow_forking": true, "is_template": true, "web_commit_signoff_required": false, "topics": [], "visibility": "public", "forks": 0, "open_issues": 0, "watchers": 24, "default_branch": "main", "permissions": {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}, "temp_clone_token": ""}

readme:
  # datasette-import

  [![PyPI](https://img.shields.io/pypi/v/datasette-import.svg)](https://pypi.org/project/datasette-import/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-import?include_prereleases&label=changelog)](https://github.com/datasette/datasette-import/releases)
  [![Tests](https://github.com/datasette/datasette-import/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-import/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-import/blob/main/LICENSE)

  Tools for importing data into Datasette

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-import
  ```
  ## Usage

  This plugin adds a database action item called "Create table with imported data".

  This action is available to users with the `create-table` permission.

  It links to a page that allows users to upload files or paste in CSV, TSV or JSON data, and then use that to create and populate a new table in Datasette.

  CSV and TSV data must have headers on the first row.

  JSON data must be an array of objects with the same keys, or a container object object where one of the keys is an array of objects.

  ## Credits

  The CSV and TSV parsing is performed using [Papa Parse](https://www.papaparse.com/), an MIT licensed JavaScript library that is bundled with this plugin.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-import
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-import</h1><a id="user-content-datasette-import" class="anchor" aria-label="Permalink: datasette-import" href="#datasette-import"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-import/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-import.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/8816d1f0daa8f51fc1f4906c9541a7c11e0624019a2db0de7d6c883c498b4e04/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d696d706f72742e737667"></a>
  <a href="https://github.com/datasette/datasette-import/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-import?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/db079fd0cdee06fa832d2810f633cbf54e2dd21950329b762fa18c9b744f70c0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d696d706f72743f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-import/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-import/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-import/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Tools for importing data into Datasette</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-import"><pre>datasette install datasette-import</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin adds a database action item called "Create table with imported data".</p>
  <p dir="auto">This action is available to users with the <code>create-table</code> permission.</p>
  <p dir="auto">It links to a page that allows users to upload files or paste in CSV, TSV or JSON data, and then use that to create and populate a new table in Datasette.</p>
  <p dir="auto">CSV and TSV data must have headers on the first row.</p>
  <p dir="auto">JSON data must be an array of objects with the same keys, or a container object object where one of the keys is an array of objects.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Credits</h2><a id="user-content-credits" class="anchor" aria-label="Permalink: Credits" href="#credits"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">The CSV and TSV parsing is performed using <a href="https://www.papaparse.com/" rel="nofollow">Papa Parse</a>, an MIT licensed JavaScript library that is bundled with this plugin.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-import
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-import
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOLxu_vQ
name: datasette-secrets
full_name: datasette/datasette-secrets
html_url: https://github.com/datasette/datasette-secrets
description: Manage secrets such as API keys for use with other Datasette plugins
created_at: 2024-04-22T18:03:04Z
updated_at: 2025-11-11T01:56:01Z
pushed_at: 2025-11-11T01:56:21Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
template_repository:
  {"id": 400878073, "node_id": "MDEwOlJlcG9zaXRvcnk0MDA4NzgwNzM=", "name": "datasette-plugin-template-repository", "full_name": "simonw/datasette-plugin-template-repository", "private": false, "owner": {"login": "simonw", "id": 9599, "node_id": "MDQ6VXNlcjk1OTk=", "avatar_url": "https://avatars.githubusercontent.com/u/9599?v=4", "gravatar_id": "", "url": "https://api.github.com/users/simonw", "html_url": "https://github.com/simonw", "followers_url": "https://api.github.com/users/simonw/followers", "following_url": "https://api.github.com/users/simonw/following{/other_user}", "gists_url": "https://api.github.com/users/simonw/gists{/gist_id}", "starred_url": "https://api.github.com/users/simonw/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/simonw/subscriptions", "organizations_url": "https://api.github.com/users/simonw/orgs", "repos_url": "https://api.github.com/users/simonw/repos", "events_url": "https://api.github.com/users/simonw/events{/privacy}", "received_events_url": "https://api.github.com/users/simonw/received_events", "type": "User", "user_view_type": "public", "site_admin": false}, "html_url": "https://github.com/simonw/datasette-plugin-template-repository", "description": "GitHub template repository for creating new Datasette plugins, using the simonw/datasette-plugin cookiecutter template", "fork": false, "url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository", "forks_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/forks", "keys_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/teams", "hooks_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/hooks", "issue_events_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues/events{/number}", "events_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/events", "assignees_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/assignees{/user}", "branches_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/branches{/branch}", "tags_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/tags", "blobs_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/refs{/sha}", "trees_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/statuses/{sha}", "languages_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/languages", "stargazers_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/stargazers", "contributors_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/contributors", "subscribers_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/subscribers", "subscription_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/subscription", "commits_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/commits{/sha}", "git_commits_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/git/commits{/sha}", "comments_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/comments{/number}", "issue_comment_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues/comments{/number}", "contents_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/contents/{+path}", "compare_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/merges", "archive_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/downloads", "issues_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/issues{/number}", "pulls_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/pulls{/number}", "milestones_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/milestones{/number}", "notifications_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/labels{/name}", "releases_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/releases{/id}", "deployments_url": "https://api.github.com/repos/simonw/datasette-plugin-template-repository/deployments", "created_at": "2021-08-28T19:50:28Z", "updated_at": "2026-03-03T05:49:18Z", "pushed_at": "2026-01-03T22:42:16Z", "git_url": "git://github.com/simonw/datasette-plugin-template-repository.git", "ssh_url": "git@github.com:simonw/datasette-plugin-template-repository.git", "clone_url": "https://github.com/simonw/datasette-plugin-template-repository.git", "svn_url": "https://github.com/simonw/datasette-plugin-template-repository", "homepage": "", "size": 27, "stargazers_count": 26, "watchers_count": 26, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": false, "has_discussions": false, "forks_count": 0, "mirror_url": null, "archived": false, "disabled": false, "open_issues_count": 0, "license": null, "allow_forking": true, "is_template": true, "web_commit_signoff_required": false, "has_pull_requests": true, "pull_request_creation_policy": "all", "topics": [], "visibility": "public", "forks": 0, "open_issues": 0, "watchers": 26, "default_branch": "main", "permissions": {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}, "temp_clone_token": ""}

readme:
  # datasette-secrets

  [![PyPI](https://img.shields.io/pypi/v/datasette-secrets.svg)](https://pypi.org/project/datasette-secrets/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-secrets?include_prereleases&label=changelog)](https://github.com/datasette/datasette-secrets/releases)
  [![Tests](https://github.com/datasette/datasette-secrets/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-secrets/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-secrets/blob/main/LICENSE)

  Manage secrets such as API keys for use with other Datasette plugins

  This plugin requires a **Datasette 1.0 alpha** release.

  Datasette plugins sometimes need access to secrets, such as API keys used to integrate with tools hosted outside of Datasette - things like geocoders or hosted AI language models.

  This plugin provides ways to configure those secrets:

  - Secrets can be configured using environment variables, such as `DATASETTE_SECRETS_OPENAI_API_KEY`
  - Secrets can be stored, encrypted, in a SQLite database table which administrator users can then update through the Datasette web interface

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-secrets
  ```
  ## Configuration

  First you will need to generate an encryption key for this plugin to use. Run this command:

  ```bash
  datasette secrets generate-encryption-key
  ```
  Store this secret somewhere secure. It will be used to both encrypt and decrypt secrets stored by this plugin - if you lose it you will not be able to recover your secrets.

  Configure the plugin with these these two plugin settings:

  ```yaml
  plugins:
    datasette-secrets:
      encryption-key:
        $env: DATASETTE_SECRETS_ENCRYPTION_KEY
      database: name_of_database
  ```
  The `encryption_key` setting should be set to the encryption key you generated earlier. You can store it in an environment variable if you prefer.

  `database` is the name of the database that the encrypted keys should be stored in. Omit this setting to use the internal database.

  ### Using the internal database

  While the secrets stored in the `datasette_secrets` table are encrypted, we still recommend hiding that table from view.

  One way to do that is to keep the table in Datasette's internal database, which is invisible to all users, even users who are logged in.

  By default, the internal database is an in-memory database that is reset when Datasette restarts. This is no good for persistent secret storage!

  Instead, you should switch Datasette to using an on-disk internal database. You can do this by starting Datasette with the `--internal` option:
  ```bash
  datasette data.db --internal internal.db
  ```
  Your secrets will be stored in the `datasette_secrets` table in that database file.

  ### Permissions

  Only users with the `manage-secrets` permission will have access to manage secrets through the Datasette web interface.

  You can grant that permission to the `root` user (or the user with an ID of your choice) by including this in your `datasette.yml` file:

  ```yaml
  permissions:
    manage-secrets:
      id: root
  ```
  Then start Datasette like this (with `--root` to get a URL to login as the root user):
  ```bash
  datasette data.db --internal internal.db -c datasette.yml --root
  ```
  Alternatively, use the `-s` option to set that setting without creating a configuration file:
  ```bash
  datasette data.db --internal internal.db \
    -s permissions.manage-secrets.id root \
    --root
  ```

  ## Usage

  users with the `manage-secrets` permission will see a new "Manage secrets" link in the Datasette navigation menu. This interface can also be accessed at `/-/secrets`.

  The page with the list of secrets will show the user who last updated each secret. This will use the [actors_from_ids()](https://docs.datasette.io/en/latest/plugin_hooks.html#actors-from-ids-datasette-actor-ids) mechanism, displaying the actor's `username` if available, otherwise the `name`, otherwise the `id`.

  ## For plugin authors

  Plugins can depend on this plugin if they want to implement secrets.

  `datasette-secrets` to the `dependencies` list in `pyproject.toml`.

  Then declare the name and description of any secrets you need using the `register_secrets()` plugin hook:

  ```python
  from datasette import hookimpl
  from datasette_secrets import Secret

  @hookimpl
  def register_secrets():
      return [
          Secret(
              name="OPENAI_API_KEY",
              description="An OpenAI API key"
          ),
      ]
  ```
  You can also provide optional `obtain_url` and `obtain_label` fields to link to a page where a user can obtain an API key:
  ```python
  @hookimpl
  def register_secrets():
      return [
          Secret(
              name="OPENAI_API_KEY",
              obtain_url="https://platform.openai.com/api-keys",
              obtain_label="Get an OpenAI API key"
          ),
      ]
  ```

  The hook can take an optional `datasette` argument. It can return a list or an `async def` function that, when awaited, returns a list.

  The list should consist of `Secret()` instances, each with a name and an optional description. The description can contain HTML.

  To obtain the current value of the secret, use the `await get_secret()` method:

  ```python
  from datasette_secrets import get_secret

  # Third argument is the actor_id, optional
  secret = await get_secret(datasette, "OPENAI_API_KEY", "root")
  ```
  If the Datasette administrator set a `DATASETTE_SECRETS_OPENAI_API_KEY` environment variable, that will be returned.

  Otherwise the encrypted value in the database table will be decrypted and returned - or `None` if there is no configured secret.

  The `last_used_at` column is updated every time a secret is accessed. The `last_used_by` column will be set to the actor ID passed to `get_secret()`, or `null` if no actor ID was passed.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-secrets
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-secrets</h1><a id="user-content-datasette-secrets" class="anchor" aria-label="Permalink: datasette-secrets" href="#datasette-secrets"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-secrets/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-secrets.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/bdbcad9f0848899cc13f4db003438d023df49d04339830dd0d8d633c3484435d/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d736563726574732e737667"></a>
  <a href="https://github.com/datasette/datasette-secrets/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-secrets?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/0c70f75f439624fa87033fa269239daaf440b5aef3f7875a61caf43fd7cb5dde/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d736563726574733f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-secrets/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-secrets/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-secrets/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Manage secrets such as API keys for use with other Datasette plugins</p>
  <p dir="auto">This plugin requires a <strong>Datasette 1.0 alpha</strong> release.</p>
  <p dir="auto">Datasette plugins sometimes need access to secrets, such as API keys used to integrate with tools hosted outside of Datasette - things like geocoders or hosted AI language models.</p>
  <p dir="auto">This plugin provides ways to configure those secrets:</p>
  <ul dir="auto">
  <li>Secrets can be configured using environment variables, such as <code>DATASETTE_SECRETS_OPENAI_API_KEY</code></li>
  <li>Secrets can be stored, encrypted, in a SQLite database table which administrator users can then update through the Datasette web interface</li>
  </ul>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-secrets"><pre>datasette install datasette-secrets</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Configuration</h2><a id="user-content-configuration" class="anchor" aria-label="Permalink: Configuration" href="#configuration"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">First you will need to generate an encryption key for this plugin to use. Run this command:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette secrets generate-encryption-key"><pre>datasette secrets generate-encryption-key</pre></div>
  <p dir="auto">Store this secret somewhere secure. It will be used to both encrypt and decrypt secrets stored by this plugin - if you lose it you will not be able to recover your secrets.</p>
  <p dir="auto">Configure the plugin with these these two plugin settings:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plugins:
    datasette-secrets:
      encryption-key:
        $env: DATASETTE_SECRETS_ENCRYPTION_KEY
      database: name_of_database"><pre><span class="pl-ent">plugins</span>:
    <span class="pl-ent">datasette-secrets</span>:
      <span class="pl-ent">encryption-key</span>:
        <span class="pl-ent">$env</span>: <span class="pl-s">DATASETTE_SECRETS_ENCRYPTION_KEY</span>
      <span class="pl-ent">database</span>: <span class="pl-s">name_of_database</span></pre></div>
  <p dir="auto">The <code>encryption_key</code> setting should be set to the encryption key you generated earlier. You can store it in an environment variable if you prefer.</p>
  <p dir="auto"><code>database</code> is the name of the database that the encrypted keys should be stored in. Omit this setting to use the internal database.</p>
  <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">Using the internal database</h3><a id="user-content-using-the-internal-database" class="anchor" aria-label="Permalink: Using the internal database" href="#using-the-internal-database"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">While the secrets stored in the <code>datasette_secrets</code> table are encrypted, we still recommend hiding that table from view.</p>
  <p dir="auto">One way to do that is to keep the table in Datasette's internal database, which is invisible to all users, even users who are logged in.</p>
  <p dir="auto">By default, the internal database is an in-memory database that is reset when Datasette restarts. This is no good for persistent secret storage!</p>
  <p dir="auto">Instead, you should switch Datasette to using an on-disk internal database. You can do this by starting Datasette with the <code>--internal</code> option:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette data.db --internal internal.db"><pre>datasette data.db --internal internal.db</pre></div>
  <p dir="auto">Your secrets will be stored in the <code>datasette_secrets</code> table in that database file.</p>
  <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">Permissions</h3><a id="user-content-permissions" class="anchor" aria-label="Permalink: Permissions" href="#permissions"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Only users with the <code>manage-secrets</code> permission will have access to manage secrets through the Datasette web interface.</p>
  <p dir="auto">You can grant that permission to the <code>root</code> user (or the user with an ID of your choice) by including this in your <code>datasette.yml</code> file:</p>
  <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="permissions:
    manage-secrets:
      id: root"><pre><span class="pl-ent">permissions</span>:
    <span class="pl-ent">manage-secrets</span>:
      <span class="pl-ent">id</span>: <span class="pl-s">root</span></pre></div>
  <p dir="auto">Then start Datasette like this (with <code>--root</code> to get a URL to login as the root user):</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette data.db --internal internal.db -c datasette.yml --root"><pre>datasette data.db --internal internal.db -c datasette.yml --root</pre></div>
  <p dir="auto">Alternatively, use the <code>-s</code> option to set that setting without creating a configuration file:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette data.db --internal internal.db \
    -s permissions.manage-secrets.id root \
    --root"><pre>datasette data.db --internal internal.db \
    -s permissions.manage-secrets.id root \
    --root</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">users with the <code>manage-secrets</code> permission will see a new "Manage secrets" link in the Datasette navigation menu. This interface can also be accessed at <code>/-/secrets</code>.</p>
  <p dir="auto">The page with the list of secrets will show the user who last updated each secret. This will use the <a href="https://docs.datasette.io/en/latest/plugin_hooks.html#actors-from-ids-datasette-actor-ids" rel="nofollow">actors_from_ids()</a> mechanism, displaying the actor's <code>username</code> if available, otherwise the <code>name</code>, otherwise the <code>id</code>.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">For plugin authors</h2><a id="user-content-for-plugin-authors" class="anchor" aria-label="Permalink: For plugin authors" href="#for-plugin-authors"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Plugins can depend on this plugin if they want to implement secrets.</p>
  <p dir="auto"><code>datasette-secrets</code> to the <code>dependencies</code> list in <code>pyproject.toml</code>.</p>
  <p dir="auto">Then declare the name and description of any secrets you need using the <code>register_secrets()</code> plugin hook:</p>
  <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from datasette import hookimpl
  from datasette_secrets import Secret

  @hookimpl
  def register_secrets():
      return [
          Secret(
              name="OPENAI_API_KEY",
              description="An OpenAI API key"
          ),
      ]"><pre><span class="pl-k">from</span> <span class="pl-s1">datasette</span> <span class="pl-k">import</span> <span class="pl-s1">hookimpl</span>
  <span class="pl-k">from</span> <span class="pl-s1">datasette_secrets</span> <span class="pl-k">import</span> <span class="pl-v">Secret</span>

  <span class="pl-en">@<span class="pl-s1">hookimpl</span></span>
  <span class="pl-k">def</span> <span class="pl-en">register_secrets</span>():
      <span class="pl-k">return</span> [
          <span class="pl-en">Secret</span>(
              <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s">"OPENAI_API_KEY"</span>,
              <span class="pl-s1">description</span><span class="pl-c1">=</span><span class="pl-s">"An OpenAI API key"</span>
          ),
      ]</pre></div>
  <p dir="auto">You can also provide optional <code>obtain_url</code> and <code>obtain_label</code> fields to link to a page where a user can obtain an API key:</p>
  <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@hookimpl
  def register_secrets():
      return [
          Secret(
              name="OPENAI_API_KEY",
              obtain_url="https://platform.openai.com/api-keys",
              obtain_label="Get an OpenAI API key"
          ),
      ]"><pre><span class="pl-en">@<span class="pl-s1">hookimpl</span></span>
  <span class="pl-k">def</span> <span class="pl-en">register_secrets</span>():
      <span class="pl-k">return</span> [
          <span class="pl-en">Secret</span>(
              <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s">"OPENAI_API_KEY"</span>,
              <span class="pl-s1">obtain_url</span><span class="pl-c1">=</span><span class="pl-s">"https://platform.openai.com/api-keys"</span>,
              <span class="pl-s1">obtain_label</span><span class="pl-c1">=</span><span class="pl-s">"Get an OpenAI API key"</span>
          ),
      ]</pre></div>
  <p dir="auto">The hook can take an optional <code>datasette</code> argument. It can return a list or an <code>async def</code> function that, when awaited, returns a list.</p>
  <p dir="auto">The list should consist of <code>Secret()</code> instances, each with a name and an optional description. The description can contain HTML.</p>
  <p dir="auto">To obtain the current value of the secret, use the <code>await get_secret()</code> method:</p>
  <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from datasette_secrets import get_secret

  # Third argument is the actor_id, optional
  secret = await get_secret(datasette, "OPENAI_API_KEY", "root")"><pre><span class="pl-k">from</span> <span class="pl-s1">datasette_secrets</span> <span class="pl-k">import</span> <span class="pl-s1">get_secret</span>

  <span class="pl-c"># Third argument is the actor_id, optional</span>
  <span class="pl-s1">secret</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">get_secret</span>(<span class="pl-s1">datasette</span>, <span class="pl-s">"OPENAI_API_KEY"</span>, <span class="pl-s">"root"</span>)</pre></div>
  <p dir="auto">If the Datasette administrator set a <code>DATASETTE_SECRETS_OPENAI_API_KEY</code> environment variable, that will be returned.</p>
  <p dir="auto">Otherwise the encrypted value in the database table will be decrypted and returned - or <code>None</code> if there is no configured secret.</p>
  <p dir="auto">The <code>last_used_at</code> column is updated every time a secret is accessed. The <code>last_used_by</code> column will be set to the actor ID passed to <code>get_secret()</code>, or <code>null</code> if no actor ID was passed.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-secrets
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-secrets
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


node_id: R_kgDOMkfZPg
name: datasette-checkbox
full_name: datasette/datasette-checkbox
html_url: https://github.com/datasette/datasette-checkbox
description: Add interactive checkboxes to columns in Datasette
created_at: 2024-08-16T20:08:22Z
updated_at: 2025-11-06T23:59:25Z
pushed_at: 2025-11-06T16:35:54Z
language: Python
license: apache-2.0
topics: []
visibility: public
default_branch: main
permissions: {"admin": false, "maintain": false, "push": false, "triage": false, "pull": false}
custom_properties: {}
pull_request_creation_policy: all
readme:
  # datasette-checkbox

  [![PyPI](https://img.shields.io/pypi/v/datasette-checkbox.svg)](https://pypi.org/project/datasette-checkbox/)
  [![Changelog](https://img.shields.io/github/v/release/datasette/datasette-checkbox?include_prereleases&label=changelog)](https://github.com/datasette/datasette-checkbox/releases)
  [![Tests](https://github.com/datasette/datasette-checkbox/actions/workflows/test.yml/badge.svg)](https://github.com/datasette/datasette-checkbox/actions/workflows/test.yml)
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/datasette/datasette-checkbox/blob/main/LICENSE)

  Add interactive checkboxes to columns in Datasette. Requires Datasette 1.0 alpha or higher.

  ![Animated demo showing checkboxes in columns for is_done, should_be_deleted and is_happy - checking the checkboxes shows an updated message next to each one which then fades away.](https://raw.githubusercontent.com/datasette/datasette-checkbox/main/datasette-checkbox.gif)

  ## Installation

  Install this plugin in the same environment as Datasette.
  ```bash
  datasette install datasette-checkbox
  ```
  ## Usage

  This plugin adds checkboxes to the table and row pages in Datasette for any column with a name that starts `is_*` or `should_*` or `has_*` and that is of type `integer`.

  Toggling those checkboxes updates the underlying column to a `1` or a `0`.

  The checkbox interface will only be shown for users who have `update-row` permission for the table.

  The easiest way to try this plugin is using the `--root` Datasette option:

  ```bash
  datasette data.db --root
  ```
  Or use the [Datasette permission system](https://docs.datasette.io/en/latest/authentication.html#permissions) to grant `update-row` to specific users.

  ## Development

  To set up this plugin locally, first checkout the code. Then create a new virtual environment:
  ```bash
  cd datasette-checkbox
  python3 -m venv venv
  source venv/bin/activate
  ```
  Now install the dependencies and test dependencies:
  ```bash
  pip install -e '.[test]'
  ```
  To run the tests:
  ```bash
  pytest
  ```

readme_html:
  <div id="readme" class="md" data-path="README.md"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">datasette-checkbox</h1><a id="user-content-datasette-checkbox" class="anchor" aria-label="Permalink: datasette-checkbox" href="#datasette-checkbox"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto"><a href="https://pypi.org/project/datasette-checkbox/" rel="nofollow"><img src="https://img.shields.io/pypi/v/datasette-checkbox.svg" alt="PyPI" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/a193dd7e97d84e42be195053e596ccb3b074cc42ca7e09f3707708ecdbe2ae58/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6461746173657474652d636865636b626f782e737667"></a>
  <a href="https://github.com/datasette/datasette-checkbox/releases"><img src="https://img.shields.io/github/v/release/datasette/datasette-checkbox?include_prereleases&label=changelog" alt="Changelog" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/7e58a574f78104eb97b1354c17a0df5ec58f0ccb131ba1eef8543b400cebad3e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6461746173657474652f6461746173657474652d636865636b626f783f696e636c7564655f70726572656c6561736573266c6162656c3d6368616e67656c6f67"></a>
  <a href="https://github.com/datasette/datasette-checkbox/actions/workflows/test.yml"><img src="https://github.com/datasette/datasette-checkbox/actions/workflows/test.yml/badge.svg" alt="Tests" style="max-width: 100%;"></a>
  <a href="https://github.com/datasette/datasette-checkbox/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" style="max-width: 100%;" data-camo-src="https://camo.githubusercontent.com/c355f200ea90fddaa407b6eaab303663a669248ea3ca7b1fcf77dbe04ff5f48c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d417061636865253230322e302d626c75652e737667"></a></p>
  <p dir="auto">Add interactive checkboxes to columns in Datasette. Requires Datasette 1.0 alpha or higher.</p>
  <p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/datasette/datasette-checkbox/main/datasette-checkbox.gif"><img src="https://raw.githubusercontent.com/datasette/datasette-checkbox/main/datasette-checkbox.gif" alt="Animated demo showing checkboxes in columns for is_done, should_be_deleted and is_happy - checking the checkboxes shows an updated message next to each one which then fades away." data-animated-image="" style="max-width: 100%;"></a></p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">Install this plugin in the same environment as Datasette.</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette install datasette-checkbox"><pre>datasette install datasette-checkbox</pre></div>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Usage</h2><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">This plugin adds checkboxes to the table and row pages in Datasette for any column with a name that starts <code>is_*</code> or <code>should_*</code> or <code>has_*</code> and that is of type <code>integer</code>.</p>
  <p dir="auto">Toggling those checkboxes updates the underlying column to a <code>1</code> or a <code>0</code>.</p>
  <p dir="auto">The checkbox interface will only be shown for users who have <code>update-row</code> permission for the table.</p>
  <p dir="auto">The easiest way to try this plugin is using the <code>--root</code> Datasette option:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="datasette data.db --root"><pre>datasette data.db --root</pre></div>
  <p dir="auto">Or use the <a href="https://docs.datasette.io/en/latest/authentication.html#permissions" rel="nofollow">Datasette permission system</a> to grant <code>update-row</code> to specific users.</p>
  <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">Development</h2><a id="user-content-development" class="anchor" aria-label="Permalink: Development" href="#development"><svg class="octicon octicon-link" viewbox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
  <p dir="auto">To set up this plugin locally, first checkout the code. Then create a new virtual environment:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd datasette-checkbox
  python3 -m venv venv
  source venv/bin/activate"><pre><span class="pl-c1">cd</span> datasette-checkbox
  python3 -m venv venv
  <span class="pl-c1">source</span> venv/bin/activate</pre></div>
  <p dir="auto">Now install the dependencies and test dependencies:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install -e '.[test]'"><pre>pip install -e <span class="pl-s"><span class="pl-pds">'</span>.[test]<span class="pl-pds">'</span></span></pre></div>
  <p dir="auto">To run the tests:</p>
  <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pytest"><pre>pytest</pre></div>
  </article></div>


