# issues

node_id: I_kwDOCGYnMM5RCelr
title: Idea: `sqlite-utils create-table tablename --sql "select ..."`
state: open
created_at: 2022-09-02T01:41:24Z
updated_at: 2022-09-02T01:42:08Z
author_association: OWNER
type: issue
body:
  Could offer syntactic sugar for:

  ```sql
  create table foo as select * from bar
  ```

  ```
  sqlite-utils create-table data.db foo --sql "select * from bar"
  ```
  https://sqlite-utils.datasette.io/en/stable/cli-reference.html#create-table

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/481/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5RJKMs
title: balanced table default column_order
state: closed
created_at: 2022-09-05T03:00:18Z
updated_at: 2022-10-10T17:43:02Z
closed_at: 2022-09-06T20:17:27Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  Is there any performance or size difference with column order in SQLITE ? similar to this https://www.cybertec-postgresql.com/en/column-order-in-postgresql-does-matter/

  It might be interesting to have an option to create with an optimized column order. I'm assuming this would look something like INTEGER columns, REAL columns, BLOB columns, TEXT columns, NULL columns. NULL columns at the end because they are more likely to be TEXT and it is impossible to know if they will become INTEGER

  (Of course, any schema evolution would reduce optimization but maybe column order could also be re-evaluated when schema changes)

  edit:

  this is easy to accomplish with the existing `transform` method:

  ```
  int_columns = [k for k, v in table_columns.items() if v == int]
  db[table].transform(column_order=[*int_columns])
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/482/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4-Yqgo
title: Update aiofiles requirement from <0.9,>=0.4 to >=0.4,<22.2
state: closed
created_at: 2022-09-05T16:13:48Z
updated_at: 2022-09-05T18:36:44Z
closed_at: 2022-09-05T18:36:43Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1799
type: pull
body:
  Updates the requirements on [aiofiles](https://github.com/Tinche/aiofiles) to permit the latest version.
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/Tinche/aiofiles/commit/9d697f5857b5e49bad485212d9d81917ce65b607"><code>9d697f5</code></a> 22.1.0</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/6a14491ff8fe7dd9788c62722f4f4bc7922d0c92"><code>6a14491</code></a> Update README</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/76f8934028d0cf490e180636f55eb381fa9343f9"><code>76f8934</code></a> Update test deps</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/885df353c199dd86d64424663880f0972b0c3943"><code>885df35</code></a> Min Python to 3.7</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/a93206be5bbc12c68a5bef753d40a8af449fa934"><code>a93206b</code></a> Bump poetry to 1.2.0</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/d2eda6120a813a6bd1014bd676abade70928c641"><code>d2eda61</code></a> Add missing comma</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/b02cf6a33872598cae3e587d233ad5404d7c7fb0"><code>b02cf6a</code></a> CI tweaks</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/7636eff01f2de6e2d3f94ea234eaf27380b33080"><code>7636eff</code></a> Update README.rst</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/9bc662aab0f735d06c54c69938ff3a828d8f91d8"><code>9bc662a</code></a> Added os scantdir with is't tests and improved the tests for listdir</li>
  <li><a href="https://github.com/Tinche/aiofiles/commit/2aefa1e4df8356604b5692fda45877b8a401e0df"><code>2aefa1e</code></a> Added os listdir function with it's tests</li>
  <li>Additional commits viewable in <a href="https://github.com/Tinche/aiofiles/compare/v0.4.0...v22.1.0">compare view</a></li>
  </ul>
  </details>
  <br />


  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1799.org.readthedocs.build/en/1799/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1799/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5RNAUl
title: Remove upper bound dependencies as a default policy
state: closed
created_at: 2022-09-05T18:23:45Z
updated_at: 2022-09-05T18:39:52Z
closed_at: 2022-09-05T18:35:41Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://iscinumpy.dev/post/bound-version-constraints/ has convinced me not to use upper bound dependencies unless I'm certain they are needed.

  Relevant PR:
  - https://github.com/simonw/datasette/pull/1799

  Also:

  https://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L45-L46

  https://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L48-L49

  https://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L51-L55

  https://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L57-L59

  https://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L75-L78

  https://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L81-L82

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1800/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4-ZGW6
title: Don't use upper bound dependencies, refs #1800
state: closed
created_at: 2022-09-05T18:29:28Z
updated_at: 2022-09-05T18:35:41Z
closed_at: 2022-09-05T18:35:41Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1801
type: pull
body:
  See https://iscinumpy.dev/post/bound-version-constraints/

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1801.org.readthedocs.build/en/1801/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1801/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5RNJ62
title: Tests reliably failing on Python 3.7
state: closed
created_at: 2022-09-05T19:21:16Z
updated_at: 2022-09-06T00:40:20Z
closed_at: 2022-09-06T00:40:20Z
author_association: OWNER
type: issue
state_reason: completed
body:
  <img width="819" alt="image" src="https://user-images.githubusercontent.com/9599/188504608-5be0f941-dca2-4f42-83bc-3d04bbad221d.png">

  https://github.com/simonw/datasette/runs/8194907739?check_suite_focus=true

  I thought this might be an intermittent failure but attempts to re-run the tests have not made it pass.

  End of that trace is:

  ```
  /home/runner/work/datasette/datasette/datasette/app.py:234: in __init__
      self._refresh_schemas_lock = asyncio.Lock()
  /opt/hostedtoolcache/Python/3.7.13/x64/lib/python3.7/asyncio/locks.py:161: in __init__
      self._loop = events.get_event_loop()
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

  self = <asyncio.unix_events._UnixDefaultEventLoopPolicy object at 0x7fb1fc799fd0>

      def get_event_loop(self):
          """Get the event loop for the current context.
      
          Returns an instance of EventLoop or raises an exception.
          """
          if (self._local._loop is None and
                  not self._local._set_called and
                  isinstance(threading.current_thread(), threading._MainThread)):
              self.set_event_loop(self.new_event_loop())
      
          if self._local._loop is None:
              raise RuntimeError('There is no current event loop in thread %r.'
  >                              % threading.current_thread().name)
  E           RuntimeError: There is no current event loop in thread 'MainThread'.
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1802/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4-ZxWD
title: Workaround for test failure: RuntimeError: There is no current event loop
state: closed
created_at: 2022-09-06T00:31:06Z
updated_at: 2022-09-06T00:40:19Z
closed_at: 2022-09-06T00:40:19Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1803
type: pull
body:
  Closes #1802

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1803.org.readthedocs.build/en/1803/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1803/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODFdgUs5RQXSn
title: Fetch repos doesn't support organisations
state: open
created_at: 2022-09-06T12:55:06Z
updated_at: 2022-09-06T12:55:06Z
author_association: NONE
type: issue
body:
  Say I want to get all my Github Org's repos info, for data analysis. Not just the public repos, but also the private/internal repos.

  The endpoints are different for organisation, and this tool doesn't take it into account:
  https://github.com/dogsheep/github-to-sqlite/blob/ace13ec3d98090d99bd71871c286a4a612c96a50/github_to_sqlite/utils.py#L453
  https://github.com/dogsheep/github-to-sqlite/blob/ace13ec3d98090d99bd71871c286a4a612c96a50/github_to_sqlite/utils.py#L455

  The endpoints for organisation repos is instead ([source](https://docs.github.com/en/rest/repos/repos#list-organization-repositories)):
  `url = "https://api.github.com/orgs/{}/repos".format(username)`

  Let's add support for organisations repo scraping.

reactions:
  {"url": "https://api.github.com/repos/dogsheep/github-to-sqlite/issues/75/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODFdgUs4-cIa_
title: Add organization support to repos command
state: open
created_at: 2022-09-06T13:21:42Z
updated_at: 2022-09-06T13:59:08Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/github-to-sqlite/pulls/76
type: pull
body:
  New --organization flag to signify all given "usernames" are private
  orgs. Adapts API URL to the organization path instead.

  Not the best implementation, but a first draft to talk around

  Fixes #75 (badly, no tests, overly vague, untested)

reactions:
  {"url": "https://api.github.com/repos/dogsheep/github-to-sqlite/issues/76/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5RRHVn
title: Ability to set a custom facet_size per table
state: closed
created_at: 2022-09-06T15:11:40Z
updated_at: 2022-09-07T00:21:56Z
closed_at: 2022-09-06T18:06:53Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Suggestion from Discord: https://discord.com/channels/823971286308356157/823971286941302908/1016725586351247430

  > Is it possible to limit the facet size per database or even per table?

  This is a really good idea, it could be done in `metadata.yml`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1804/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5RRioM
title: truncate_cells_html does not work for links?
state: open
created_at: 2022-09-06T16:41:29Z
updated_at: 2022-10-03T09:18:06Z
author_association: NONE
type: issue
state_reason: reopened
body:
  We have many links inside our dataset (please don't blame us ;-).

  When I use `--settings truncate_cells_html 60` it is not working for the links.

  Eg. https://images.openfoodfacts.org/images/products/000/000/000/088/nutrition_fr.5.200.jpg (87 chars) is not truncated:
  ![image](https://user-images.githubusercontent.com/562352/188689045-1946d776-2305-47cf-bfc5-b5685b9206b7.png)

  IMHO It would make sense that links should be treated as HTML. The link should work of course, but Datasette could truncate it:
  [https://images.openfoodfacts.org/images/products/00[...].jpg](https://images.openfoodfacts.org/images/products/000/000/000/088/nutrition_fr.5.200.jpg)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1805/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5RSWqc
title: `sqlite-utils install` command
state: closed
created_at: 2022-09-06T20:13:55Z
updated_at: 2022-09-26T19:04:43Z
closed_at: 2022-09-26T18:57:15Z
author_association: OWNER
type: issue
state_reason: completed
body:
  With the addition of `--functions` in:
  - #471

  In addition to the existing `convert` command, there are now very good reasons to want to install additional packages into the same virtual environment as `sqlite-utils` itself, to allow them to be used with those features.

  This isn't easy if you installed the tool with `pipx` or `brew install sqlite-utils`.

  Datasette solved this problem with the `datasette install` command:

  - https://github.com/simonw/datasette/issues/925

  `sqlite-utils` could benefit from the same idea.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/483/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5RSW69
title: Expose convert recipes to `sqlite-utils --functions`
state: open
created_at: 2022-09-06T20:15:08Z
updated_at: 2022-09-07T19:09:52Z
author_association: OWNER
type: issue
body:
  `--functions` was added in:
  - #471 

  It would be useful if the `r.jsonsplit()` and similar recipes for `sqlite-utils convert` could be used in these blocks of code too: https://sqlite-utils.datasette.io/en/stable/cli.html#sqlite-utils-convert-recipes

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/484/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5RZ4-o
title: UX to recover from Error 500: "You can only execute one statement at a time."
state: open
created_at: 2022-09-08T08:01:27Z
updated_at: 2022-09-08T08:01:37Z
author_association: NONE
type: issue
body:
  When using the Custom SQL query view, when accidentally adding a semicolon in the middle of my query, datasette errors with: 

  > # Error 500
  > You can only execute one statement at a time.

  The error view doesn't contain the query textarea anymore, so it provides no easy way recover from the error. It would be nice if I could change and submit it again.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1806/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5RcfaI
title: Progressbar not shown when inserting/upserting jsonlines file
state: closed
created_at: 2022-09-08T14:13:18Z
updated_at: 2022-09-15T20:39:52Z
closed_at: 2022-09-15T20:37:52Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  When inserting or upserting a jsonlines file, no progressbar is shown. Expected behavior is that, just like with .csv/.tsv files, also for a jsonlines file (--nl), unless --silent is provided, a progressbar is shown.

  ```bash
  sql-utils upsert mydb.db posts posts.jl --nl --pk post_id
  (silence)
  ```

  Currently `file_progress` is only called within the tsv/csv logic, however I think it can be safely wrapped around all the all the input formats that use `decoded`: https://github.com/simonw/sqlite-utils/blob/main/sqlite_utils/cli.py#L963

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/485/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOCGYnMM4-nBs9
title: progressbar for inserts/upserts of all fileformats, closes #485
state: closed
created_at: 2022-09-08T14:58:02Z
updated_at: 2022-09-15T20:40:03Z
closed_at: 2022-09-15T20:37:51Z
author_association: CONTRIBUTOR
pull_request: simonw/sqlite-utils/pulls/486
type: pull
body:
  <!-- readthedocs-preview sqlite-utils start -->
  ----
  :books: Documentation preview :books:: https://sqlite-utils--486.org.readthedocs.build/en/486/

  <!-- readthedocs-preview sqlite-utils end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/486/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ReXio
title: Plugin ecosystem needs to avoid crashes due to no available databases
state: open
created_at: 2022-09-08T19:54:34Z
updated_at: 2022-09-08T20:14:05Z
author_association: OWNER
type: issue
body:
  Opening this here to track the issue first reported in:
  - https://github.com/simonw/datasette-upload-dbs/issues/5

  Plugins that expect to be able to write to a database need to not crash in situations where no writable database is available.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1807/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5Rh4L0
title: Specify foreign key against compound key in other table
state: closed
created_at: 2022-09-09T13:32:09Z
updated_at: 2022-09-11T04:00:44Z
closed_at: 2022-09-11T04:00:44Z
author_association: NONE
type: issue
state_reason: completed
body:
  When inserting rows via the library, is it possible to specify a foreign key to a compound primary key?

  For example, suppose I create a table:
  ```
  db = Database('events.db')
  db['events'].insert_all([
      {'venue': 'Times Square', 'date': '2022-12-31', 'title': 'Rockin New Year Eve'},
      {'venue': 'Wembley Stadium', 'date': '2022-06-05', 'title': 'FA Cup'},
      {'venue': 'Times Square', 'date': '2021-12-31', 'title': 'Rockin New Year Eve'},
  ], pk=('date', 'venue'))
  ```

  And I want to add related data in another table:
  ```
  act = {'name': 'Rick Astley', 'venue': 'Times Square', 'date': '2021-12-31' }
  db['performers'].insert(act, pk=<???>)
  ```

  Is it possible to specify a value for `pk` that will point to the compound primary key in `events`?

  SQLite does support it:
  https://www.sqlite.org/foreignkeys.html#fk_composite

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/487/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Rin7o
title: Database() constructor currently defaults is_mutable to False
state: closed
created_at: 2022-09-09T16:02:41Z
updated_at: 2022-09-09T16:37:57Z
closed_at: 2022-09-09T16:19:25Z
author_association: OWNER
type: issue
state_reason: completed
body:
  This is surprising. It caused a bug in `datasette-upload-dbs` because I didn't expect it to do that.

  > I think this is an API design flaw in Datasette itself, but I can fix it here first.

  _Originally posted by @simonw in https://github.com/simonw/datasette-upload-dbs/issues/6#issuecomment-1242150394_

  Code in question: https://github.com/simonw/datasette/blob/bf8d84af5422606597be893cedd375020cb2b369/datasette/database.py#L29-L32

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1808/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODD6af85R2Ygz
title: fails before generating views. ERR: table sqlite_master may not be modified
state: open
created_at: 2022-09-14T15:41:50Z
updated_at: 2023-04-11T03:46:17Z
author_association: NONE
type: issue
body:
  generates checkins.db but seems to fail before generating views 

  note: it worked on an Ubuntu WSL but fails on macOS 12.5.1

  later edit: I suspect this is a problem with my local set-up, `dogsheep-beta index` also throws the same error

  full error:

      Importing 2591 checkins  [###################################-]   98%  00:00:00
      Traceback (most recent call last):
        File "/Users/pax/devbox/envAll/bin/swarm-to-sqlite", line 8, in <module>
          sys.exit(cli())
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/click/core.py", line 829, in __call__
          return self.main(*args, **kwargs)
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/click/core.py", line 782, in main
          rv = self.invoke(ctx)
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
          return ctx.invoke(self.callback, **ctx.params)
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/click/core.py", line 610, in invoke
          return callback(*args, **kwargs)
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/swarm_to_sqlite/cli.py", line 77, in cli
          ensure_foreign_keys(db)
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/swarm_to_sqlite/utils.py", line 145, in ensure_foreign_keys
          db[fk.table].add_foreign_key(fk.column, fk.other_table, fk.other_column)
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/sqlite_utils/db.py", line 2123, in add_foreign_key
          self.db.add_foreign_keys([(self.name, column, other_table, other_column)])
        File "/Users/pax/devbox/envAll/lib/python3.8/site-packages/sqlite_utils/db.py", line 1086, in add_foreign_keys
          cursor.execute(
      sqlite3.OperationalError: table sqlite_master may not be modified

reactions:
  {"url": "https://api.github.com/repos/dogsheep/swarm-to-sqlite/issues/13/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5R2b7R
state: open
created_at: 2022-09-14T15:51:30Z
updated_at: 2022-12-23T17:38:55Z
author_association: OWNER
type: issue
title:
  `sqlite-utils transform` should set empty strings to null when converting text columns to integer/float

body:
  ```
  /tmp % echo "id,age,weight\n1,3,2.5\n2,," | sqlite-utils insert test.db test - --csv
  /tmp % sqlite-utils schema test.db                                                  
  CREATE TABLE [test] (
     [id] TEXT,
     [age] TEXT,
     [weight] TEXT
  );
  /tmp % sqlite-utils transform test.db test --type age integer --type weight float   
  /tmp % sqlite-utils schema test.db                                               
  CREATE TABLE "test" (
     [id] TEXT,
     [age] INTEGER,
     [weight] FLOAT
  );
  /tmp % sqlite-utils rows test.db test
  [{"id": "1", "age": 3, "weight": 2.5},
   {"id": "2", "age": "", "weight": ""}]
  ```
  It would be neat if this resulted in the following instead:
  ```
   {"id": "2", "age": null, "weight": null}
  ```
  Related Discord discussion: https://discord.com/channels/823971286308356157/823971286941302908/1019635490833567794

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/488/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5R32kX
title: `prepare_jinja2_environment()` hook should take `datasette` argument
state: closed
created_at: 2022-09-14T21:15:46Z
updated_at: 2022-09-17T03:39:05Z
closed_at: 2022-09-17T03:38:33Z
author_association: OWNER
type: issue
state_reason: completed
body:
  That plugin hook's current signature is:

  https://github.com/simonw/datasette/blob/610425460b519e9c16d386cb81aa081c9d730ef0/datasette/hookspecs.py#L28-L30

  As a result in the first alpha release of `datasette-edit-templates` I had to include this horrific hack: https://github.com/simonw/datasette-edit-templates/blob/087f6a6cabc20020f2b0524f11aa3a7836320848/datasette_edit_templates/__init__.py#L72-L75

  ```python
  @hookimpl
  def prepare_jinja2_environment(env):
      # TODO: This should ideally take datasette, but that's not an argument yet
      datasette = inspect.currentframe().f_back.f_back.f_back.f_back.f_locals["self"]
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1809/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5R7yQ5
title: Featured table(s) on the homepage
state: open
created_at: 2022-09-15T14:30:49Z
updated_at: 2022-09-15T15:51:25Z
author_association: OWNER
type: issue
body:
  Many Datasette instances mainly exist to serve a single table - for example:

  - https://global-power-plants.datasettes.com/global-power-plants/global-power-plants
  - https://laion-aesthetic.datasette.io/laion-aesthetic-6pls/images

  It would be neat if the / homepage of those instances could be configured to highlight that specific table.

  Or maybe more than one?

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1810/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5R8-lH
title: Ability to load JSON records held in a file with a single top level key that is a list of objects
state: open
created_at: 2022-09-15T18:46:03Z
updated_at: 2022-09-15T20:56:10Z
author_association: OWNER
type: issue
body:
  It's very common for JSON to look like this:
  ```json
  {
    "Version": "5.5.52.6",
    "List": [
      {
        "Description": "Nonpartisan",
        "Id": 1,
        "ExternalId": ""
      },
      {
        "Description": "Undeclared",
        "Id": 2,
        "ExternalId": ""
      }
    ]
  }
  ```
  This example taken from the records downloaded from https://www.elections.alaska.gov/election-results/e/

  Right now you can't import this into `sqlite-utils` - you need to run it through `jq .List` first.

  But since this is so common, it would be neat if `sqlite-utils` could have a rule of thumb that says "if it's an object, but it has a single key that is is a list of objects, use that instead".

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/489/reactions", "total_count": 2, "+1": 2, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SAO7s
title: Drop-down menu with "REGEXP" choice
state: open
created_at: 2022-09-16T11:06:18Z
updated_at: 2022-09-16T15:30:31Z
author_association: NONE
type: issue
body:
  Drop-down menu below could add "REGEXP" choice when REGEXP sqlite extension is installed and used
  ![image](https://user-images.githubusercontent.com/562352/190675352-810fbdca-0827-4034-8b9f-fd67d5c35afb.png)

  Not sure. Close the issue if you don't find it relevant.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1811/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4_GVBS
title: Bump furo from 2022.6.21 to 2022.9.15
state: closed
created_at: 2022-09-16T13:10:45Z
updated_at: 2022-09-16T19:50:53Z
closed_at: 2022-09-16T19:50:52Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1812
type: pull
body:
  Bumps [furo](https://github.com/pradyunsg/furo) from 2022.6.21 to 2022.9.15.
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/pradyunsg/furo/blob/main/docs/changelog.md">furo's changelog</a>.</em></p>
  <blockquote>
  <h1>Changelog</h1>
  <!-- raw HTML omitted -->
  <h2>2022.09.15 -- Pragmatic Pistachio</h2>
  <ul>
  <li>Add a minimum version constraint on pygments.</li>
  <li>Add an explicit dependency on <code>sass</code>.</li>
  <li>Change right sidebar title from &quot;Contents&quot; to &quot;On this page&quot;.</li>
  <li>Correctly position sidebars on small screens.</li>
  <li>Correctly select only Furo's own <code>svg</code> in related pages <code>nav</code>.</li>
  <li>Make numpy-style documentation headers consistent.</li>
  <li>Retitle the reference section.</li>
  <li>Update npm dependencies.</li>
  </ul>
  <h2>2022.06.21 -- Opulent Opal</h2>
  <ul>
  <li>Fix <code>docutils &lt;= 0.17.x</code> compatibility.</li>
  <li>Bump to the latest Node.js LTS.</li>
  </ul>
  <h2>2022.06.04.1 -- Naughty Nickel bugfix</h2>
  <ul>
  <li>Fix the URL used in the &quot;Edit this page&quot; for Read the Docs builds.</li>
  </ul>
  <h2>2022.06.04 -- Naughty Nickel</h2>
  <ul>
  <li>✨ Advertise Sphinx 5 compatibility.</li>
  <li>✨ Change to <code>basic-ng</code> as the base theme (from {pypi}<code>sphinx-basic-ng</code>).</li>
  <li>Document site-wide announcement banners.</li>
  <li>Drop the pin on pygments.</li>
  <li>Improve edit button, using <code>basic-ng</code>'s <code>edit-this-page</code> component.</li>
  <li>Tweak headings to better match what users expect.</li>
  <li>Tweak how Sphinx's default HTML is rendered, using docutils post-transforms (this replaces parsing+modifying it with BeautifulSoup).</li>
  <li>When built with docutils 0.18, footnotes are rendered differently and stylised differently in Furo.</li>
  </ul>
  <h2>2022.04.07 -- Magical Mauve</h2>
  <ul>
  <li>✨ Make sphinx-copybutton look better.</li>
  <li>Add margin to indentations in line blocks.</li>
  <li>Add styling for non-arabic list styles</li>
  <li>Add support for <code>html_baseurl</code>.</li>
  </ul>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/pradyunsg/furo/commit/08e6b3844a35bd04faf8aa9eda41f94be7aefe9f"><code>08e6b38</code></a> Prepare release: 2022.09.15</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/9de7613b7138450915ad9ec0e010d3640fae292c"><code>9de7613</code></a> Update changelog</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/a06492959d6c794eefa05eff63d2c5cd75f87bf9"><code>a064929</code></a> Tweak changelog content style</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/46f4adc02bd0a7e9e7d59f650dce42efeff919da"><code>46f4adc</code></a> Revert &quot;Add initial theme.conf content for eventual ablog support&quot;</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/45b839b7426b55dbd934741de1cd2679d7389954"><code>45b839b</code></a> Set a minimum constraint on pygments</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/a4af9889811ad392fea28b97a3d70fc2c9eeb621"><code>a4af988</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/518">#518</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/a72186fbfb7f1dc35cb9a46b874cb5e61116b52c"><code>a72186f</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/504">#504</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/9f41ee678d68ee11d91b98ffbdc4f79a9fb8b99b"><code>9f41ee6</code></a> Add initial theme.conf content for eventual ablog support</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/75e03616f38808b2bc0af0688cb30ba6c0928f41"><code>75e0361</code></a> Make numpy-style documentation headers consistent</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/9d280e6ce45e1a5df1a058d26894dd01d880460e"><code>9d280e6</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/487">#487</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/pradyunsg/furo/compare/2022.06.21...2022.09.15">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=furo&package-manager=pip&previous-version=2022.6.21&new-version=2022.9.15)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1812.org.readthedocs.build/en/1812/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1812/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SH72c
title: missing next and next_url in JSON responses from an instance deployed on Fly
state: closed
created_at: 2022-09-19T11:32:34Z
updated_at: 2022-09-19T11:34:45Z
closed_at: 2022-09-19T11:34:45Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  👋 thank you for an incredibly useful project! 

  I have noticed that my deployed instance on Fly does not include the `next` and `next_url` keys even for a truncated response :

  <img width="815" alt="Screenshot 2022-09-19 at 13 25 07" src="https://user-images.githubusercontent.com/883348/191007558-c0e9df03-7ee3-4e03-bd1c-26c608c3bdf9.png">
   

  This is publically accessible here: `https://collectif-objets-datasette.fly.dev/collectif-objets.json?sql=select+*+from+mairies`

  However when I run the dataset server locally with the same data I get these next keys for the exact same query:

  <img width="695" alt="Screenshot 2022-09-19 at 13 24 05" src="https://user-images.githubusercontent.com/883348/191007464-c3905896-cd6f-46c0-8d6a-0f1c0b4471ca.png">

  I am wondering if I've missed some config or something specific to deployments on Fly.io? 

  I am running datasette v0.62, without any specific config : 

  - locally `poetry run datasette data/collectif-objets.sqlite`
  - for the deploy : `poetry run datasette publish fly data/collectif-objets.sqlite`

  as visible in [the Makefile](https://github.com/adipasquale/collectif-objets-datasette/blob/main/Makefile). _The very limited codebase is public but the sqlite db is not versioned yet because it is too large._

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1813/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SKizK
title: Static files not served
state: closed
created_at: 2022-09-19T20:38:17Z
updated_at: 2022-09-19T23:35:06Z
closed_at: 2022-09-19T23:34:30Z
author_association: NONE
type: issue
state_reason: completed
body:
  Folder structure:

  ```
  bibliography/
  bibliography/static-files
  bibliography/static-files/styles.css
  bibliography/bibliography.db
  bibliography/metadata.json
  bibliography/settings.json
  ```

  ```
  $ cat bibliography/settings.json 
  {
    "suggest_facets": false,
    "truncate_cells_html": 1000,
    "static": "assets:static-files/"
  }
  ```

  File `/assets/styles.css` is not found (HTTP 404, `Database not found: assets`).

  Using datasette revision d0737e4de51ce178e556fc011ccb8cc46bbb6359.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1814/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SLFKn
title: `datasette publish provider .` to publish whole directory, similar to configuration directory mode
state: open
created_at: 2022-09-19T23:28:59Z
updated_at: 2022-09-19T23:29:11Z
author_association: OWNER
type: issue
body:
  > I haven't done this with any of my other `datasette publish` tools, but I do think it's a good idea. Being able to publish the entire directory - with templates and plugins and metadata - does seem very useful to me.

  _Originally posted by @simonw in https://github.com/simonw/datasette-publish-fly/issues/23#issuecomment-1251673489_

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1815/reactions", "total_count": 2, "+1": 2, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SLGOA
title: Validate settings.json on startup in configuration directory mode
state: closed
created_at: 2022-09-19T23:35:18Z
updated_at: 2022-09-20T01:15:48Z
closed_at: 2022-09-20T01:15:48Z
author_association: OWNER
type: issue
state_reason: completed
body:
  > It might have been useful for Datasette to show an error when started against a `settings.json` file that contains an invalid setting though.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1814#issuecomment-1251677554_

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1816/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5SZqG0
title: Ability to insert multi-line files
state: closed
created_at: 2022-09-22T13:29:22Z
updated_at: 2022-09-26T18:24:44Z
closed_at: 2022-09-23T16:37:58Z
author_association: NONE
type: issue
state_reason: completed
body:
  I was looking into how to parse application log files that contain multiline text (e.g. Java stack traces) into sqlite. 
  I can see that at the moment `--lines` helps, but falls short when processing multi-line texts.

  I wonder if this functionality would be useful for sqlite-utils. A similar approach to Elastic logstash/filebeat can be adopted: https://www.elastic.co/guide/en/beats/filebeat/current/multiline-examples.html 

  Potential changes:

  - add a `--multiline` option
  - additional properties for
    - multiline-pattern (regex expression)
    - multiline-negate: true/false
    - multiline-what: previous or next

  Or if this is achievable in a different way, please share. Thanks!

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/490/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5SeMWX
title: Ability to merge databases and tables
state: open
created_at: 2022-09-23T11:10:55Z
updated_at: 2023-06-14T22:14:24Z
author_association: NONE
type: issue
body:
  Hi! Let me firstly say that I am a big fan of your work -- I follow your tweets and blog posts with great interest 😄.

  Now onto the matter at hand: I think it would be great if `sqlite-utils` included a `merge` or `combine` command, with the purpose of combining different SQLite databases into a single SQLite database. This way, the newly "merged" database would contain all differently named tables contained in the databases to be merged as-is, as well a concatenation of all tables of the same name.

  This could look something like this:

  ```bash
  sqlite-utils merge cats.db dogs.db > animals.db
  ```

  I imagine this is rather straightforward if all databases involved in the merge contain differently named tables (i.e. no chance of conflicts), but things get slightly more complicated if two or more of the databases to be merged contain tables with the same name. Not only do you have to "do something" with the primary key(s), but these tables could also simply have different schemas (and therefore be incompatible for concatenation to begin with).

  Anyhow, I would love your thoughts on this, and, if you are open to it, work together on the design and implementation!

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/491/reactions", "total_count": 2, "+1": 2, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SglhB
title: Expose `sql` and `params` arguments to various plugin hooks
state: open
created_at: 2022-09-23T20:34:45Z
updated_at: 2022-09-27T00:27:53Z
author_association: OWNER
type: issue
body:
  On Discord: https://discord.com/channels/823971286308356157/996877076982415491/1022784534363787305

  > Hi! I'm attempting to write a plugin that would provide some statistics on text fields (most common words, etc). I would want this information displayed in the table pages, and (ideally) also updated when users make custom queries from the table pages.
  >
  > It seems one way to do this would be to use the extra_template_vars hook, and make the appropriate SQL query there. So extra_template_vars would create a variable that is a list of most common words, and this is displayed on the page, possibly above the regular table view.
  >
  > Is there a way that the plugin code can access the SQL query (or even the data) that was used to produce the table view? I can see that TableView class constructs the SQL query, but I can't seem to find a way to access that information from the objects that are available to extra_template_vars.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1817/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Sho5p
title: Setting to turn off table row counts entirely
state: open
created_at: 2022-09-24T06:39:22Z
updated_at: 2022-12-11T02:03:09Z
author_association: OWNER
type: issue
body:
  There are situations - such as loading SQLite files remotely using HTTP range headers - where counting all of the rows in a table should be avoided entirely.

  > > Also, this chunked inefficiency means that I have to hack the URL to not load tables of a database as it seems to try to load the whole database when I click on a database.
  >
  > I bet that's because Datasette tries to show a count of all of the rows in each table when it shows the list on that page, which triggers a full table scan.
  >
  > Would be great to have a setting that turns that feature off, which could then be exposed as a query string option for Datasette Lite.

  _Originally posted by @simonw in https://github.com/simonw/datasette-lite/issues/49#issuecomment-1256880715_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1818/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SjdKi
title: Preserve query on timeout
state: closed
created_at: 2022-09-25T13:32:31Z
updated_at: 2022-09-26T23:16:15Z
closed_at: 2022-09-26T23:06:06Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  If a query hits the timeout it shows a message like:

  > SQL query took too long. The time limit is controlled by the [sql_time_limit_ms](https://docs.datasette.io/en/stable/settings.html#sql-time-limit-ms) configuration option.

  But the query is lost. Hitting the browser back button shows the query _before_ the one that errored.

  It would be nice if the query that errored was preserved for more tweaking. This would make it similar to how "invalid syntax" works since #1346 / #619.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1819/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4_oHI4
title: [SPIKE] Don't truncate query CSVs
state: closed
created_at: 2022-09-26T17:27:01Z
updated_at: 2022-10-07T16:12:17Z
closed_at: 2022-10-07T16:12:17Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1820
type: pull
body:
  Relates to #526 

  This is a minimal set of changes needed for having *query* CSVs attempt to download all the rows. 

  What's good about it is the minimalism.

  What's bad about it:

  1. We are abusing the `_size` argument to indicate we don't want truncation, which isn't the most obvious thing. Additionally, there are various checks that make sure the "_size" URL parameter is a positive integer, which we are relying on to prevent overloading.
  2. The default CSV on a table page will use the max_returned_rows argument. Changing this could be a breaking change, since that's currently a place that has some facilities for pagination. Additionally, i think there's a limit under the hood somewhere which if we removed could lead to sql timeouts
  3. There are similar reasons for leaving the current streaming method alone, as the current methods could allow for downloading very large files that could have a sql timeout if we tried to get them in one go.



  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1820.org.readthedocs.build/en/1820/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1820/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5SpMVs
title: Idea: ability to pass extra variables to `--convert` scripts
state: open
created_at: 2022-09-26T18:30:45Z
updated_at: 2022-09-26T18:33:19Z
author_association: OWNER
type: issue
body:
  Got this idea from this example in https://jeqo.github.io/notes/2022-09-24-ingest-logs-sqlite/

  ```bash
  sqlite-utils insert /tmp/kafka-logs.db logs server.log.2022-09-24-21 --text --convert "
  import re
  r = re.compile(r'^\[(?P<datetime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\] (?P<level>\w+) (?P<log>(.+(\n(?\!\[).+|)+))', re.MULTILINE)
  def convert(text):
      rows = [m.groupdict() for m in r.finditer(text)]
      for row in rows:
          row.update({'server': 'localhost'})
          row.update({'component': 'broker'})
      return rows
  "
  ```
  And the accompanying note:

  > The `row.update` allows to label rows as I’m planning to ingest logs from different hosts and potentially different components.

  This made me think: it might be neat if you could inject additional variable values into that script with extra command-line options, to make this kind of reuse easier. Something like this:

  ```bash
  sqlite-utils insert /tmp/kafka-logs.db logs server.log.2022-09-24-21 --text --convert "
  import re
  r = re.compile(r'^\[(?P<datetime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\] (?P<level>\w+) (?P<log>(.+(\n(?\!\[).+|)+))', re.MULTILINE)
  def convert(text):
      rows = [m.groupdict() for m in r.finditer(text)]
      for row in rows:
          row.update({'server': server})
          row.update({'component': component})
      return rows
  " --var server "localhost" --var component "broker"
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/492/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5SpURm
title: Tiny typographical error in install/uninstall docs
state: open
created_at: 2022-09-26T19:00:42Z
updated_at: 2022-10-25T21:31:15Z
author_association: OWNER
type: issue
body:
  Added in:
  - #483

  I don't know how to fix this in Sphinx: I'm getting this: https://sqlite-utils.datasette.io/en/latest/cli.html#cli-install

  > The [insert –convert](https://sqlite-utils.datasette.io/en/latest/cli.html#cli-insert-convert) and [query –functions](https://sqlite-utils.datasette.io/en/latest/cli.html#cli-query-functions) options

  <img width="849" alt="image" src="https://user-images.githubusercontent.com/9599/192358225-4fae509e-9fa8-4e8d-91d4-48aa1b79225e.png">

  But I want it to display `insert --convert` and not `insert –convert` there.

  Here's the code: https://github.com/simonw/sqlite-utils/blob/85247038f70d7eb2f3e272cfeaa4c44459cafba8/docs/cli.rst#L2125

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/493/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5Spb4z
title: Document how to use Just
state: closed
created_at: 2022-09-26T19:25:12Z
updated_at: 2022-09-26T19:32:36Z
closed_at: 2022-09-26T19:26:39Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I'm using `just` a lot know, based on this file - I should add that to https://sqlite-utils.datasette.io/en/latest/contributing.html

  https://github.com/simonw/sqlite-utils/blob/afbd2b2cba45cccb305c3d4638d18db4dd3d4bbd/Justfile#L1-L24

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/494/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Sp-Mv
title: Release Datasette 0.63a0
state: closed
created_at: 2022-09-26T21:15:27Z
updated_at: 2022-09-26T22:06:39Z
closed_at: 2022-09-26T22:06:39Z
author_association: OWNER
type: issue
state_reason: completed
body:
  > - The [prepare_jinja2_environment(env, datasette)](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-prepare-jinja2-environment) plugin hook now accepts an optional `datasette` argument. Hook implementations can also now return an `async` function which will be awaited automatically. ([#1809](https://github.com/simonw/datasette/issues/1809))
  > - `--load-extension` option now supports entrypoints. Thanks, Alex Garcia. ([#1789](https://github.com/simonw/datasette/pull/1789))
  > - New tutorial: [Cleaning data with sqlite-utils and Datasette](https://datasette.io/tutorials/clean-data).
  > - Facet size can now be set per-table with the new `facet_size` table metadata option. ([#1804](https://github.com/simonw/datasette/issues/1804))
  > - `truncate_cells_html` setting now also affects long URLs in columns. ([#1805](https://github.com/simonw/datasette/issues/1805))
  > - `Database(is_mutable=)` now defaults to `True`. ([#1808](https://github.com/simonw/datasette/issues/1808))
  > - Non-JavaScript textarea now increases height to fit the SQL query. ([#1786](https://github.com/simonw/datasette/issues/1786))
  > - More detailed command descriptions on the [CLI reference](https://docs.datasette.io/en/latest/cli-reference.html#cli-reference) page. ([#1787](https://github.com/simonw/datasette/issues/1787))
  > - Datasette no longer enforces upper bounds on its depenedencies. ([#1800](https://github.com/simonw/datasette/issues/1800))
  > - Facets are now displayed with better line-breaks in long values. Thanks, Daniel Rech. ([#1794](https://github.com/simonw/datasette/pull/1794))
  > - The `settings.json` file used in [Configuration directory mode](https://docs.datasette.io/en/latest/settings.html#config-dir) is now validated on startup. ([#1816](https://github.com/simonw/datasette/issues/1816))

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1821/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Sqbdm
title: Switch to keyword-only arguments for a bunch of internal methods
state: open
created_at: 2022-09-26T23:20:38Z
updated_at: 2022-09-27T00:44:04Z
author_association: OWNER
type: issue
body:
  This is a good idea, and one that needs to happen before Datasette 1.0:

  > While you are adding features, would you be future-proofing your APIs if you switched over some arguments over to keyword-only arguments or would that be too disruptive?
  >
  > Thinking out loud:
  >
  > ```
  > async def render_template( 
  >      self, templates, *, context=None, plugin_context=None, request=None, view_name=None 
  > ): 
  > ```
  _Originally posted by @jefftriplett in https://github.com/simonw/datasette/issues/1817#issuecomment-1256781274_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1822/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4_prjN
title: Keyword-only arguments for a bunch of internal methods
state: open
created_at: 2022-09-27T00:44:59Z
updated_at: 2022-10-05T04:37:54Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1823
type: pull
body:
  Refs #1822

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1823.org.readthedocs.build/en/1823/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1823/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Sts_1
title: Convert &_hide_sql=1 to #_hide_sql
state: open
created_at: 2022-09-27T12:53:31Z
updated_at: 2022-10-05T12:56:27Z
author_association: NONE
type: issue
body:
  Hiding the SQL textarea with `&_hide_sql=1` enforces a page reload, which can take several seconds and use server resource (which is annoying for big database or complex queries).

  It could probably be done with a few lines of Javascript (I'm going to see if I can do that).

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1824/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4_uCkO
title: Add documentation for serving via OpenRC
state: closed
created_at: 2022-09-27T19:00:56Z
updated_at: 2022-09-28T04:21:37Z
closed_at: 2022-09-28T04:21:37Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1825
type: pull
body:
  I also removed a few lines which felt redundant given the following section dedicated to running behind a nginx proxy.

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1825.org.readthedocs.build/en/1825/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1825/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5SxNbp
title: render_cell documentation example doesn't match the method signature
state: closed
created_at: 2022-09-28T02:37:59Z
updated_at: 2022-09-28T04:30:28Z
closed_at: 2022-09-28T04:05:16Z
author_association: NONE
type: issue
state_reason: completed
body:
  Open Datasette stable doc at https://docs.datasette.io/en/stable/plugin_hooks.html?highlight=render_cell#render-cell-row-value-column-table-database-datasette

  render_cell plugin hook method signature is `render_cell(row, value, column, table, database, datasette)`, the example shown inline uses `render_cell(value)`.

  ![image](https://user-images.githubusercontent.com/66709385/192674691-34265b81-6cdd-41d2-8424-aa12f8bc8c94.png)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1826/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c4_8BMC
title: Bump furo from 2022.9.15 to 2022.9.29
state: closed
created_at: 2022-09-30T13:15:35Z
updated_at: 2022-09-30T17:55:42Z
closed_at: 2022-09-30T17:55:41Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1827
type: pull
body:
  Bumps [furo](https://github.com/pradyunsg/furo) from 2022.9.15 to 2022.9.29.
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/pradyunsg/furo/blob/main/docs/changelog.md">furo's changelog</a>.</em></p>
  <blockquote>
  <h1>Changelog</h1>
  <!-- raw HTML omitted -->
  <h2>2022.09.29 -- Quaint Quartz</h2>
  <ul>
  <li>Add ability to set arbitrary URLs for edit button.</li>
  <li>Add support for aligning text in MyST-parser generated tables.</li>
  </ul>
  <h2>2022.09.15 -- Pragmatic Pistachio</h2>
  <ul>
  <li>Add a minimum version constraint on pygments.</li>
  <li>Add an explicit dependency on <code>sass</code>.</li>
  <li>Change right sidebar title from &quot;Contents&quot; to &quot;On this page&quot;.</li>
  <li>Correctly position sidebars on small screens.</li>
  <li>Correctly select only Furo's own <code>svg</code> in related pages <code>nav</code>.</li>
  <li>Make numpy-style documentation headers consistent.</li>
  <li>Retitle the reference section.</li>
  <li>Update npm dependencies.</li>
  </ul>
  <h2>2022.06.21 -- Opulent Opal</h2>
  <ul>
  <li>Fix <code>docutils &lt;= 0.17.x</code> compatibility.</li>
  <li>Bump to the latest Node.js LTS.</li>
  </ul>
  <h2>2022.06.04.1 -- Naughty Nickel bugfix</h2>
  <ul>
  <li>Fix the URL used in the &quot;Edit this page&quot; for Read the Docs builds.</li>
  </ul>
  <h2>2022.06.04 -- Naughty Nickel</h2>
  <ul>
  <li>✨ Advertise Sphinx 5 compatibility.</li>
  <li>✨ Change to <code>basic-ng</code> as the base theme (from {pypi}<code>sphinx-basic-ng</code>).</li>
  <li>Document site-wide announcement banners.</li>
  <li>Drop the pin on pygments.</li>
  <li>Improve edit button, using <code>basic-ng</code>'s <code>edit-this-page</code> component.</li>
  <li>Tweak headings to better match what users expect.</li>
  <li>Tweak how Sphinx's default HTML is rendered, using docutils post-transforms (this replaces parsing+modifying it with BeautifulSoup).</li>
  <li>When built with docutils 0.18, footnotes are rendered differently and stylised differently in Furo.</li>
  </ul>
  <h2>2022.04.07 -- Magical Mauve</h2>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/pradyunsg/furo/commit/1375f9d7c3facfd4f2f6bb62b5f43fd51248248f"><code>1375f9d</code></a> Prepare release: 2022.09.29</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/af43607724dd523dce3e863ebc7b555a9b4f4ec9"><code>af43607</code></a> Update changelog</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/bc0fe522c67eab477964bcfdb02f4db08e16cb95"><code>bc0fe52</code></a> Update user-facing documentation for edit button</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/509c558905cb5127402fdbb9d36166eb34fc1ef2"><code>509c558</code></a> Modernise the <code>edit-this-page.html</code> template</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/5a0ceca905c23dcdb79678354912ce91b096438c"><code>5a0ceca</code></a> Add <code>source_edit_link</code> as a theme configuration parameter (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/510">#510</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/52fc32fcb10ee4f64c3f3ca3232808eb529212f6"><code>52fc32f</code></a> Build documentation in pull requests</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/149f77b5ca335142ab99cdd9a390653e70b702c5"><code>149f77b</code></a> Fix stylesheet for MyST tables</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/9af2e44c7c714dd0bfc90dedf9001c05144127ba"><code>9af2e44</code></a> Support MyST table column alignment (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/531">#531</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/82dd61c092e6137f8df51dc3feb2c7e6f6a121a1"><code>82dd61c</code></a> Back to development</li>
  <li>See full diff in <a href="https://github.com/pradyunsg/furo/compare/2022.09.15...2022.09.29">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=furo&package-manager=pip&previous-version=2022.9.15&new-version=2022.9.29)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1827.org.readthedocs.build/en/1827/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1827/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5TAsQa
title: Support JSON values returned from .convert() functions
state: closed
created_at: 2022-09-30T16:33:49Z
updated_at: 2022-10-25T21:23:37Z
closed_at: 2022-10-25T21:23:28Z
author_association: NONE
type: issue
state_reason: completed
body:
  When using the convert function on a JSON column, the result of the conversion function must be a string. If the return value is either a dict (object) or a list (array), the convert call will error out with an unhelpful user defined function exception. 

  It makes sense that since the original column value was a string and required conversion to data structures, the result should be converted back into a JSON string as well. However, other functions auto-convert to JSON string representation, so the fact that convert doesn't could be surprising.

  At least the documentation should note this requirement, because the sqlite error messages won't readily reveal the issue.

  Jf only sqlite's JSON column type meant something :)

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/495/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5TCpOM
title: devrel/python api: Pylance type hinting
state: open
created_at: 2022-10-01T03:03:34Z
updated_at: 2023-05-03T05:53:27Z
author_association: CONTRIBUTOR
type: issue
body:
  Pylance is generally pretty good at figuring out stuff but `sqlite-utils` has some quirks which make type hinting kinda useless. Maybe you don't care but I thought I would bring it to your attention.

  For example:

  ```
  db["subs"].insert_all(subs, pk="index")
  ```

  ```
  Cannot access member "insert_all" for type "View"
    Member "insert_all" is unknown
  ```

  `insert_all` and all the other methods show up as a type issues because the program can't know whether something is a View or a Table. Fair enough. But that basically throws all type checking out the window.

  `pk="index"` also shows up as a type issue:

  ```
  Argument of type "Literal['index']" cannot be assigned to parameter "pk" of type "Default" in function "insert_all"
    "Literal['index']" is incompatible with "Default"
  ```

  I think this is because DEFAULT is an empty class? 

  maybe a few small changes could be made to make the library more type-friendly

  The interim solution is of course to turn off type hints completely for the line
  ```
  db["subs"].insert_all(subs, pk="index")  # type: ignore
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/496/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5TCr4k
title: column_names
state: closed
created_at: 2022-10-01T03:34:21Z
updated_at: 2022-10-25T21:09:28Z
closed_at: 2022-10-25T21:09:28Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  It would be nice to have a `column_names`. Similar to `table_names`.

  Or if you could get one or all of the following syntax to work for both Database and Table that might be even better: 

  Style 1
  - `if 'table1' in db`
  - `if 'col1' in db['table1']`

  Style 2
  - `if 'table1' in db.tables`
  - `if 'col1' in db['table1'].columns`

  maybe the table ones actually work but I'm too lazy to check. I just know that I have to do:

   `[c.name for c in db['table1'].columns]`

  Edit: This is possible with `columns_dict`. I have actually used that before but I forgot about it. Feel free to close, but I do think accessing this data could be more consistent and intuitive.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/497/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODD6af84__DNJ
title: Photo links
state: open
created_at: 2022-10-01T09:44:15Z
updated_at: 2022-11-18T17:10:49Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/swarm-to-sqlite/pulls/14
type: pull
body:
  * add to `checkin_details` view new column for a calculated photo links
  * supported multiple links split by newline
  * create `events` table if there's no events in the history to avoid SQL errors

  Fixes #9.

reactions:
  {"url": "https://api.github.com/repos/dogsheep/swarm-to-sqlite/issues/14/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TFUjl
title: word-wrap: anywhere resulting in weird display
state: closed
created_at: 2022-10-02T21:25:03Z
updated_at: 2022-10-02T23:01:17Z
closed_at: 2022-10-02T23:01:17Z
author_association: OWNER
type: issue
state_reason: completed
body:
  e.g. on https://github-to-sqlite.dogsheep.net/github/commits

  <img width="893" alt="image" src="https://user-images.githubusercontent.com/9599/193476890-a96fae4f-4883-4698-816d-90f9cf6efd6c.png">

  This is from a change introduced here: https://github.com/simonw/datasette/commit/bf8d84af5422606597be893cedd375020cb2b369 in #1805

  https://github.com/simonw/datasette/blob/bf8d84af5422606597be893cedd375020cb2b369/datasette/static/app.css#L447-L450

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1828/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TQ77V
title: Table/database that is private due to inherited permissions does not show padlock
state: closed
created_at: 2022-10-04T23:14:16Z
updated_at: 2022-10-24T02:23:46Z
closed_at: 2022-10-24T02:11:37Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I noticed that a table page that is private because the database or instance is private, e.g. this one:

  <img width="982" alt="image" src="https://user-images.githubusercontent.com/9599/193947303-ed643dcd-a07c-4ffb-ab22-539c4c803206.png">

  Is not displaying the padlock icon that indicates the table is not visible to the public.

  <img width="969" alt="image" src="https://user-images.githubusercontent.com/9599/193947373-ddbdf398-ea67-4e21-b54d-60c48496701d.png">

  Same issue for the database page too, which in this case is private due to `view-instance`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1829/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TRDFK
title: Add documentation for writing tests with signed actor cookies
state: open
created_at: 2022-10-04T23:51:26Z
updated_at: 2022-10-04T23:51:26Z
author_association: OWNER
type: issue
body:
  I use this pattirn in a lot of plugin tests, e.g. https://github.com/simonw/datasette-edit-templates/blob/087f6a6cabc20020f2b0524f11aa3a7836320848/tests/test_edit_templates.py#L55-L58
  ```python
      actor = ds.sign({"a": {"id": "root"}}, "actor")
      response1 = await ds.client.get(
          "/-/edit-templates/_footer.html", cookies={"ds_actor": actor}
      )
  ```
  I should add this to the documentation on this page: https://docs.datasette.io/en/latest/testing_plugins.html

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1830/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TRdB5
title: If user can see table but NOT database/instance nav links should not display
state: closed
created_at: 2022-10-05T02:16:31Z
updated_at: 2022-10-13T21:52:04Z
closed_at: 2022-10-13T21:52:04Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Spotted this bug while building this plugin:
  - https://github.com/simonw/datasette-public

  This is a public table, but the two links in the nav go to forbidden pages:

  <img width="1007" alt="image" src="https://user-images.githubusercontent.com/9599/193964983-c574efcd-fd7d-4507-bb71-58fe5252a831.png">

  Those nav links shouldn't be shown at all.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1831/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TR3vb
title: __bool__ method on Results
state: closed
created_at: 2022-10-05T04:18:12Z
updated_at: 2022-10-05T04:32:33Z
closed_at: 2022-10-05T04:32:33Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Wrote this code today: https://github.com/simonw/datasette-public/blob/1401bfae50e71c1dfd2bfb6954f2e86d5a7ab21b/datasette_public/__init__.py#L41
  ```python
      results = await db.execute(
          "select 1 from _public_tables where table_name = ?", [table_name]
      )
      if len(results):
          return True
  ```
  Would be nice if I could use `if results` there instead.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1832/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TcUpJ
title: Ability to submit long queries by POST
state: open
created_at: 2022-10-06T16:03:26Z
updated_at: 2022-10-06T16:18:00Z
author_association: OWNER
type: issue
body:
  Datasette doesn't limit URL lengths but some common web proxies do - the one in front of Google Cloud Run for example limits to 8KB total for incoming request headers: https://cloud.google.com/load-balancing/docs/quotas#https-lb-header-limits

  This means longer SQL queries can break!

  Need an optional mechanism for submitting queries by POST instead.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1833/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Tc5Jj
title: inspect data is not used for caching database hash
state: closed
created_at: 2022-10-06T17:52:01Z
updated_at: 2022-10-06T20:06:21Z
closed_at: 2022-10-06T20:06:08Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  When databases are loaded,

  https://github.com/simonw/datasette/blob/cb1e093fd361b758120aefc1a444df02462389a3/datasette/app.py#L257-L260

  there is nothing preventing the rehashing of the database for immutable databases.

  https://github.com/simonw/datasette/blob/cb1e093fd361b758120aefc1a444df02462389a3/datasette/database.py#L50-L53

  what i might expect is that relevant values of `inspect_data` get passed to the `Database` class to prevent re-hashing?

  With data that is many gigs large, this is a significant start up time.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1834/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5AVujU
title: use inspect data for hash and file size
state: closed
created_at: 2022-10-06T18:25:24Z
updated_at: 2022-10-27T20:51:30Z
closed_at: 2022-10-06T20:06:07Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1835
type: pull
body:
  `inspect_data` should already include the hash and the db file size, so this PR takes advantage of using those instead of always recalculating. should help a lot on startup with large DBs.

  closes #1834 

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1835/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5TeAZ8
title: docker image is duplicating db files somehow
state: open
created_at: 2022-10-06T22:35:54Z
updated_at: 2022-10-08T16:56:51Z
author_association: CONTRIBUTOR
type: issue
body:
  if you look into the docker image created by docker publish, the `datasette inspect` line is duplicating the db files.

  here's the result of the inspect command:

  <img width="490" alt="Screen Shot 2022-10-06 at 2 58 08 PM" src="https://user-images.githubusercontent.com/536941/194430909-9303ee1a-9bdd-4212-b54b-de28f43768d4.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1836/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5AWyQK
title: Make hash and size a lazy property
state: closed
created_at: 2022-10-06T23:51:22Z
updated_at: 2022-10-27T20:51:21Z
closed_at: 2022-10-27T20:51:20Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1837
type: pull
body:
  Many apologies, @simonw. My previous PR #1835 did not really solve the problem because the name of the database is often not known to database object in the init method.

  I took a cue from how you dealt with this issue and made hash a lazy property and did something similar with size.

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1837.org.readthedocs.build/en/1837/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1837/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5AW_kl
title: Open Datasette link in new tab
state: closed
created_at: 2022-10-07T01:12:20Z
updated_at: 2022-10-07T16:28:41Z
closed_at: 2022-10-07T02:01:07Z
author_association: NONE
pull_request: simonw/datasette/pulls/1838
type: pull
body:
  This is technically a Sandstorm-specific fix (as external links do not work inside the grain frame), however, I think it is an improvement to the upstream project, so I wanted to propose it here rather than patching it in our package.

  There's much opinions on the Internet about whether external links should open in a new tab by default or not, but I'd argue very few people who might click a "powered by" link intend to complete their interaction with the source page (a Datasette). And furthermore, users may be working within various queries or loading visualizations (navigating away when trying to plot a million GPS coordinates pretty much just resets your progress!), so linking away within the tab might be a frustrating or destructive act to one's work, even inadvertently.

  original report: https://github.com/ocdtrekkie/datasette-sandstorm/issues/1

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1838.org.readthedocs.build/en/1838/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1838/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5AZLzm
title: Bump black from 22.8.0 to 22.10.0
state: closed
created_at: 2022-10-07T13:13:41Z
updated_at: 2022-10-27T20:51:46Z
closed_at: 2022-10-27T20:51:45Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1839
type: pull
body:
  Bumps [black](https://github.com/psf/black) from 22.8.0 to 22.10.0.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/psf/black/releases">black's releases</a>.</em></p>
  <blockquote>
  <h2>22.10.0</h2>
  <h3>Highlights</h3>
  <ul>
  <li>Runtime support for Python 3.6 has been removed. Formatting 3.6 code will still be
  supported until further notice.</li>
  </ul>
  <h3>Stable style</h3>
  <ul>
  <li>Fix a crash when <code># fmt: on</code> is used on a different block level than <code># fmt: off</code>
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3281">#3281</a>)</li>
  </ul>
  <h3>Preview style</h3>
  <ul>
  <li>Fix a crash when formatting some dicts with parenthesis-wrapped long string keys
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3262">#3262</a>)</li>
  </ul>
  <h3>Configuration</h3>
  <ul>
  <li><code>.ipynb_checkpoints</code> directories are now excluded by default (<a href="https://github-redirect.dependabot.com/psf/black/issues/3293">#3293</a>)</li>
  <li>Add <code>--skip-source-first-line</code> / <code>-x</code> option to ignore the first line of source code
  while formatting (<a href="https://github-redirect.dependabot.com/psf/black/issues/3299">#3299</a>)</li>
  </ul>
  <h3>Packaging</h3>
  <ul>
  <li>Executables made with PyInstaller will no longer crash when formatting several files
  at once on macOS. Native x86-64 executables for macOS are available once again.
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3275">#3275</a>)</li>
  <li>Hatchling is now used as the build backend. This will not have any effect for users
  who install Black with its wheels from PyPI. (<a href="https://github-redirect.dependabot.com/psf/black/issues/3233">#3233</a>)</li>
  <li>Faster compiled wheels are now available for CPython 3.11 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3276">#3276</a>)</li>
  </ul>
  <h3><em>Blackd</em></h3>
  <ul>
  <li>Windows style (CRLF) newlines will be preserved (<a href="https://github-redirect.dependabot.com/psf/black/issues/3257">#3257</a>).</li>
  </ul>
  <h3>Integrations</h3>
  <ul>
  <li>Vim plugin: add flag (<code>g:black_preview</code>) to enable/disable the preview style (<a href="https://github-redirect.dependabot.com/psf/black/issues/3246">#3246</a>)</li>
  <li>Update GitHub Action to support formatting of Jupyter Notebook files via a <code>jupyter</code>
  option (<a href="https://github-redirect.dependabot.com/psf/black/issues/3282">#3282</a>)</li>
  <li>Update GitHub Action to support use of version specifiers (e.g. <code>&lt;23</code>) for Black
  version (<a href="https://github-redirect.dependabot.com/psf/black/issues/3265">#3265</a>)</li>
  </ul>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/psf/black/blob/main/CHANGES.md">black's changelog</a>.</em></p>
  <blockquote>
  <h2>22.10.0</h2>
  <h3>Highlights</h3>
  <ul>
  <li>Runtime support for Python 3.6 has been removed. Formatting 3.6 code will still be
  supported until further notice.</li>
  </ul>
  <h3>Stable style</h3>
  <ul>
  <li>Fix a crash when <code># fmt: on</code> is used on a different block level than <code># fmt: off</code>
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3281">#3281</a>)</li>
  </ul>
  <h3>Preview style</h3>
  <ul>
  <li>Fix a crash when formatting some dicts with parenthesis-wrapped long string keys
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3262">#3262</a>)</li>
  </ul>
  <h3>Configuration</h3>
  <ul>
  <li><code>.ipynb_checkpoints</code> directories are now excluded by default (<a href="https://github-redirect.dependabot.com/psf/black/issues/3293">#3293</a>)</li>
  <li>Add <code>--skip-source-first-line</code> / <code>-x</code> option to ignore the first line of source code
  while formatting (<a href="https://github-redirect.dependabot.com/psf/black/issues/3299">#3299</a>)</li>
  </ul>
  <h3>Packaging</h3>
  <ul>
  <li>Executables made with PyInstaller will no longer crash when formatting several files
  at once on macOS. Native x86-64 executables for macOS are available once again.
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3275">#3275</a>)</li>
  <li>Hatchling is now used as the build backend. This will not have any effect for users
  who install Black with its wheels from PyPI. (<a href="https://github-redirect.dependabot.com/psf/black/issues/3233">#3233</a>)</li>
  <li>Faster compiled wheels are now available for CPython 3.11 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3276">#3276</a>)</li>
  </ul>
  <h3><em>Blackd</em></h3>
  <ul>
  <li>Windows style (CRLF) newlines will be preserved (<a href="https://github-redirect.dependabot.com/psf/black/issues/3257">#3257</a>).</li>
  </ul>
  <h3>Integrations</h3>
  <ul>
  <li>Vim plugin: add flag (<code>g:black_preview</code>) to enable/disable the preview style (<a href="https://github-redirect.dependabot.com/psf/black/issues/3246">#3246</a>)</li>
  <li>Update GitHub Action to support formatting of Jupyter Notebook files via a <code>jupyter</code>
  option (<a href="https://github-redirect.dependabot.com/psf/black/issues/3282">#3282</a>)</li>
  <li>Update GitHub Action to support use of version specifiers (e.g. <code>&lt;23</code>) for Black
  version (<a href="https://github-redirect.dependabot.com/psf/black/issues/3265">#3265</a>)</li>
  </ul>
  </blockquote>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/psf/black/commit/27d20144a7517594e24a1649451177b2a11284be"><code>27d2014</code></a> Prepare release 22.10.0 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3311">#3311</a>)</li>
  <li><a href="https://github.com/psf/black/commit/4da0851809e024760d3861ff43309125de34157a"><code>4da0851</code></a> Add option to skip the first line of source code (<a href="https://github-redirect.dependabot.com/psf/black/issues/3299">#3299</a>)</li>
  <li><a href="https://github.com/psf/black/commit/0359b85b5800dd77f8f1cfaa88ca8ab8215df685"><code>0359b85</code></a> Preserve crlf line endings in blackd (<a href="https://github-redirect.dependabot.com/psf/black/issues/3257">#3257</a>)</li>
  <li><a href="https://github.com/psf/black/commit/27d7ea43eb127cc5189a724a7d194d94ba312861"><code>27d7ea4</code></a> Bump docutils from 0.18.1 to 0.19 in /docs (<a href="https://github-redirect.dependabot.com/psf/black/issues/3161">#3161</a>)</li>
  <li><a href="https://github.com/psf/black/commit/1a20c4d4874f912822f6a42cb61816330a4f6508"><code>1a20c4d</code></a> Bump sphinx from 5.2.1 to 5.2.3 in /docs (<a href="https://github-redirect.dependabot.com/psf/black/issues/3305">#3305</a>)</li>
  <li><a href="https://github.com/psf/black/commit/980997f215d25deb27e03ea704258f62199b8a5f"><code>980997f</code></a> Bump furo from 2022.9.15 to 2022.9.29 in /docs (<a href="https://github-redirect.dependabot.com/psf/black/issues/3304">#3304</a>)</li>
  <li><a href="https://github.com/psf/black/commit/b1077aa14ee6afc90aac15549a1f5d0aff4fd524"><code>b1077aa</code></a> Bump myst-parser from 0.18.0 to 0.18.1 in /docs (<a href="https://github-redirect.dependabot.com/psf/black/issues/3303">#3303</a>)</li>
  <li><a href="https://github.com/psf/black/commit/956bf3962edff284d05ad42576bac7e74ae8788d"><code>956bf39</code></a> Add .ipynb_checkpoints to DEFAULT_EXCLUDES (<a href="https://github-redirect.dependabot.com/psf/black/issues/3293">#3293</a>)</li>
  <li><a href="https://github.com/psf/black/commit/141291a1d86d43158da89d0254b7c2cc79609679"><code>141291a</code></a> Enable build isolation under CIWB (<a href="https://github-redirect.dependabot.com/psf/black/issues/3297">#3297</a>)</li>
  <li><a href="https://github.com/psf/black/commit/ddb99241b583f45e01df622c0d8f119aecd0188e"><code>ddb9924</code></a> Bump pypa/cibuildwheel from 2.10.0 to 2.10.2 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3290">#3290</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/psf/black/compare/22.8.0...22.10.0">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=black&package-manager=pip&previous-version=22.8.0&new-version=22.10.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1839.org.readthedocs.build/en/1839/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1839/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5AdyZ4
title: test commit
state: closed
created_at: 2022-10-10T05:15:26Z
updated_at: 2022-10-10T09:11:50Z
closed_at: 2022-10-10T09:11:50Z
author_association: FIRST_TIMER
pull_request: simonw/datasette/pulls/1840
type: pull
body:
  lalalalalalala

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1840.org.readthedocs.build/en/1840/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1840/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOCGYnMM5AicIh
title: fix: enable-fts permanently save triggers
state: closed
created_at: 2022-10-11T05:10:51Z
updated_at: 2022-10-15T04:33:08Z
closed_at: 2022-10-11T06:34:31Z
author_association: CONTRIBUTOR
pull_request: simonw/sqlite-utils/pulls/498
type: pull
body:
  I was wondering why my all my databases were giving wild search results. Turns out create_trigger was not sticking!

  Running `sqlite-utils triggers x.db` shows `[]` after running `enable-fts` using the python api. Looking at the counts trigger it seems that is the right way to save triggers. triggers show up now

  <!-- readthedocs-preview sqlite-utils start -->
  ----
  :books: Documentation preview :books:: https://sqlite-utils--498.org.readthedocs.build/en/498/

  <!-- readthedocs-preview sqlite-utils end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/498/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOCGYnMM5AmYzy
title: feat: recreate fts triggers after table transform
state: open
created_at: 2022-10-11T20:35:39Z
updated_at: 2022-10-26T17:54:51Z
author_association: CONTRIBUTOR
pull_request: simonw/sqlite-utils/pulls/499
type: pull
body:
  https://github.com/simonw/sqlite-utils/pull/498

  <!-- readthedocs-preview sqlite-utils start -->
  ----
  :books: Documentation preview :books:: https://sqlite-utils--499.org.readthedocs.build/en/499/

  <!-- readthedocs-preview sqlite-utils end -->

  alternatively, `self.disable_fts()`

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/499/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5T2vxq
title: Drop format_bytes for Jinja filesizeformat filter
state: open
created_at: 2022-10-12T22:06:34Z
updated_at: 2022-10-12T22:06:34Z
author_association: OWNER
type: issue
body:
  Turns out this isn't necessary:

  https://github.com/simonw/datasette/blob/5aa359b86907d11b3ee601510775a85a90224da8/datasette/utils/__init__.py#L849-L858

  I can use this instead: https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.filesizeformat

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1841/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5Axrpb
title: check_visibility can now take multiple permissions into account
state: closed
created_at: 2022-10-14T00:06:04Z
updated_at: 2022-10-24T02:11:36Z
closed_at: 2022-10-24T02:11:36Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1842
type: pull
body:
  Refs #1829

  - [x] Fix table page
  - [x] Fix database page
  - [x] Fix query page
  - [x] Fix row page
  - [x] Tests
  - [x] Updated documentation for `check_visibility` method, to cover the new `permissions=` keyword argument

  Also this fix is currently only applied on the table page - needs to be applied on database, row and query pages too.

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1842.org.readthedocs.build/en/1842/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1842/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5T9-_J
title: Intermittent "Too many open files" error running tests
state: open
created_at: 2022-10-14T04:45:01Z
updated_at: 2022-12-17T22:02:41Z
author_association: OWNER
type: issue
state_reason: reopened
body:
  Partial stack trace from one of them:
  ```
  /Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/jinja2/loaders.py:200: in get_source
      f = open_if_exists(filename)
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

  filename = '/Users/simon/Dropbox/Development/datasette/datasette/templates/error.html', mode = 'rb'

      def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO]:
          """Returns a file descriptor for the filename if that file exists,
          otherwise ``None``.
          """
          if not os.path.isfile(filename):
              return None
      
  >       return open(filename, mode)
  E       OSError: [Errno 24] Too many open files: '/Users/simon/Dropbox/Development/datasette/datasette/templates/error.html'
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1843/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UBf6g
title: Update screenshots in documentation to match latest designs
state: closed
created_at: 2022-10-14T18:01:18Z
updated_at: 2022-10-14T23:51:46Z
closed_at: 2022-10-14T19:57:17Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://docs.datasette.io/en/0.62/full_text_search.html has this out-of-date screenshot:

  <img width="1191" alt="image" src="https://user-images.githubusercontent.com/9599/195911747-386f4cd2-5239-4c83-8e0c-072e6ae56ff6.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1844/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UD49p
title: Reconsider the Datasette first-run experience
state: open
created_at: 2022-10-15T22:21:31Z
updated_at: 2022-10-16T08:54:53Z
author_association: OWNER
type: issue
body:
  Had a really interesting conversation today about how hard it is to get from "I installed Datasette" to "I've done something useful with it": https://news.ycombinator.com/item?id=33216789#33218590

  Spending some time focusing on that first-run experience feels very worthwhile.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1845/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODFdgUs5UE0KQ
title: Feature: Support GitHub discussions
state: open
created_at: 2022-10-16T16:53:38Z
updated_at: 2022-10-16T16:53:38Z
author_association: CONTRIBUTOR
type: issue
body:
  Hi @simonw I've been a happy user of this tool.  Thank you for writing it and sharing it.

  I wanted to suggest a feature request to support  Discussions.  For example the VisiData project has discussions https://github.com/saulpw/visidata/discussions , and it would be useful if there was a way to pull that data into the database.

  However, I'm not offering a pull request.

reactions:
  {"url": "https://api.github.com/repos/dogsheep/github-to-sqlite/issues/77/reactions", "total_count": 2, "+1": 2, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5UQfze
title: Turn --flatten into a documented utility function
state: closed
created_at: 2022-10-18T17:43:36Z
updated_at: 2022-10-18T18:02:10Z
closed_at: 2022-10-18T18:00:40Z
author_association: OWNER
type: issue
state_reason: completed
body:
  The `--flatten` implementation isn't currently available to Python code - people have to roll their own implementation. Feedback from a conversation at DjangoCon.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/500/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5UQnNZ
title: Tests failing due to updated tabulate library
state: closed
created_at: 2022-10-18T18:07:52Z
updated_at: 2022-10-18T18:23:40Z
closed_at: 2022-10-18T18:23:40Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Failure here: https://github.com/simonw/sqlite-utils/actions/runs/3275786702/jobs/5391063221

  I figured out the problem:

  ```diff
  diff --git a/docs/cli-reference.rst b/docs/cli-reference.rst
  index b88e38a..82b4b6c 100644
  --- a/docs/cli-reference.rst
  +++ b/docs/cli-reference.rst
  @@ -112,11 +112,15 @@ See :ref:`cli_query`.
         --tsv                       Output TSV
         --no-headers                Omit CSV headers
         -t, --table                 Output as a formatted table
  -      --fmt TEXT                  Table format - one of fancy_grid, fancy_outline,
  -                                  github, grid, html, jira, latex, latex_booktabs,
  -                                  latex_longtable, latex_raw, mediawiki, moinmoin,
  -                                  orgtbl, pipe, plain, presto, pretty, psql, rst,
  -                                  simple, textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT                  Table format - one of asciidoc, double_grid,
  +                                  double_outline, fancy_grid, fancy_outline, github,
  +                                  grid, heavy_grid, heavy_outline, html, jira,
  +                                  latex, latex_booktabs, latex_longtable, latex_raw,
  +                                  mediawiki, mixed_grid, mixed_outline, moinmoin,
  +                                  orgtbl, outline, pipe, plain, presto, pretty,
  +                                  psql, rounded_grid, rounded_outline, rst, simple,
  +                                  simple_grid, simple_outline, textile, tsv,
  +                                  unsafehtml, youtrack
         --json-cols                 Detect JSON cols and output them as JSON, not
                                     escaped strings
         -r, --raw                   Raw output, first column of first row
  @@ -176,11 +180,15 @@ See :ref:`cli_memory`.
         --tsv                       Output TSV
         --no-headers                Omit CSV headers
         -t, --table                 Output as a formatted table
  -      --fmt TEXT                  Table format - one of fancy_grid, fancy_outline,
  -                                  github, grid, html, jira, latex, latex_booktabs,
  -                                  latex_longtable, latex_raw, mediawiki, moinmoin,
  -                                  orgtbl, pipe, plain, presto, pretty, psql, rst,
  -                                  simple, textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT                  Table format - one of asciidoc, double_grid,
  +                                  double_outline, fancy_grid, fancy_outline, github,
  +                                  grid, heavy_grid, heavy_outline, html, jira,
  +                                  latex, latex_booktabs, latex_longtable, latex_raw,
  +                                  mediawiki, mixed_grid, mixed_outline, moinmoin,
  +                                  orgtbl, outline, pipe, plain, presto, pretty,
  +                                  psql, rounded_grid, rounded_outline, rst, simple,
  +                                  simple_grid, simple_outline, textile, tsv,
  +                                  unsafehtml, youtrack
         --json-cols                 Detect JSON cols and output them as JSON, not
                                     escaped strings
         -r, --raw                   Raw output, first column of first row
  @@ -401,11 +409,14 @@ See :ref:`cli_search`.
         --tsv                  Output TSV
         --no-headers           Omit CSV headers
         -t, --table            Output as a formatted table
  -      --fmt TEXT             Table format - one of fancy_grid, fancy_outline,
  -                             github, grid, html, jira, latex, latex_booktabs,
  -                             latex_longtable, latex_raw, mediawiki, moinmoin,
  -                             orgtbl, pipe, plain, presto, pretty, psql, rst, simple,
  -                             textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT             Table format - one of asciidoc, double_grid,
  +                             double_outline, fancy_grid, fancy_outline, github,
  +                             grid, heavy_grid, heavy_outline, html, jira, latex,
  +                             latex_booktabs, latex_longtable, latex_raw, mediawiki,
  +                             mixed_grid, mixed_outline, moinmoin, orgtbl, outline,
  +                             pipe, plain, presto, pretty, psql, rounded_grid,
  +                             rounded_outline, rst, simple, simple_grid,
  +                             simple_outline, textile, tsv, unsafehtml, youtrack
         --json-cols            Detect JSON cols and output them as JSON, not escaped
                                strings
         --load-extension TEXT  Path to SQLite extension, with optional :entrypoint
  @@ -651,11 +662,14 @@ See :ref:`cli_tables`.
         --tsv                  Output TSV
         --no-headers           Omit CSV headers
         -t, --table            Output as a formatted table
  -      --fmt TEXT             Table format - one of fancy_grid, fancy_outline,
  -                             github, grid, html, jira, latex, latex_booktabs,
  -                             latex_longtable, latex_raw, mediawiki, moinmoin,
  -                             orgtbl, pipe, plain, presto, pretty, psql, rst, simple,
  -                             textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT             Table format - one of asciidoc, double_grid,
  +                             double_outline, fancy_grid, fancy_outline, github,
  +                             grid, heavy_grid, heavy_outline, html, jira, latex,
  +                             latex_booktabs, latex_longtable, latex_raw, mediawiki,
  +                             mixed_grid, mixed_outline, moinmoin, orgtbl, outline,
  +                             pipe, plain, presto, pretty, psql, rounded_grid,
  +                             rounded_outline, rst, simple, simple_grid,
  +                             simple_outline, textile, tsv, unsafehtml, youtrack
         --json-cols            Detect JSON cols and output them as JSON, not escaped
                                strings
         --columns              Include list of columns for each table
  @@ -689,11 +703,14 @@ See :ref:`cli_views`.
         --tsv                  Output TSV
         --no-headers           Omit CSV headers
         -t, --table            Output as a formatted table
  -      --fmt TEXT             Table format - one of fancy_grid, fancy_outline,
  -                             github, grid, html, jira, latex, latex_booktabs,
  -                             latex_longtable, latex_raw, mediawiki, moinmoin,
  -                             orgtbl, pipe, plain, presto, pretty, psql, rst, simple,
  -                             textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT             Table format - one of asciidoc, double_grid,
  +                             double_outline, fancy_grid, fancy_outline, github,
  +                             grid, heavy_grid, heavy_outline, html, jira, latex,
  +                             latex_booktabs, latex_longtable, latex_raw, mediawiki,
  +                             mixed_grid, mixed_outline, moinmoin, orgtbl, outline,
  +                             pipe, plain, presto, pretty, psql, rounded_grid,
  +                             rounded_outline, rst, simple, simple_grid,
  +                             simple_outline, textile, tsv, unsafehtml, youtrack
         --json-cols            Detect JSON cols and output them as JSON, not escaped
                                strings
         --columns              Include list of columns for each view
  @@ -732,11 +749,15 @@ See :ref:`cli_rows`.
         --tsv                       Output TSV
         --no-headers                Omit CSV headers
         -t, --table                 Output as a formatted table
  -      --fmt TEXT                  Table format - one of fancy_grid, fancy_outline,
  -                                  github, grid, html, jira, latex, latex_booktabs,
  -                                  latex_longtable, latex_raw, mediawiki, moinmoin,
  -                                  orgtbl, pipe, plain, presto, pretty, psql, rst,
  -                                  simple, textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT                  Table format - one of asciidoc, double_grid,
  +                                  double_outline, fancy_grid, fancy_outline, github,
  +                                  grid, heavy_grid, heavy_outline, html, jira,
  +                                  latex, latex_booktabs, latex_longtable, latex_raw,
  +                                  mediawiki, mixed_grid, mixed_outline, moinmoin,
  +                                  orgtbl, outline, pipe, plain, presto, pretty,
  +                                  psql, rounded_grid, rounded_outline, rst, simple,
  +                                  simple_grid, simple_outline, textile, tsv,
  +                                  unsafehtml, youtrack
         --json-cols                 Detect JSON cols and output them as JSON, not
                                     escaped strings
         --load-extension TEXT       Path to SQLite extension, with optional
  @@ -768,11 +789,14 @@ See :ref:`cli_triggers`.
         --tsv                  Output TSV
         --no-headers           Omit CSV headers
         -t, --table            Output as a formatted table
  -      --fmt TEXT             Table format - one of fancy_grid, fancy_outline,
  -                             github, grid, html, jira, latex, latex_booktabs,
  -                             latex_longtable, latex_raw, mediawiki, moinmoin,
  -                             orgtbl, pipe, plain, presto, pretty, psql, rst, simple,
  -                             textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT             Table format - one of asciidoc, double_grid,
  +                             double_outline, fancy_grid, fancy_outline, github,
  +                             grid, heavy_grid, heavy_outline, html, jira, latex,
  +                             latex_booktabs, latex_longtable, latex_raw, mediawiki,
  +                             mixed_grid, mixed_outline, moinmoin, orgtbl, outline,
  +                             pipe, plain, presto, pretty, psql, rounded_grid,
  +                             rounded_outline, rst, simple, simple_grid,
  +                             simple_outline, textile, tsv, unsafehtml, youtrack
         --json-cols            Detect JSON cols and output them as JSON, not escaped
                                strings
         --load-extension TEXT  Path to SQLite extension, with optional :entrypoint
  @@ -804,11 +828,14 @@ See :ref:`cli_indexes`.
         --tsv                  Output TSV
         --no-headers           Omit CSV headers
         -t, --table            Output as a formatted table
  -      --fmt TEXT             Table format - one of fancy_grid, fancy_outline,
  -                             github, grid, html, jira, latex, latex_booktabs,
  -                             latex_longtable, latex_raw, mediawiki, moinmoin,
  -                             orgtbl, pipe, plain, presto, pretty, psql, rst, simple,
  -                             textile, tsv, unsafehtml, youtrack
  +      --fmt TEXT             Table format - one of asciidoc, double_grid,
  +                             double_outline, fancy_grid, fancy_outline, github,
  +                             grid, heavy_grid, heavy_outline, html, jira, latex,
  +                             latex_booktabs, latex_longtable, latex_raw, mediawiki,
  +                             mixed_grid, mixed_outline, moinmoin, orgtbl, outline,
  +                             pipe, plain, presto, pretty, psql, rounded_grid,
  +                             rounded_outline, rst, simple, simple_grid,
  +                             simple_outline, textile, tsv, unsafehtml, youtrack
         --json-cols            Detect JSON cols and output them as JSON, not escaped
                                strings
         --load-extension TEXT  Path to SQLite extension, with optional :entrypoint
  diff --git a/docs/cli.rst b/docs/cli.rst
  index 8bc4176..1d67e88 100644
  --- a/docs/cli.rst
  +++ b/docs/cli.rst
  @@ -187,10 +187,15 @@ Available ``--fmt`` options are:
       cog.out("\n" + "\n".join('- ``{}``'.format(t) for t in tabulate.tabulate_formats) + "\n\n")
   .. ]]]
   
  +- ``asciidoc``
  +- ``double_grid``
  +- ``double_outline``
   - ``fancy_grid``
   - ``fancy_outline``
   - ``github``
   - ``grid``
  +- ``heavy_grid``
  +- ``heavy_outline``
   - ``html``
   - ``jira``
   - ``latex``
  @@ -198,15 +203,22 @@ Available ``--fmt`` options are:
   - ``latex_longtable``
   - ``latex_raw``
   - ``mediawiki``
  +- ``mixed_grid``
  +- ``mixed_outline``
   - ``moinmoin``
   - ``orgtbl``
  +- ``outline``
   - ``pipe``
   - ``plain``
   - ``presto``
   - ``pretty``
   - ``psql``
  +- ``rounded_grid``
  +- ``rounded_outline``
   - ``rst``
   - ``simple``
  +- ``simple_grid``
  +- ``simple_outline``
   - ``textile``
   - ``tsv``
   - ``unsafehtml``
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/501/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UpFNR
title: Both _local_metadata and _metadata_local?
state: closed
created_at: 2022-10-24T01:43:08Z
updated_at: 2022-10-24T01:53:13Z
closed_at: 2022-10-24T01:53:13Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Spotted this in the debugger against the `datasette` object while running tests (`pytest -k test_permissions_cascade` to be exact):

  ```
  (Pdb) [p for p in dir(self) if p.startswith('_') and '__' not in p]
  ['_actor', '_asset_urls', '_connected_databases', '_crumb_items', '_local_metadata', '_metadata', '_metadata_local', '_metadata_recursive_update', '_permission_checks', '_plugins', '_prepare_connection', '_refresh_schemas', '_refresh_schemas_lock', '_register_custom_units', '_register_renderers', '_root_token', '_routes', '_secret', '_settings', '_show_messages', '_startup_hook_calculation', '_startup_hook_fired', '_startup_invoked', '_threads', '_versions', '_write_messages_to_response']
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1847/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UpN0j
title: Private database page should show padlock on every table
state: closed
created_at: 2022-10-24T02:28:38Z
updated_at: 2022-10-24T02:50:29Z
closed_at: 2022-10-24T02:42:34Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Following:
  - #1829

  https://latest.datasette.io/_internal looks like this:

  <img width="741" alt="image" src="https://user-images.githubusercontent.com/9599/197436797-815ab54f-33d9-4f49-981f-628ce4e9013c.png">

  But those queries and tables are private too, and should also show the padlock icon.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1848/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UpiVO
title: NoneType' object has no attribute 'actor'
state: closed
created_at: 2022-10-24T04:02:15Z
updated_at: 2022-10-26T21:13:40Z
closed_at: 2022-10-26T21:13:40Z
author_association: OWNER
type: issue
state_reason: completed
body:
  ```
    File "/usr/local/lib/python3.10/site-packages/datasette/templates/_crumbs.html", line 3, in template
      {% set items=crumb_items(request=request, database=database, table=table) %}
    File "jinja2/async_utils.py", line 65, in auto_await
      return await t.cast("t.Awaitable[V]", value)
    File "datasette/app.py", line 638, in _crumb_items
      actor=request.actor, action="view-instance", default=True
  ```
  From Sentry.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1849/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UutJ7
title: Write API in Datasette core
state: closed
created_at: 2022-10-24T22:13:24Z
updated_at: 2022-11-29T20:11:20Z
closed_at: 2022-11-29T20:11:20Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I need this for Datasette Cloud, and in thinking it through I realized that it's really time Datasette grew a default write API as well.

  I'm going to mostly model this off `sqlite-utils`, since I've spent a bunch of time iterating on a pseudo-JSON API for that over the past few years (piping JSON to stdin etc).

  I want this for Datasette 1.0. I'm going to be building it in the new [1.0-dev](https://github.com/simonw/datasette/tree/1.0-dev) branch, which is automatically deployed to https://latest-1-0-dev.datasette.io/ running on Cloud Run.

  API features to build:

  - [x] #1852
    - [x] #1856
    - [x] #1857
    - [x] #1858
    - [x] #1859
  - [x] #1871
    - [x] #1888
  - [x] #1868
  - [x] #1851
  - [x] #1863
  - [x] #1864
  - [x] #1866
  - [x] https://github.com/simonw/datasette/issues/1882
  - [x] #1862
  - [x] #1874
    - [x] https://github.com/simonw/datasette/issues/1887
  - [x] #1877

  Bumped to later on:

  - #1855
  - #1878
  - #1873
  - #1875
  - Make sure CORS works
  - https://github.com/simonw/datasette/issues/1889
  - Alter a table - `sqlite-utils transform` style (more powerful than straight ALTER)
  - Execute SQL against a write connection
  - Maybe even multiple write SQL statements bundled in a single transaction
  - https://github.com/simonw/datasette/issues/1867

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1850/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5UuwzO
title: API to insert a single record into an existing table
state: closed
created_at: 2022-10-24T22:24:21Z
updated_at: 2022-11-15T19:59:18Z
closed_at: 2022-10-28T00:59:25Z
author_association: OWNER
body: Controlled by a new `insert-row` permission.
type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1851/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Uuynf
title: Default API token authentication mechanism
state: closed
created_at: 2022-10-24T22:31:07Z
updated_at: 2022-11-15T19:57:00Z
closed_at: 2022-10-26T02:19:54Z
author_association: OWNER
type: issue
state_reason: completed
body:
  API authentication will be via `Authorization: Bearer XXX` request headers.

  I'm inclined to add a default token mechanism to Datasette based on tokens that are signed with the `DATASETTE_SECRET`. Maybe the root user can access `/-/create-token` which provides a UI for generating a time-limited signed token? Could also have a `datasette token` command for creating such tokens at the command-line.

  Plugins can then define alternative ways of creating tokens, such as the existing https://datasette.io/plugins/datasette-auth-tokens plugin.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1850#issuecomment-1289706439_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1852/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Uz_gD
title: Upgrade Datasette Docker to Python 3.11
state: closed
created_at: 2022-10-25T18:44:31Z
updated_at: 2022-10-25T19:28:56Z
closed_at: 2022-10-25T19:05:16Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Related:
  - #1768

  I think this base image looks right: [3.11.0-slim-bullseye](https://hub.docker.com/layers/library/python/3.11.0-slim-bullseye/images/sha256-244c0b0e6e7608a16f87382fc8a5ef3c330d042113a9a7b6fc15a95360181651?context=explore)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1853/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5U0JBW
title: Fix tests for Python 3.11
state: closed
created_at: 2022-10-25T19:20:31Z
updated_at: 2022-10-25T19:23:47Z
closed_at: 2022-10-25T19:23:47Z
author_association: OWNER
type: issue
state_reason: completed
body:
  The way errors are represented has changed: https://github.com/simonw/sqlite-utils/actions/runs/3323588047/jobs/5494127154
  ```
  _________________________ test_query_invalid_function __________________________

  db_path = '/tmp/pytest-of-runner/pytest-0/test_query_invalid_function0/test.db'

      def test_query_invalid_function(db_path):
          result = CliRunner().invoke(
              cli.cli, [db_path, "select bad()", "--functions", "def invalid_python"]
          )
          assert result.exit_code == 1
  >       assert (
              result.output.strip()
              == "Error: Error in functions definition: invalid syntax (<string>, line 1)"
          )
  E       AssertionError: assert 'Error: Error...ing>, line 1)' == 'Error: Error...ing>, line 1)'
  E         - Error: Error in functions definition: invalid syntax (<string>, line 1)
  E         ?                                       ^^^^^^  ^^^^^^
  E         + Error: Error in functions definition: expected '(' (<string>, line 1)
  E         ?                                       ^^^^^^^  ^^^
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/502/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U0Ni3
title: Flaky test: test_serve_localhost_http
state: closed
created_at: 2022-10-25T19:37:35Z
updated_at: 2022-10-25T19:53:02Z
closed_at: 2022-10-25T19:53:02Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Failing on Python 3.10 at the moment: https://github.com/simonw/datasette/actions/runs/3323629947/jobs/5494340302

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1854/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5U0UR-
title: test_recreate failing on Windows Python 3.11
state: closed
created_at: 2022-10-25T20:01:41Z
updated_at: 2022-10-25T20:47:34Z
closed_at: 2022-10-25T20:45:43Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://github.com/simonw/sqlite-utils/actions/runs/3323672128/jobs/5494726927

  Related:
  - #502

  ```
  FAILED tests/test_recreate.py::test_recreate[True-True] - 
    PermissionError: [WinError 32] The process cannot access the file because it is being used by another process:
    'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\pytest-of-runneradmin\\pytest-0\\test_recreate_True_True_0\\data.db'
  FAILED tests/test_recreate.py::test_recreate[False-True] - 
    PermissionError: [WinError 32] The process cannot access the file because it is being used by another process:
    'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\pytest-of-runneradmin\\pytest-0\\test_recreate_False_True_0\\data.db'
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/503/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5U0lDI
title: db.close() method, calling db.conn.close()
state: closed
created_at: 2022-10-25T20:50:50Z
updated_at: 2022-10-25T21:00:29Z
closed_at: 2022-10-25T20:57:47Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I ended up needing to use `db.conn.close()` to fix this issue:
  - #503

  I think `.close()` should be a method on `Database` itself.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/504/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5U1Au6
title: Release sqlite-utils 3.30
state: closed
created_at: 2022-10-25T22:20:05Z
updated_at: 2022-10-25T22:41:26Z
closed_at: 2022-10-25T22:41:16Z
author_association: OWNER
body: https://github.com/simonw/sqlite-utils/compare/3.29...defa2974c6d3abc19be28d6b319649b8028dc966
type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/505/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U1mKZ
title: `datasette create-token` ability to create tokens with a reduced set of permissions
state: closed
created_at: 2022-10-26T02:20:52Z
updated_at: 2022-12-14T01:24:49Z
closed_at: 2022-12-13T05:20:24Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Initial design ideas: https://github.com/simonw/datasette/issues/1852#issuecomment-1289733483

  > Token design concept:
  > 
  > ```json
  > {
  >     "t": {
  >         "a": ["ir", "ur", "dr"],
  >         "d": {
  >             "fixtures": ["ir", "ur", "dr"]
  >         },
  >         "t": {
  >             "fixtures": {
  >                 "searchable": ["ir"]
  >             }
  >         }
  >     }
  > }
  > ```
  > 
  > That JSON would be minified and signed.
  > 
  > Minified version of the above looks like this (101 characters):
  > 
  > `{"t":{"a":["ir","ur","dr"],"d":{"fixtures":["ir","ur","dr"]},"t":{"fixtures":{"searchable":["ir"]}}}}`
  > 
  > The `"t"` key shows this is a token that as a default API key.
  > 
  > `"a"` means "all" - these are permissions that have been granted on all tables and databases.
  > 
  > `"d"` means "databases" - this is a way to set permissions for all tables in a specific database.
  > 
  > `"t"` means "tables" - this lets you set permissions at a finely grained table level.
  > 
  > Then the permissions themselves are two character codes which are shortened versions - so:
  > 
  > * `ir` = `insert-row`
  > * `ur` = `update-row`
  > * `dr` = `delete-row`

  ## Remaining tasks

  - [x] Add these options to the `datasette create-token` command
  - [x] Tests for `datasette create-token` options
  - [x] Documentation for those options at https://docs.datasette.io/en/latest/authentication.html#datasette-create-token
  - [x] A way to handle permissions that don't have known abbreviations (permissions added by plugins). Probably need to solve the plugin permission registration problem as part of that
  - [x] Stop hard-coding names of actions in the `permission_allowed_actor_restrictions` function

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1855/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U1mK6
title: allow_signed_tokens setting for disabling API signed token mechanism
state: closed
created_at: 2022-10-26T02:20:55Z
updated_at: 2022-11-15T19:57:05Z
closed_at: 2022-10-26T02:58:35Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Had some design thoughts here: https://github.com/simonw/datasette/issues/1852#issuecomment-1291272280

  I liked this option the most:

      --setting allow_create_tokens off

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1856/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U1o7U
title: Prevent API tokens from using /-/create-token to create more tokens
state: closed
created_at: 2022-10-26T02:38:09Z
updated_at: 2022-11-15T19:57:11Z
closed_at: 2022-10-26T02:57:26Z
author_association: OWNER
type: issue
state_reason: completed
body:
  > It strikes me that users should NOT be able to use a token to create additional tokens.
  >
  > The current design actually does allow that, since the `dstok_` Bearer token can be used to authenticate calls to the `/-/create-token` page.
  >
  > So I think I need a mechanism whereby that page can only allow access to users authenticated by cookie.
  > 
  > Not obvious how to do that though, since Datasette's authentication actor system is designed to abstract that detail away!

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1850#issuecomment-1291417100_

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1857/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U1tN-
title: `max_signed_tokens_ttl` setting for a maximum duration on API tokens
state: closed
created_at: 2022-10-26T03:05:53Z
updated_at: 2022-11-15T19:58:52Z
closed_at: 2022-10-27T03:15:05Z
author_association: OWNER
type: issue
state_reason: completed
body:
  It's currently possible to use `/-/create-token` to create a token that lasts forever.

  Some administrators may wish to have a maximum expiry instead. I should support that with a setting.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1858/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U1uUW
title: datasette create-token CLI command
state: closed
created_at: 2022-10-26T03:12:59Z
updated_at: 2022-11-15T19:59:00Z
closed_at: 2022-10-26T04:31:39Z
author_association: OWNER
body: The CLI equivalent of the `/-/create-token` page.
type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1859/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U5kic
title: SQL query field can't begin by a comment
state: closed
created_at: 2022-10-26T16:55:31Z
updated_at: 2022-10-27T18:57:37Z
closed_at: 2022-10-27T04:21:40Z
author_association: NONE
type: issue
state_reason: completed
body:
  ![image](https://user-images.githubusercontent.com/562352/198085197-f26fcd61-4dac-4ca4-a346-e70f88a30ecc.png)

  SQL comments are **very** useful to explain the meaning of the query. It's currently impossible to put it at the beginning of the field as seen on the screen capture: it leads to an error: `Statement must be a SELECT`.

  It would be great to make it possible because:
  * as the request is the title of the page:
    * it eases the search with search engines
    * it eases the search in the browsers' url field
  * it acts as a kind of title: the global meaning of the query is immediately understandable
  * some tools, such as Slack, are shortening long URLs and displaying the beginning of the URLs (eg. `https://example.org/products?sql=select+%28length%28data_quality_errors_ta[...]+%21%3D+%22%22+group+by+NB_of_issues+order+by+NB_of_issues+desc+limit+200`)

  Beginning a query with a comment is possible with SQLite.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1860/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U73pB
title: request.headers.get("Content-Type") fails
state: open
created_at: 2022-10-27T03:39:12Z
updated_at: 2022-10-27T03:39:12Z
author_association: OWNER
type: issue
body:
  Turns out this is case-sensitive, needs to be:

      request.headers.get("content-type") != "application/json"

  That's not great usability. It should be case insensitive.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1861/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U7_FW
title: Create a new table from one or more records, `sqlite-utils` style
state: closed
created_at: 2022-10-27T04:25:02Z
updated_at: 2022-11-15T19:59:47Z
closed_at: 2022-11-15T06:42:09Z
author_association: OWNER
type: issue
state_reason: completed
body:
  It's interesting to also think about what the form-based UI for this could look like - since that would involve users creating new columns of different types on the fly.

  Will need the `create-table` permission.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1862/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U8Dh6
title: Update a single record in an existing table
state: closed
created_at: 2022-10-27T04:53:17Z
updated_at: 2022-11-29T18:08:53Z
closed_at: 2022-11-29T18:06:37Z
author_association: OWNER
type: issue
state_reason: completed
body:
  API design:

  ```
  POST /db/table/row-pks/-/update
  {
     "field": "updated_value"
  }
  ```
  Only the fields that you pass will be updated.

  Maybe this is the wrong design though? The design for insert currently looks like this:

  - https://github.com/simonw/datasette/issues/1851#issuecomment-1294224185

  ```
  POST /db/table/-/insert
  Authorization: Bearer xxx
  Content-Type: application/json
  {
    "row": {
      "id": 1,
      "name": "New name"
    }
  }
  ```
  I could use the same format for `/-/update`, but in this case the API doesn't require you to pass every field so `"row"` doesn't seem like the right key.

  I think I'll go with this:

  ```
  POST /db/table/1/-/update
  Authorization: Bearer xxx
  Content-Type: application/json
  {
    "update": {
      "name": "New name"
    }
  }
  ```
  The benefit of having an `"update"` key is that it allows me to use other keys in the future. Maybe a `"alter": true` key to indicate that new columns should be added if they are missing.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1863/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U8Dib
title: Delete a single record from an existing table
state: closed
created_at: 2022-10-27T04:53:22Z
updated_at: 2022-11-29T18:54:04Z
closed_at: 2022-11-29T18:54:04Z
author_association: OWNER
type: issue
state_reason: completed
body:
  API design:
  ```
  POST /db/table/row-pks/-/delete
  Or...
  DELETE /db/table/row-pks/-/delete
  ```
  I'm just going to do `POST` for the moment, like I did here:
  - #1874

  Permission: `delete-row`

  Still needed:

  - [ ] Tests for rowid tables
  - [ ] Tests for compound primary keys

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1864/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U-i6f
title: Stop syncing main to master
state: closed
created_at: 2022-10-27T13:55:38Z
updated_at: 2022-10-27T13:58:27Z
closed_at: 2022-10-27T13:56:13Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I think it's been long enough now that I can drop the code that syncs the main branch to master.

  I originally added this for people who might be using `datasette publish ... --branch master` - which might only have been me anyway!

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1865/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5U_w6F
title: API for bulk inserting records into a table
state: closed
created_at: 2022-10-27T17:19:25Z
updated_at: 2022-11-15T19:59:34Z
closed_at: 2022-10-30T06:04:07Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Similar to https://github.com/simonw/datasette-insert/blob/0.8/README.md#inserting-data-and-creating-tables

  I expect this to become by far the most common way that data gets into a Datasette instance - more so than the individual row API in:
  - #1851 

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1866/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VAEEO
title: /db/table/-/rename API (also allows atomic replace)
state: open
created_at: 2022-10-27T18:13:23Z
updated_at: 2023-01-09T15:34:12Z
author_association: OWNER
type: issue
body:
  > There's one catch with batched inserts: if your CLI tool fails half way through you could end up with a partially populated table - since a bunch of batches will have succeeded first.
  >
  > ...
  >
  > If people care about that kind of thing they could always push all of their inserts to a table called `_tablename` and then atomically rename that once they've uploaded all of the data (assuming I provide an atomic-rename-this-table mechanism).

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1866#issuecomment-1293893789_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1867/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VAgPt
title: Design URLs for the write API
state: closed
created_at: 2022-10-27T19:55:30Z
updated_at: 2022-11-15T19:59:14Z
closed_at: 2022-10-27T20:07:01Z
author_association: OWNER
type: issue
state_reason: completed
body:
  My original design for this issue:
  - #1851

  Was `POST /db/table` with JSON of `{"insert": {...}}`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1868/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VAuak
title: Release 0.63
state: closed
created_at: 2022-10-27T20:53:01Z
updated_at: 2022-10-27T22:24:38Z
closed_at: 2022-10-27T22:11:33Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Most of the release notes are already written:
  - https://github.com/simonw/datasette/releases/tag/0.63a0
  - https://github.com/simonw/datasette/releases/tag/0.63a1

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1869/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5BtJNn
title: don't use immutable=1, only mode=ro
state: open
created_at: 2022-10-27T23:33:04Z
updated_at: 2023-10-03T19:12:37Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1870
type: pull
body:
  Opening db files in immutable mode sometimes leads to the file being mutated, which causes duplication in the docker image layers: see #1836, #1480

  That this happens in "immutable" mode is surprising, because the sqlite docs say that setting this should open the database as read only. 

  https://www.sqlite.org/c3ref/open.html

  > immutable: The immutable parameter is a boolean query parameter that indicates that the database file is stored on read-only media. When immutable is set, SQLite assumes that the database file cannot be changed, even by a process with higher privilege, and so the database is opened read-only and all locking and change detection is disabled. Caution: Setting the immutable property on a database file that does in fact change can result in incorrect query results and/or [SQLITE_CORRUPT](https://www.sqlite.org/rescode.html#corrupt) errors. See also: [SQLITE_IOCAP_IMMUTABLE](https://www.sqlite.org/c3ref/c_iocap_atomic.html).

  Perhaps this is a bug in sqlite?



  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1870.org.readthedocs.build/en/1870/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1870/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VEsbV
title: API explorer tool
state: closed
created_at: 2022-10-28T13:49:11Z
updated_at: 2022-11-15T19:59:05Z
closed_at: 2022-11-14T04:59:59Z
author_association: OWNER
type: issue
state_reason: completed
body:
  The API will be much easier to develop if there's a page that helps you execute JSON POSTs against it.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1871/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VJhiU
title: SITE-BUSTING ERROR: "render_template() called before await ds.invoke_startup()"
state: closed
created_at: 2022-10-30T02:28:39Z
updated_at: 2022-10-30T06:26:01Z
closed_at: 2022-10-30T06:26:01Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  1. My https://list.saferdisinfectants.org/disinfectants/listN page (linked from https://SaferDisinfectants.org ) has been running beautifully for a year and a half, including a GitHub Actions workflow that's been routinely updating the database.

  2. I received a recent report that the list page is down. I don't know when it went down, but the content is replaced with: "render_template() called before await ds.invoke_startup()"

  3. The local datasette repo runs without incident.

  4. The site is hosted on vercel, linked to my github repo. Perhaps  some vercel changes were made, but not by anyone on our side. Here is a screenshot of the current project settings:

  <img width="877" alt="Screen Shot 2022-10-29 at 9 23 30 PM" src="https://user-images.githubusercontent.com/192568/198859474-341a5504-88b8-452d-bd06-e988cbe75e6c.png">

  Here a screenshot of the latest deployment status:
  <img width="1351" alt="Screen Shot 2022-10-29 at 10 19 21 PM" src="https://user-images.githubusercontent.com/192568/198859641-ad3d99ba-a41d-4b98-88f6-e3a01fe9f238.png">

  This is my repository:
  https://github.com/mroswell/list-N
  (I notice: datasette==0.59 in my requirements.txt file)

  Because it's been long while since I actively worked on this or any other datasette project, I forget a lot of what I knew at one point. Perhaps some configuration file could be missing? Or perhaps I just need to know the right incantation to add to that vercel settings page. 

  Help is welcome as the nonprofit org is soon hosting its annual conference, and we'd love to have the page working again.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1872/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VJyrt
title: Ensure insert API has good tests for rowid and compound primark key tables
state: open
created_at: 2022-10-30T06:22:17Z
updated_at: 2022-12-13T05:29:08Z
author_association: OWNER
type: issue
state_reason: reopened
body:
  Following:
  - #1866

  I need to design and implement various edge-cases or primary keys:

  - Table without an auto-incrementing primary key
  - Table with compound primary keys
  - Table with just a `rowid`

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1873/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5VLULk
title: Make `cursor.rowcount` accessible (wontfix)
state: closed
created_at: 2022-10-30T21:51:55Z
updated_at: 2022-11-01T17:37:47Z
closed_at: 2022-11-01T17:37:13Z
author_association: OWNER
type: issue
state_reason: completed
body:
  In building this Datasette feature on top of `sqlite-utils` I thought it might be useful to expose the number of rows that had been affected by a bulk insert or update - the `cursor.rowcount`:

  - https://github.com/simonw/datasette/issues/1866

  This isn't currently exposed by `sqlite-utils`.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/506/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VLUXF
title: API to drop a table
state: closed
created_at: 2022-10-30T21:55:11Z
updated_at: 2022-11-15T19:59:53Z
closed_at: 2022-11-14T05:45:06Z
author_association: OWNER
body:
  `POST /db/table/-/drop`

  Require `drop-table` permission.

type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1874/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5VQQdv
title: conn.execute: UnicodeEncodeError: 'utf-8' codec can't encode character
state: closed
created_at: 2022-10-31T18:49:51Z
updated_at: 2022-11-01T00:40:17Z
closed_at: 2022-11-01T00:40:16Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  I'm not really sure what caused this and it happened in the middle of my program (after running for 35775 seconds).

  ```
  Extracting metadata 49.9% (chunk 9893 of 19831)
  ...
    File "/home/xk/.local/lib/python3.10/site-packages/xklb/fs_extract.py", line 90, in extract_chunk
      args.db["media"].insert_all(utils.list_dict_filter_bool(media), pk="path", alter=True, replace=True)
    File "/home/xk/.local/lib/python3.10/site-packages/sqlite_utils/db.py", line 3107, in insert_all
      self.insert_chunk(
    File "/home/xk/.local/lib/python3.10/site-packages/sqlite_utils/db.py", line 2872, in insert_chunk
      result = self.db.execute(query, params)
    File "/home/xk/.local/lib/python3.10/site-packages/sqlite_utils/db.py", line 483, in execute
      return self.conn.execute(sql, parameters)
  UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 62: surrogates not allowed
  ```

  This might be relevant: https://stackoverflow.com/questions/31898353/python-cant-encode-with-surrogateescape

  I'm going to try re-running with 

  ```py
      def execute(
          self, sql: str, parameters: Optional[Union[Iterable, dict]] = None
      ) -> sqlite3.Cursor:
          """
          Execute SQL query and return a ``sqlite3.Cursor``.

          :param sql: SQL query to execute
          :param parameters: Parameters to use in that query - an iterable for ``where id = ?``
            parameters, or a dictionary for ``where id = :id``
          """
          try:
              if self._tracer:
                  self._tracer(sql, parameters)
              if parameters is not None:
                  return self.conn.execute(sql, parameters)
              else:
                  return self.conn.execute(sql)
          except UnicodeEncodeError:
              sql = sql.encode('utf-8', 'surrogatepass').decode('utf-8')
              if parameters is not None:
                  parameters = parameters.encode('utf-8', 'surrogatepass').decode('utf-8')
              return self.execute(sql, parameters)
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/507/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOCGYnMM5B6_6K
title: Allow surrogates in parameters
state: closed
created_at: 2022-10-31T22:11:49Z
updated_at: 2022-11-17T15:11:16Z
closed_at: 2022-10-31T22:55:36Z
author_association: CONTRIBUTOR
pull_request: simonw/sqlite-utils/pulls/508
type: pull
body:
  closes #507

  https://dwheeler.com/essays/fixing-unix-linux-filenames.html

  <!-- readthedocs-preview sqlite-utils start -->
  ----
  :books: Documentation preview :books:: https://sqlite-utils--508.org.readthedocs.build/en/508/

  <!-- readthedocs-preview sqlite-utils end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/508/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VSDub
title: Figure out design for JSON errors (consider RFC 7807)
state: open
created_at: 2022-11-01T03:14:15Z
updated_at: 2022-12-13T05:29:08Z
author_association: OWNER
type: issue
body:
  https://datatracker.ietf.org/doc/draft-ietf-httpapi-rfc7807bis/ is a brand new standard.

  Since I need a neat, predictable format for my JSON errors, maybe I should use this one?

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1875/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VV1XH
title: SQL query should wrap on SQL interrupted screen
state: closed
created_at: 2022-11-01T17:14:01Z
updated_at: 2022-11-01T17:22:33Z
closed_at: 2022-11-01T17:22:33Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Just saw this:

  <img width="1197" alt="CleanShot 2022-11-01 at 10 12 16@2x" src="https://user-images.githubusercontent.com/9599/199294909-df6fcb3b-40d0-4444-8a92-a7a358a28d86.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1876/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VWsYO
title: Refactor and tidy up final write API code
state: closed
created_at: 2022-11-01T20:00:11Z
updated_at: 2022-11-29T19:44:16Z
closed_at: 2022-11-29T19:44:07Z
author_association: OWNER
type: issue
state_reason: completed
body:
  - `views/table.py` has got a bit too big - I think the write classes should be pulled out into a separate module.
  - [x] There's duplicate logic for deciding if the table and database exist and checking permissions

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1877/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VWsuI
title: /db/table/-/upsert API
state: closed
created_at: 2022-11-01T20:01:18Z
updated_at: 2022-12-08T01:12:18Z
closed_at: 2022-12-08T01:12:17Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Equivalent to `sqlite-utils upsert`: https://sqlite-utils.datasette.io/en/stable/python-api.html#upserting-data

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1878/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VWyfN
title: Make it easier to fix URL proxy problems
state: open
created_at: 2022-11-01T20:19:23Z
updated_at: 2022-11-01T20:33:52Z
author_association: OWNER
type: issue
body:
  This came up on Discord again today: figuring out how to run Datasette behind a proxy that might hide the incoming Host: header (and strip HTTPS) is really hard!

  https://discord.com/channels/823971286308356157/823971286941302908/1037012475322847263

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1879/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5VYFdn
title: `sqlite-utils transform` breaks DEFAULT string values and STRFTIME()
state: closed
created_at: 2022-11-02T02:32:23Z
updated_at: 2023-05-08T21:13:38Z
closed_at: 2023-05-08T21:13:38Z
author_association: NONE
type: issue
state_reason: completed
body:
  Very nice library! Our team found sqlite-utils through @simonw's [comment on the "Simple declarative schema migration for SQLite" article](https://news.ycombinator.com/item?id=31249823), and we were excited to use it, but unfortunately `sqlite-utils transform` seems to break our DB. 

  Running `sqlite-utils transform` to modify a column mangles their DEFAULT values:

  - Default string values are wrapped in extra single quotes
  - Function expressions such as [`STRFTIME()`](https://www.sqlite.org/lang_datefunc.html) are turned into strings!

  ------

  Here are steps to reproduce:

  **Original database**

  ```
  $ sqlite3 test.db << EOF
  CREATE TABLE mytable (
      col1 TEXT DEFAULT 'foo',
      col2 TEXT DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))
  )
  EOF

  $ sqlite3 test.db "SELECT sql FROM sqlite_master WHERE name = 'mytable';"
  CREATE TABLE mytable (
      col1 TEXT DEFAULT 'foo',
      col2 TEXT DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))
  )
  ```

  **Modified database after sqlite-utils**

  ```
  $ sqlite3 test.db "INSERT INTO mytable DEFAULT VALUES; SELECT * FROM mytable;"
  foo|2022-11-02 02:26:58.038

  $ sqlite-utils transform test.db mytable --rename col1 renamedcol1

  $ sqlite3 test.db "SELECT sql FROM sqlite_master WHERE name = 'mytable';"
  CREATE TABLE "mytable" (
     [renamedcol1] TEXT DEFAULT '''foo''',
     [col2] TEXT DEFAULT 'STRFTIME(''%Y-%m-%d %H:%M:%f'', ''NOW'')'
  )

  $ sqlite3 test.db "INSERT INTO mytable DEFAULT VALUES; SELECT * FROM mytable;"
  foo|2022-11-02 02:26:58.038
  'foo'|STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')
  ```

  (Related: #336)

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/509/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VcqOf
title: Datasette with many and large databases > Memory use
state: open
created_at: 2022-11-02T18:10:27Z
updated_at: 2022-11-16T17:50:29Z
author_association: NONE
type: issue
body:
  > Datasette maintains an in-memory SQLite database with details of the the databases, tables and columns for all of the attached databases.

  The above is from the docs ^. There's two problems here - the number of datasette "instances" in a single server/VM and the size of the database itself. We want the **opposite** of in-memory, including what happens on SQLlite - documented in https://www.sqlite.org/inmemorydb.html

  From the context in https://github.com/simonw/datasette/issues/1150 - does it mean datasette is memory-bound to the size of the dataset - which might be a deal-breaker for many large-scale use cases?

  In an extreme case - let's say a single server had 100 SQLlite databases, which would enable 100 "instances" of datasette to run, one per client (e.g. in a SaaS multi-tenant environment). How could we achieve all these goals:

  1. Allow any _one_ of these 100 databases to grow to say 2Tb in size 
  2. Have one datasette instance, which connects to 1 of the 100 instances, based on incoming credentials/tenant ID
  3. Minimize memory use entirely - both by datasette and SQLlite, such that almost all operations are executed in real-time on-disk with little to no memory consumption per-tenant, or per-database.

  Any ideas appreciated - we're looking to use this in a SaaS type of setting - many instances, single server.

  @simonw great work on datasette, in general! Possibly related to https://github.com/simonw/datasette/issues/1480 but we don't want use any kind of serverless infra - this is a long-running VM/server.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1880/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Veosd
title: Tool for simulating permission checks against actors
state: closed
created_at: 2022-11-03T04:43:20Z
updated_at: 2022-12-09T01:38:21Z
closed_at: 2022-11-04T00:13:05Z
author_association: OWNER
type: issue
state_reason: completed
body:
  In working on this issue:
  - #1855

  I realized that if I'm going to make actors more complicated (the proposed `_r` key for additional restricted permissions) I really need an interactive tool for simulating these checks, similar to the https://latest.datasette.io/-/allow-debug tool.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1881/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5VhwIX
title: Cannot enable FTS5 despite it being available
state: closed
created_at: 2022-11-03T16:03:49Z
updated_at: 2022-11-18T18:37:52Z
closed_at: 2022-11-17T10:36:28Z
author_association: NONE
type: issue
state_reason: completed
body:
  When I do `sqlite-utils enable-fts my.db table_name column_name` (with or without `--fts5`), I get an FTS4 virtual table instead of the expected FTS5.

  FTS5 is however available and Python/SQLite versions do not seem to be the issue. I can manually create the FTS5 virtual table, and then Datasette also works with it from this same Python environment.

  `>>> sqlite3.version`
  `2.6.0`
  `>>> sqlite3.sqlite_version`
  `3.39.4`

  `PRAGMA compile_options;` includes `ENABLE_FTS5`.

  `sqlite-utils, version 3.30`.

  Any ideas what's happening and how to fix?

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/510/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VjNsE
title: `/db/-/create` API for creating tables
state: closed
created_at: 2022-11-03T21:44:32Z
updated_at: 2022-11-15T19:59:43Z
closed_at: 2022-11-15T06:00:41Z
author_association: OWNER
type: issue
state_reason: completed
body:
  >  It really feels like this should be accompanied by a `/db/-/create` API for creating tables. I had to add that to `sqlite-utils` eventually (initially it only supported creating by passing in an example document):
  >
  > https://sqlite-utils.datasette.io/en/stable/cli.html#cli-create-table

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1862#issuecomment-1299073433_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1882/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Vlly_
title: Errors when using table filters behind a proxy
state: closed
created_at: 2022-11-04T11:18:47Z
updated_at: 2022-11-11T09:20:22Z
closed_at: 2022-11-11T06:54:58Z
author_association: NONE
type: issue
state_reason: completed
body:
  Using datasette==0.63 table filters do not respect the `base_url` setting as described [here](https://docs.datasette.io/en/stable/deploying.html#running-datasette-behind-a-proxy)

  To reproduce, go to:
  https://datasette-apache-proxy-demo.datasette.io/prefix/fixtures/binary_data

  Then use the table filter buttons.
  The `/prefix/` is dropped, resulting in URL not found:
  https://datasette-apache-proxy-demo.datasette.io/fixtures/binary_data?_sort=rowid&rowid__exact=1

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1883/reactions", "total_count": 1, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 1}


node_id: I_kwDOCGYnMM5Vn9qi
title: [insert_all, upsert_all] IntegrityError: constraint failed
state: closed
created_at: 2022-11-04T19:21:48Z
updated_at: 2022-11-04T22:59:54Z
closed_at: 2022-11-04T22:54:09Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  My understand is that `INSERT OR IGNORE` will ignore when inserts would cause duplicate keys so I'm not sure exactly why the error is raised from `sqlite3`.

  ```
  import argparse
  from pathlib import Path

  from xklb import db, utils
  from xklb.utils import log


  def parse_args() -> argparse.Namespace:
      parser = argparse.ArgumentParser()
      parser.add_argument("database")
      parser.add_argument("dbs", nargs="*")
      parser.add_argument("--upsert")
      parser.add_argument("--db", "-db", help=argparse.SUPPRESS)
      parser.add_argument("--verbose", "-v", action="count", default=0)
      args = parser.parse_args()

      if args.db:
          args.database = args.db
      Path(args.database).touch()
      args.db = db.connect(args)
      log.info(utils.dict_filter_bool(args.__dict__))

      return args


  def merge_db(args, source_db):
      source_db = str(Path(source_db).resolve())

      s_db = db.connect(argparse.Namespace(database=source_db, verbose=args.verbose))
      for table in [s for s in s_db.table_names() if not "_fts" in s and not s.startswith("sqlite_")]:
          log.info("[%s]: %s", source_db, table)
          with s_db.conn:
              data = s_db[table].rows

          with args.db.conn:
              if args.upsert:
                  args.db[table].upsert_all(data, pk=args.upsert.split(","), alter=True)
              else:
                  args.db[table].insert_all(data, alter=True, replace=True)


  def merge_dbs():
      args = parse_args()
      for s_db in args.dbs:
          merge_db(args, s_db)


  if __name__ == "__main__":
      merge_dbs()

  ```

  ```
  $ lb-dev merge video.db tube_71.db --upsert path -vv
  SQL: INSERT OR IGNORE INTO [media]([path]) VALUES(?); - params: ['https://archive.org/details/088ghostofachanceroygetssackedrevengeofthelivinglunchdvdripxvidphz']
  ...
  File ~/.local/lib/python3.10/site-packages/sqlite_utils/db.py:3122, in Table.insert_all(self, records, pk, foreign_keys, column_order, not_null, defaults, batch_size, hash_id, hash_id_columns, alter, ignore, replace, truncate, extracts, conversions, columns, upsert, analyze)
     3116             all_columns += [
     3117                 column for column in record if column not in all_columns
     3118             ]
     3120     first = False
  -> 3122     self.insert_chunk(
     3123         alter,
     3124         extracts,
     3125         chunk,
     3126         all_columns,
     3127         hash_id,
     3128         hash_id_columns,
     3129         upsert,
     3130         pk,
     3131         conversions,
     3132         num_records_processed,
     3133         replace,
     3134         ignore,
     3135     )
     3137 if analyze:
     3138     self.analyze()

  File ~/.local/lib/python3.10/site-packages/sqlite_utils/db.py:2887, in Table.insert_chunk(self, alter, extracts, chunk, all_columns, hash_id, hash_id_columns, upsert, pk, conversions, num_records_processed, replace, ignore)
     2885 for query, params in queries_and_params:
     2886     try:
  -> 2887         result = self.db.execute(query, params)
     2888     except OperationalError as e:
     2889         if alter and (" column" in e.args[0]):
     2890             # Attempt to add any missing columns, then try again

  File ~/.local/lib/python3.10/site-packages/sqlite_utils/db.py:484, in Database.execute(self, sql, parameters)
      482     self._tracer(sql, parameters)
      483 if parameters is not None:
  --> 484     return self.conn.execute(sql, parameters)
      485 else:
      486     return self.conn.execute(sql)

  IntegrityError: constraint failed
  > /home/xk/.local/lib/python3.10/site-packages/sqlite_utils/db.py(484)execute()
      482                 self._tracer(sql, parameters)
      483             if parameters is not None:
  --> 484                 return self.conn.execute(sql, parameters)
      485             else:
      486                 return self.conn.execute(sql)
  ```

  ```
  sqlite3 --version
  3.36.0 2021-06-18 18:36:39
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/511/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5VxYnP
title: Exclude virtual tables from datasette inspect
state: open
created_at: 2022-11-07T21:26:01Z
updated_at: 2022-11-21T04:40:56Z
author_association: CONTRIBUTOR
type: issue
body:
  Ran `inspect` on a spatialite database and got these warnings:

  ```
  ERROR: conn=<sqlite3.Connection object at 0x119e46110>, sql = 'select count(*) from [SpatialIndex]', params = None: no such module: VirtualSpatialIndex
  ERROR: conn=<sqlite3.Connection object at 0x119e46110>, sql = 'select count(*) from [ElementaryGeometries]', params = None: no such module: VirtualElementary
  ERROR: conn=<sqlite3.Connection object at 0x119e46110>, sql = 'select count(*) from [KNN]', params = None: no such module: VirtualKNN
  ```

  It still worked, but probably want to catch this.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1884/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WOj9h
title: Integrate inside GUI app (tkinter)
state: open
created_at: 2022-11-13T00:10:43Z
updated_at: 2022-11-13T00:11:09Z
author_association: NONE
type: issue
body:
  Hi, I'd like to integrate datasette inside a tkinter app. The app should be able to start/stop datasette server. How could I integrate datasette inside my app, so it can start and stop datasette server?

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1885/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WQD3y
title: Call for birthday presents: if you're using Datasette, let us know how you're using it here
state: open
created_at: 2022-11-13T19:25:51Z
updated_at: 2022-12-18T17:34:20Z
author_association: OWNER
type: issue
body:
  Datasette is 5 years old today. To celebrate, I'm asking the community for birthday presents:

  https://simonwillison.net/2022/Nov/13/datasette-birthday/

  > To celebrate this open source project’s birthday, I’ve decided to try something new: I’m going to ask for birthday presents.
  > 
  > An aspect of Datastte’s marketing that I’ve so far neglected is social proof. I think it’s time to change that: I know people are using the software to do cool things, but this often happens behind closed doors.
  > 
  > For Datastte’s birthday, I’m looking for endorsements and case studies and just general demonstrations that show how people are using it do so cool stuff.
  > 
  > So: if you’ve used Datasette to solve a problem, and you’re willing to publicize it, please give us the gift of your endorsement!
  > 
  > [...]
  > 
  > Add a comment to [this issue thread](https://github.com/simonw/datasette/issues/1886) describing what you’re doing. Just a few sentences is fine—though a screenshot or even a link to a live instance would be even better

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1886/reactions", "total_count": 2, "+1": 0, "-1": 0, "laugh": 0, "hooray": 2, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WRWaJ
title: Add a confirm step to the drop table API
state: closed
created_at: 2022-11-14T04:59:53Z
updated_at: 2022-11-15T19:59:59Z
closed_at: 2022-11-14T05:18:51Z
author_association: OWNER
type: issue
state_reason: completed
body:
  > In playing with the API explorer just now I realized it's way too easy to accidentally drop a table using it.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1871#issuecomment-1313097057_

  Added drop table API in:
  - #1874

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1887/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WRi5x
title: API explorer should take immutability into account
state: closed
created_at: 2022-11-14T06:00:14Z
updated_at: 2022-11-15T19:59:10Z
closed_at: 2022-11-14T06:04:48Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Refs:
  - #1871

  I noticed the API explorer doesn't show any links on https://latest-1-0-dev.datasette.io/-/api because the `fixtures` database is immutable.

  It should still show read examples there.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1888/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WRpAs
title: Ability to create new tokens via the API
state: open
created_at: 2022-11-14T06:21:36Z
updated_at: 2022-12-13T05:29:08Z
author_association: OWNER
type: issue
body:
  Refs:
  - #1850

  Initially I decided that the API shouldn't be able to create new tokens at all - I don't like the idea of an API token holder creating themselves additional tokens.

  Then I realized that two of the API features are specifically more useful if you can generate fresh tokens via the API:

  - Tokes that expire after a time limit are MUCH more useful if they can be automatically generated
  - Likewise, tokens that are restricted to a subset of permissions (see #1855) make more sense to be generated like this, especially in conjunction with expiry times

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1889/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WUOm-
title: Autocomplete text entry for filter values that correspond to facets
state: closed
created_at: 2022-11-14T14:11:31Z
updated_at: 2022-11-17T00:47:36Z
closed_at: 2022-11-16T03:23:01Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  datasette allows users to enter in the value for named parameters into a free-text form field.

  I think it would add a lot of usability, if the form field could be a drop down of options when query value is already a faceted column.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1890/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Wcd7l
title: 1.0a0 release notes
state: closed
created_at: 2022-11-15T19:58:20Z
updated_at: 2022-11-29T19:23:41Z
closed_at: 2022-11-29T19:23:41Z
author_association: OWNER
body:
  This release will mainly help preview the new Datasette write API:
  - #1850

type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1891/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WcgKX
title: Merge 1.0-dev branch back to main
state: closed
created_at: 2022-11-15T20:04:25Z
updated_at: 2022-11-29T19:40:23Z
closed_at: 2022-11-29T19:40:23Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I'm committed enough to the 1.0 work now that I'm ready for the `main` branch to reflect that instead.

  If I need to make any dot-releases against 0.63 I can do those from a branch.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1892/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5C9ZuP
title: Upgrade to CodeMirror 6, add SQL autocomplete
state: closed
created_at: 2022-11-15T20:52:35Z
updated_at: 2022-11-16T23:54:02Z
closed_at: 2022-11-16T23:49:06Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1893
type: pull
body:
  In an effort to get closer to table / column autocomplete I took a shot at https://github.com/simonw/datasette/issues/1796. I haven't done a lot of testing but would be curious if this fixes some of the concerns raised in https://github.com/simonw/datasette/issues/1796#issue-1355148385 for example.

  Done:
  * Changed to bundling using rollup as per https://codemirror.net/examples/bundle/
  * Restored a fromTextArea-like function from https://codemirror.net/docs/migration/
  * Removed old JS and CSS files (no external CSS needed anymore as per https://codemirror.net/examples/styling/)
  * Updated instructions for building the bundle

  Not done:
  * cmResize had an error, so commented out the resize handle
  * Add extraKeys option for shift+enter and tab

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1893.org.readthedocs.build/en/1893/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1893/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WeWel
title: Initialize CodeMirror during DOMContentLoaded instead of onload
state: closed
created_at: 2022-11-16T03:52:19Z
updated_at: 2022-11-18T07:29:02Z
closed_at: 2022-11-18T07:29:02Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  As per https://github.com/simonw/datasette/pull/1893/files#r1023248927 this should prevent a flash between the textarea being replaced by CodeMirror.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1894/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5We8bJ
title: mypy failures in CI
state: closed
created_at: 2022-11-16T06:22:48Z
updated_at: 2022-11-16T07:49:51Z
closed_at: 2022-11-16T07:49:50Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://github.com/simonw/sqlite-utils/actions/runs/3472012235 failed on Python 3.11:

  Truncated output:
  ```
  sqlite_utils/db.py:2467: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
  sqlite_utils/db.py:2467: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
  sqlite_utils/db.py:2530: error: Incompatible default for argument "where" (default has type "None", argument has type "str")  [assignment]
  sqlite_utils/db.py:2530: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
  sqlite_utils/db.py:2530: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
  sqlite_utils/db.py:2658: error: Argument 1 to "count_where" of "Queryable" has incompatible type "Optional[str]"; expected "str"  [arg-type]
  Found 23 errors in 1 file (checked 51 source files)
  ```
  Best look at https://github.com/hauntsaninja/no_implicit_optional

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/512/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WkUOl
title: Avoid using host name when building absolute URLs?
state: open
created_at: 2022-11-16T22:21:27Z
updated_at: 2022-11-16T22:21:27Z
author_association: NONE
type: issue
body:
  When deploying Datasette to Cloud Run and rewriting certain routes from a Firebase app to the Cloud Run service, some of the URLs in the page start with `https://[service].run.app` rather than the (custom) domain of the Firebase app. 

  I guess this is because a) the custom domain of the Firebase app isn't being passed through in the `host` header of the request to the Cloud Run instance and b) the `absolute_url` function in Datasette is using information from the request to build the URL.

  Would it be possible to not use the host name when building the absolute URLs, i.e. only include the path in the URL?

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1895/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WkVPp
title: Extract logic for resolving a URL to a database / table / row
state: closed
created_at: 2022-11-16T22:25:20Z
updated_at: 2022-11-18T22:57:47Z
closed_at: 2022-11-18T22:56:55Z
author_association: OWNER
type: issue
state_reason: completed
body:
  >  In trying to write this I realize that there's a lot of duplicated code with delete row, specifically around resolving the incoming URL into a row (or a database or a table).
  >
  > Since this is so common, I think it's worth extracting the logic out first.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1863#issuecomment-1317755263_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1896/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Wkr0v
title: Serve schema JSON to the SQL editor to enable autocomplete
state: closed
created_at: 2022-11-16T23:47:45Z
updated_at: 2022-11-18T05:33:20Z
closed_at: 2022-11-18T02:54:43Z
author_association: OWNER
body:
  See:
  - https://github.com/simonw/datasette/issues/1893#issuecomment-1317831555

type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1897/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5DEh-E
title: Use DOMContentLoaded instead of load event for CodeMirror initialization
state: closed
created_at: 2022-11-17T00:19:21Z
updated_at: 2022-11-18T07:29:01Z
closed_at: 2022-11-18T07:29:01Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1898
type: pull
body:
   Closes #1894

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1898.org.readthedocs.build/en/1898/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1898/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Wk1DJ
state: closed
created_at: 2022-11-17T00:29:52Z
updated_at: 2022-11-18T07:28:28Z
closed_at: 2022-11-18T07:20:53Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
title:
  Clicking within the CodeMirror area below the SQL (i.e. when there's only a single line) doesn't cause the editor to get focused 

body:
  After the upgrade to 6 (#1893) I noticed this. I think it's because we're doing overflow:hidden to accomplish the CSS resizer.

  When there's a single line of SQL there's a gap below that line where clicking doesn't do anything. It should focus at the end of the line.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1899/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WlH68
title: datasette package --spatialite throws error during build
state: open
created_at: 2022-11-17T02:03:28Z
updated_at: 2022-11-18T08:00:38Z
author_association: NONE
type: issue
body:
  Hello! Attempting to use `datasette package` to bundle up a SpatiaLite DB and I'm getting this error during the `docker build`:

  ```
  sqlite3.OperationalError: /usr/lib/x86_64-linux-gnu/mod_spatialite.so.so: cannot open shared object file: No such file or directory
  ```

  Seems to be throwing when this step is ran:

  ```
  ERROR [6/6] RUN datasette inspect results.db --inspect-file inspect-data.json
  ```

  This is with `v0.63.1`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1900/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5WnRP-
title: Add or document streamlined workflow for importing Datasette csv / json exports
state: open
created_at: 2022-11-17T10:54:47Z
updated_at: 2022-11-17T10:54:47Z
author_association: NONE
type: issue
body:
  I'm working on some small front-end enhancements to the laion-aesthetic-datasette project, and I wanted to partially populate a database directly using exports from the existing Datasette instance instead of downloading the parquet files and creating my own multi-GB database.

  There have been a number of small issues that are certainly related to my relative lack of familiarity with the toolkit, but that are still surprising. 

  For example: a CSV export of the images table (http://laion-aesthetic.datasette.io/laion-aesthetic-6pls.csv?sql=select+rowid%2C+url%2C+text%2C+domain_id%2C+width%2C+height%2C+similarity%2C+punsafe%2C+pwatermark%2C+aesthetic%2C+hash%2C+__index_level_0__+from+images+order+by+random%28%29+limit+100) has nested single quotes, double quotes, and commas that aren't handled by rows_from_file. Similarly, the json output has to be manually transformed to add the column names and remove extraneous information before sqlite_utils can import it.

  I was able to work through these issues, but as an enhancement it would be really helpful to create or document a clear workflow that avoids the friction of this data transformation.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/513/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Wp26Y
title: Some plugins show "home" breadcrumbs twice in the top left
state: closed
created_at: 2022-11-17T18:44:58Z
updated_at: 2022-11-18T07:22:37Z
closed_at: 2022-11-18T07:02:56Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  <img width="1023" alt="Screenshot 2022-11-17 at 10 44 12 AM" src="https://user-images.githubusercontent.com/95570/202531505-b8632f70-d95a-425f-b2f2-6380b153478b.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1901/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WsmeI
title: Document {% block crumbs %} for plugin authors
state: open
created_at: 2022-11-18T06:16:30Z
updated_at: 2022-11-18T06:16:39Z
author_association: OWNER
type: issue
body:
  > For `datasette-copyable` I want to show breadcrumbs that take database/instance permissions into account, so I'm removing `{% block nav %}` entirely and replacing it with this:
  >
  > ```html+jinja
  > {% block crumbs %}
  > {{ crumbs.nav(request=request, database=database, table=table) }}
  > {% endblock %}
  > ```

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1901#issuecomment-1319588163_

  I should document this.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1902/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Wx7SV
title: Refactor all error classes into a datasette.exceptions module
state: open
created_at: 2022-11-18T22:44:45Z
updated_at: 2022-11-20T22:35:01Z
author_association: OWNER
type: issue
body:
  While working on this issue:
  - #1896

  I realized that Datasette has error classes scattered around a fair bit, including some in the `datasette.utils.asgi` module for some reason.

  I should clean these up.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1903/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Wx8Ys
title: Datasette Lite tests failing due to httpx upgrade
state: closed
created_at: 2022-11-18T22:49:31Z
updated_at: 2022-11-18T22:57:48Z
closed_at: 2022-11-18T22:52:22Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Same problem as this one:
  - https://github.com/simonw/datasette-lite/issues/56

  Caused this failure: https://github.com/simonw/datasette/actions/runs/3500765964

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1904/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WyP5K
title: `publish heroku` failing due to old Python version
state: closed
created_at: 2022-11-19T00:01:45Z
updated_at: 2022-11-19T01:12:05Z
closed_at: 2022-11-19T00:52:29Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Reported on Discord: https://discord.com/channels/823971286308356157/823971286941302908/1042814317118115901

  ```
  -----> Building on the Heroku-22 stack
  -----> Determining which buildpack to use for this app
  -----> Python app detected
  -----> Using Python version specified in runtime.txt
   !     Requested runtime 'python-3.8.10' is not available for this stack (heroku-22).
   !     For supported versions, see: https://devcenter.heroku.com/articles/python-support
   !     Push rejected, failed to compile Python app.

   !     Push failed
   ▸    Build failed
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1905/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5WyQJq
title: Extract publish Heroku support to a plugin
state: open
created_at: 2022-11-19T00:02:51Z
updated_at: 2022-11-19T00:03:10Z
author_association: OWNER
type: issue
body:
  > This is a strong argument for extracting the Heroku support out to a plugin - it would allow this to be fixed with a plugin release without needing to push a full release of Datasette itself.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1905#issuecomment-1320678715_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1906/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5XVRcJ
title: upsert of new row with check constraints fails
state: closed
created_at: 2022-11-26T16:12:23Z
updated_at: 2023-05-08T21:50:52Z
closed_at: 2023-05-08T21:50:51Z
author_association: NONE
type: issue
state_reason: completed
body:
  (I originally opened this in https://github.com/simonw/datasette-insert/issues/20, but I see that that library depends on sqlite-utils)

  In the case of a new row, upsert first adds the row, specifying only its pkeys: https://github.com/simonw/sqlite-utils/blob/965ca0d5f5bffe06cc02cd7741344d1ddddf9d56/sqlite_utils/db.py#L2783-L2787

  This means that a table with NON NULL (or other constraint) columns that aren't part of the pkey can't have new rows upserted.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/514/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOCGYnMM5DvZxa
title: upsert new rows with constraints, fixes #514
state: closed
created_at: 2022-11-26T16:15:21Z
updated_at: 2023-05-08T21:27:11Z
closed_at: 2023-05-08T21:27:10Z
author_association: NONE
pull_request: simonw/sqlite-utils/pulls/515
type: pull
body:
  This fixes #514 by making the initial insert for upserts include all columns, so that new rows can be added to tables with non-pkey columns that have constraints.

  (aside: I'm not a python programmer. `pip`? `pipenv`? `venv`? These are mystical incantations to me. The process to set up this repo for local development and testing was _so easy_. Thank you for the excellent contributing documentation!)

  <!-- readthedocs-preview sqlite-utils start -->
  ----
  :books: Documentation preview :books:: https://sqlite-utils--515.org.readthedocs.build/en/515/

  <!-- readthedocs-preview sqlite-utils end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/515/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xb-uy
title: Option to sort facets alphabetically
state: open
created_at: 2022-11-28T19:18:14Z
updated_at: 2022-11-28T19:19:26Z
author_association: OWNER
body:
  Suggested here:
  - https://github.com/simonw/datasette/discussions/1908

type: issue
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1909/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xh3X-
title: Check incoming column types on various write APIs
state: open
created_at: 2022-11-29T18:09:10Z
updated_at: 2022-12-13T05:29:09Z
author_association: OWNER
type: issue
body:
  > I do think this needs type checking - I just tried and you really can send a string to an integer column and have it work, which feels bad.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1863#issuecomment-1331089156_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1910/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xh9UT
title: `/db/-/create` should support creating tables with compound primary keys
state: closed
created_at: 2022-11-29T18:30:47Z
updated_at: 2022-11-29T18:50:58Z
closed_at: 2022-11-29T18:48:05Z
author_association: OWNER
body:
  Found myself needing this to write the tests for:
  - #1864

type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1911/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5D6nzE
title: Merge 1.0-dev (with initial write API) back into main
state: closed
created_at: 2022-11-29T19:31:21Z
updated_at: 2022-11-29T19:39:37Z
closed_at: 2022-11-29T19:39:36Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1912
type: pull
body:
  See:
  - #1892

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1912.org.readthedocs.build/en/1912/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1912/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5XiRwJ
title: Release Datasette 1.0a0
state: closed
created_at: 2022-11-29T19:41:42Z
updated_at: 2022-11-29T20:10:35Z
closed_at: 2022-11-29T20:10:35Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I attempted the release just now - https://github.com/simonw/datasette/releases/tag/1.0a0 -  and got an unexpected test failure:

  https://github.com/simonw/datasette/actions/runs/3577355358/attempts/1

  ```
  >       assert delete_response.status_code == 200
  E       assert 404 == 200
  E        +  where 404 = <Response [404 Not Found]>.status_code

  /home/runner/work/datasette/datasette/tests/test_api_write.py:396: AssertionError
  =========================== short test summary info ============================
  FAILED tests/test_api_write.py::test_delete_row[compound_pk_table-row_for_create2-pks2-article,k] - assert 404 == 200
   +  where 404 = <Response [404 Not Found]>.status_code
  ```
  I hit "retry" on that test but I expect it to fail again.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1913/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Ximrz
title: Finalize design of JSON for Datasette 1.0
state: open
created_at: 2022-11-29T20:59:10Z
updated_at: 2022-12-13T06:15:54Z
author_association: OWNER
body:
  Tracking issue.

  - [ ] #1709
  - [ ] #1729
  - [ ] #1875

type: issue
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1914/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xirqb
title: Interactive demo of Datasette 1.0 write APIs
state: closed
created_at: 2022-11-29T21:16:03Z
updated_at: 2022-11-30T04:05:46Z
closed_at: 2022-11-30T04:05:46Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I'm going to try to get this working on https://latest.datasette.io/ - it already has a way for people to sign in as root, but none of the databases there are writable.

  So I'm going to build a plugin which adds a writable named in-memory database.

  And some kind of mechanism for clearing out that database on a regular basis - maybe tables in that database get deleted automatically an hour after they are created?

  (Would be neat to display their time-left-until-deleted too)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1915/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xj2PZ
title: GET requests against POST endpoints should not 500 error
state: closed
created_at: 2022-11-30T04:04:43Z
updated_at: 2022-11-30T05:15:19Z
closed_at: 2022-11-30T05:15:19Z
author_association: OWNER
type: issue
state_reason: completed
body:
  ![CF37BA4D-0677-4DDD-A339-EAF163BB63B7](https://user-images.githubusercontent.com/9599/204705025-6f88e9f7-757d-45e8-a89c-ab97e84781e8.png)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1916/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xj9R8
title: Don't allow writable API to edit the `_memory` database
state: closed
created_at: 2022-11-30T04:51:59Z
updated_at: 2022-11-30T05:07:56Z
closed_at: 2022-11-30T05:07:55Z
author_association: OWNER
type: issue
state_reason: completed
body:
  It shows up on https://latest.datasette.io/-/api (once you are signed in as root) - but there's no point in creating tables in it because they likely won't persist from one request to the next, as it's not a shared named database.

  <img width="1122" alt="image" src="https://user-images.githubusercontent.com/9599/204710529-bfab8442-d89b-4928-9b9a-e39bc53c1673.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1917/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xj9gC
title: API explorer should list mutable databases first
state: closed
created_at: 2022-11-30T04:53:33Z
updated_at: 2022-11-30T05:22:07Z
closed_at: 2022-11-30T05:07:56Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://latest.datasette.io/-/api hides `ephemeral` down at the bottom, would be more interesting if it was at the top.

  Related:
  - #1915 

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1918/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5XkB4e
title: Intermittent `test_delete_row` test failure
state: open
created_at: 2022-11-30T05:18:46Z
updated_at: 2022-11-30T05:20:56Z
author_association: OWNER
type: issue
body:
  https://github.com/simonw/datasette/actions/runs/3580503393/jobs/6022689591

  ```
          delete_response = await ds_write.client.post(
              "/data/{}/{}/-/delete".format(table, delete_path),
              headers={
                  "Authorization": "***".format(write_token(ds_write)),
              },
          )
  >       assert delete_response.status_code == 200
  E       assert 404 == 200
  E        +  where 404 = <Response [404 Not Found]>.status_code

  /home/runner/work/datasette/datasette/tests/test_api_write.py:396: AssertionError
  =========================== short test summary info ============================
  FAILED tests/test_api_write.py::test_delete_row[compound_pk_table-row_for_create2-pks2-article,k] - assert 404 == 200
   +  where 404 = <Response [404 Not Found]>.status_code
  ```
  This passes most of the time, but very occasionally fails - in this case in Python 3.7

  It seems to only fail for the `article,k` compound primary key test.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1919/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xm1Bm
title: Document Datasette.metadata() method
state: open
created_at: 2022-11-30T15:10:36Z
updated_at: 2022-11-30T15:10:36Z
author_association: CONTRIBUTOR
type: issue
body:
  Code is here: https://github.com/simonw/datasette/blob/main/datasette/app.py#L503

  This will be the official way to access metadata from plugins.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1920/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xm7Bj
title: Document methods to get canned queries
state: open
created_at: 2022-11-30T15:26:33Z
updated_at: 2022-11-30T23:34:21Z
author_association: CONTRIBUTOR
type: issue
body:
  Two methods will get canned queries for a Datasette instance:

  [`Datasette.get_canned_queries`](https://github.com/simonw/datasette/blob/main/datasette/app.py#L575) will return all canned queries for a database that an `actor` can see.

  [`Datasette.get_canned_query`](https://github.com/simonw/datasette/blob/main/datasette/app.py#L592) will return a single canned query by name.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1921/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5XngTu
title: Make sure CORS works for write APIs
state: closed
created_at: 2022-11-30T17:15:55Z
updated_at: 2022-12-01T18:47:00Z
closed_at: 2022-12-01T18:47:00Z
author_association: OWNER
body:
  Split from:
  - #1850

type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1922/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Xo05j
title: latest.datasette.io Cloud Run deploys failing
state: closed
created_at: 2022-11-30T22:49:34Z
updated_at: 2022-11-30T23:04:56Z
closed_at: 2022-11-30T23:04:56Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://github.com/simonw/datasette/actions/runs/3587402085/jobs/6038106719v

  ```
  Warning: "service_account_key" has been deprecated. Please switch to using google-github-actions/auth which supports both Workload Identity Federation and Service Account Key JSON authentication. For more details, see https://github.com/google-github-actions/setup-gcloud#authorization
  Error: google-github-actions/setup-gcloud failed with: failed to execute command `gcloud --quiet auth activate-service-account *** --key-file -`: /opt/hostedtoolcache/gcloud/275.0.0/x64/lib/googlecloudsdk/core/console/console_io.py:544: SyntaxWarning: "is" with a literal. Did you mean "=="?
    if answer is None or (answer is '' and default is not None):
  ERROR: gcloud failed to load: module 'collections' has no attribute 'MutableMapping'
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1923/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5XpjNw
title: Docs for replace:true and ignore:true options for insert API
state: closed
created_at: 2022-12-01T01:33:25Z
updated_at: 2022-12-01T18:15:15Z
closed_at: 2022-12-01T02:08:02Z
author_association: OWNER
body: Equivalent to https://sqlite-utils.datasette.io/en/stable/cli.html#insert-replacing-data
type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1924/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5XvHrA
title: Release notes for 1.0a1 (and release it)
state: closed
created_at: 2022-12-01T21:18:12Z
updated_at: 2022-12-01T22:06:13Z
closed_at: 2022-12-01T22:06:12Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Mainly CORS support and a few small bug fixes.

  Changes: https://github.com/simonw/datasette/compare/1.0a0...99da46f7258225fc6fd8e94ddc20859ccccc4109

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1926/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5X0nh9
title: ignore:true/replace:true options for /db/-/create API
state: closed
created_at: 2022-12-02T20:32:30Z
updated_at: 2022-12-15T01:47:01Z
closed_at: 2022-12-08T01:43:01Z
author_association: OWNER
type: issue
state_reason: completed
body:
  See also:
  - #1924

  It turns out I want to be able to call `/db/-/create` multiple times with the `rows` argument, so that I don't have to worry about creating the table first.

  As such I find myself wanting support for the `"insert": true` and `"replace": true` options as well.

  Still TODO:

  - [x] A test for the case where you call `/-/create` twice with `rows` without using these options
  - [x] `pk` should be required if you are using these options
  - [x] Error if you pass `pk` and the table exists already but has a different `pk`
  - [x] Documentation for `insert` and `replace` - and what happens if you repeat a `/-/create` with rows generally
  - [x] Documentation should explain that you are allowed to call `/-/create` more than once using `rows`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1927/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5X04ou
title: Hacker News Datasette write demo
state: closed
created_at: 2022-12-02T21:17:41Z
updated_at: 2022-12-02T23:47:11Z
closed_at: 2022-12-02T21:43:19Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Idea is to have my existing scraper at https://github.com/simonw/scrape-hacker-news-by-domain also write to my private Datasette Cloud account, then create an atom feed from it.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1928/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5X1kE3
title: Incorrect link from the API explorer to the JSON API documentation
state: closed
created_at: 2022-12-03T02:08:58Z
updated_at: 2022-12-06T19:36:23Z
closed_at: 2022-12-06T19:34:20Z
author_association: CONTRIBUTOR
type: issue
state_reason: completed
body:
  I installed `datasette==1.0a1`.

  When I go to http://127.0.0.1:8001/-/api I have a link: `Use this tool to try out the [Datasette API](https://docs.datasette.io/en/1.0a1/json_api.html).` but that documentation page does not exist.

  I'm not sure where it has to be fixed, should it link to the stable page https://docs.datasette.io/en/stable/json_api.html , the latest one https://docs.datasette.io/en/latest/json_api.html#the-json-write-api or would it be more appropriated to deploy documentation for the `1.0a1` version?

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1929/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5ELz0u
title: Typo in JSON API `Updating a row` documentation
state: closed
created_at: 2022-12-03T02:22:31Z
updated_at: 2022-12-08T21:12:35Z
closed_at: 2022-12-08T21:12:35Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1930
type: pull
body:
  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1930.org.readthedocs.build/en/1930/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1930/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5EMVug
title: /db/table/-/upsert
state: closed
created_at: 2022-12-03T07:01:44Z
updated_at: 2022-12-08T01:12:17Z
closed_at: 2022-12-08T01:12:16Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1931
type: pull
body:
  Refs #1878

  Still todo:
  - [x] Support `"return": true` properly for upserts (with tests)
  - [x] Require both `insert-row` and `update-row` permissions
  - [x] Tests are going to need to cover both rowid-only and compound primary key tables, including all of the error states
  - [x] Documentation

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1931.org.readthedocs.build/en/1931/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1931/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5YNbRn
title: Feature request: output number of ignored/replaced rows for insert command
state: open
created_at: 2022-12-06T18:59:21Z
updated_at: 2022-12-06T19:08:14Z
author_association: OWNER
type: issue
body:
  https://hachyderm.io/@briandorsey/109468185742876820

  > I'm fiddling with piping json to `insert -ignore`  I'd love to see the count of records inserted & ignored, but didn't see a way to do that in the help/docs.
  >
  > Example: `xh "https://hachyderm.io/api/v1/timelines/tag/rust?max_id=109443380308326328" | sqlite-utils insert aoc.db aoc - --pk=id --ignore`

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/516/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5YNcuF
title: Return number of ignored/replaced items from /-/insert
state: open
created_at: 2022-12-06T19:01:58Z
updated_at: 2022-12-06T19:02:03Z
author_association: OWNER
body:
  Idea from here:
  - https://github.com/simonw/sqlite-utils/issues/516

type: issue
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1934/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5EouZs
title: Bump furo from 2022.9.29 to 2022.12.7
state: closed
created_at: 2022-12-07T13:02:57Z
updated_at: 2022-12-08T21:12:08Z
closed_at: 2022-12-08T21:12:07Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1935
type: pull
body:
  Bumps [furo](https://github.com/pradyunsg/furo) from 2022.9.29 to 2022.12.7.
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/pradyunsg/furo/blob/main/docs/changelog.md">furo's changelog</a>.</em></p>
  <blockquote>
  <h1>Changelog</h1>
  <!-- raw HTML omitted -->
  <h2>2022.12.07 -- Reverent Raspberry</h2>
  <ul>
  <li>✨ Add support for Sphinx 6.</li>
  <li>✨ Improve footnote presentation with docutils 0.18+.</li>
  <li>Drop support for Sphinx 4.</li>
  <li>Improve documentation about what the edit button does.</li>
  <li>Improve handling of empty-flexboxes for better print experience on Chrome.</li>
  <li>Improve styling for inline signatures.</li>
  <li>Replace the <code>meta</code> generator tag with a comment.</li>
  <li>Tweak labels with icons to prevent users selecting icons as text on touch.</li>
  </ul>
  <h2>2022.09.29 -- Quaint Quartz</h2>
  <ul>
  <li>Add ability to set arbitrary URLs for edit button.</li>
  <li>Add support for aligning text in MyST-parser generated tables.</li>
  </ul>
  <h2>2022.09.15 -- Pragmatic Pistachio</h2>
  <ul>
  <li>Add a minimum version constraint on pygments.</li>
  <li>Add an explicit dependency on <code>sass</code>.</li>
  <li>Change right sidebar title from &quot;Contents&quot; to &quot;On this page&quot;.</li>
  <li>Correctly position sidebars on small screens.</li>
  <li>Correctly select only Furo's own <code>svg</code> in related pages <code>nav</code>.</li>
  <li>Make numpy-style documentation headers consistent.</li>
  <li>Retitle the reference section.</li>
  <li>Update npm dependencies.</li>
  </ul>
  <h2>2022.06.21 -- Opulent Opal</h2>
  <ul>
  <li>Fix <code>docutils &lt;= 0.17.x</code> compatibility.</li>
  <li>Bump to the latest Node.js LTS.</li>
  </ul>
  <h2>2022.06.04.1 -- Naughty Nickel bugfix</h2>
  <ul>
  <li>Fix the URL used in the &quot;Edit this page&quot; for Read the Docs builds.</li>
  </ul>
  <h2>2022.06.04 -- Naughty Nickel</h2>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/pradyunsg/furo/commit/1034267d8a35609717ae50c6bbad816efcd7754b"><code>1034267</code></a> Prepare release: 2022.12.07</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/239e69f7d6e01031828944fe83048d3fb2c04c99"><code>239e69f</code></a> Update changelog</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/8faac34fd2a2b338288b8f86662cf5175bcffeb4"><code>8faac34</code></a> Remove the no-longer-useful gh-pages workflow</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/faa27fb89bee4627cd5b942a760404a9b4cf0d4d"><code>faa27fb</code></a> Fix the hyperlink warning</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/9849ec0ac751d72e35d8c04ac6ad137c936af7ab"><code>9849ec0</code></a> Forward the arguments to <code>stb serve</code></li>
  <li><a href="https://github.com/pradyunsg/furo/commit/e0dc9b8ebfdb301f197d0aa6a011636a794a08c2"><code>e0dc9b8</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/588">#588</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/9842e254ed0daa77efc2fd37de25a021cdb69f92"><code>9842e25</code></a> Clarify what the edit button does (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/587">#587</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/0d2cf0bf071ea93ea4f142c728bfbe70ef14b566"><code>0d2cf0b</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/578">#578</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/b7d8866c3aa1f9f293730c0868a0d52cd6f12f8a"><code>b7d8866</code></a> Revert &quot;Document that GCC is using Furo! (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/575">#575</a>)&quot; (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/577">#577</a>)</li>
  <li><a href="https://github.com/pradyunsg/furo/commit/0ab12bb37ccf4cfbbbcad2dd917c9734fbca2bd0"><code>0ab12bb</code></a> Improve footnote presentation with docutils 0.18+ (<a href="https://github-redirect.dependabot.com/pradyunsg/furo/issues/576">#576</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/pradyunsg/furo/compare/2022.09.29...2022.12.07">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=furo&package-manager=pip&previous-version=2022.9.29&new-version=2022.12.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1935.org.readthedocs.build/en/1935/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1935/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5YaJlU
title: Fix /db/table/-/upsert in the API explorer
state: open
created_at: 2022-12-08T00:59:34Z
updated_at: 2022-12-08T01:36:02Z
author_association: OWNER
type: issue
body:
  Split from:
  - #1931
  - #1878

  This is a bit tricky because the code needs to figure out what the primary keys are for an item, and whether or not `rowid` should be included.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1936/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Yaawl
title: /db/-/create API should require insert-rows permission to use row: or rows: option
state: closed
created_at: 2022-12-08T01:33:09Z
updated_at: 2022-12-14T20:21:26Z
closed_at: 2022-12-14T20:21:26Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Otherwise someone with `create-table` but no` insert-rows` permission could abuse it to insert data.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1937/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODEpn8M5Yg5N9
title: table identifications has no column named previous_observation_taxon
state: open
created_at: 2022-12-08T16:47:17Z
updated_at: 2022-12-08T16:47:17Z
author_association: NONE
type: issue
body:
  Installed successfully with pip and ran `inaturalist-to-sqlite inaturalist.db simonw` and got the error:

  ```
  sqlite3.OperationalError: table identifications has no column named previous_observation_taxon
  ```

reactions:
  {"url": "https://api.github.com/repos/dogsheep/inaturalist-to-sqlite/issues/2/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5E1iJG
title: "permissions" blocks in metadata.json/yaml
state: closed
created_at: 2022-12-08T22:07:36Z
updated_at: 2022-12-13T05:23:18Z
closed_at: 2022-12-13T05:23:18Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1938
type: pull
body:
  Refs #1636

  - [x] Documentation
  - [ ] Implementation
  - [ ] Validate metadata to check there are no nonsensical permissions (like `debug-menu` set at the table level)
  - [ ] Tests

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1938.org.readthedocs.build/en/1938/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1938/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5YjtxH
title: register_permissions(datasette) plugin hook
state: closed
created_at: 2022-12-09T01:33:25Z
updated_at: 2022-12-13T02:07:50Z
closed_at: 2022-12-13T02:05:56Z
author_association: OWNER
type: issue
state_reason: completed
body:
  A plugin hook that adds more named permissions to the list which is initially populated here:

  https://github.com/simonw/datasette/blob/e539c1c024bc62d88df91d9107cbe37e7f0fe55f/datasette/permissions.py#L1-L19

  Originally imagined this hook in this comment:

  - https://github.com/simonw/datasette/issues/1881#issuecomment-1301639370

  I need this for a few reasons:

  - https://github.com/simonw/datasette/issues/1636
    - Needs it in order to validate that permissions defined in `metadata.json` are set in the right place (don't set an instance permissions at table level for example)
  - https://github.com/simonw/datasette/issues/1855
    - Needs it to be able to register additional abbreviations for use in signed cookies
    - And for validation when you use `datasette create-token` and pass in extra permissions
  - The https://latest.datasette.io/-/permissions debug interface needs it to add extra debug options to the `<select>`

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1939/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5E3XqB
title: register_permissions() plugin hook
state: closed
created_at: 2022-12-09T05:09:28Z
updated_at: 2022-12-13T02:05:55Z
closed_at: 2022-12-13T02:05:54Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1940
type: pull
body:
  Refs #1939

  From this comment: https://github.com/simonw/datasette/issues/1939#issuecomment-1343872168

  - [x] Unit test for the registration plugin hook itself
  - [x] Use them in `check_permission_actions_are_documented` test in `conftest.py`
  - [x] Add description field to `Permissions` (and update tests and docs)
  - [x] Documentation for `datasette.permissions` dictionary
  - [x] If no `default=` provided in call to `permission_allowed()` then use default from `datasette.permissions` list
  - [x] Remove `default=` from a bunch of places
  - [x] Throw an error if two permissions are registered with the same name or abbreviation (but other attributes differ)
  - [x] Update authentication and permissions documentation to explain that permissions are now registered and have a registered default

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1940.org.readthedocs.build/en/1940/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1940/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Ykx0t
title: Mechanism for supporting key rotation for DATASETTE_SECRET
state: open
created_at: 2022-12-09T05:24:53Z
updated_at: 2022-12-09T05:25:20Z
author_association: OWNER
type: issue
body:
  Currently if you change `DATASETTE_SECRET` all existing signed tokens - both cookies and API tokens and potentially other things too - will instantly expire.

  Adding support for key rotation would allow keys to be rotated on a semi-regular basis without logging everyone out / invalidating every API token instantly.

  Can model this on how Django does it: https://github.com/django/django/commit/0dcd549bbe36c060f536ec270d34d9e7d4b8e6c7

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1941/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5YrRdy
title: Option for plugins to request that JSON be served on the page
state: open
created_at: 2022-12-10T01:08:53Z
updated_at: 2022-12-10T01:11:30Z
author_association: OWNER
type: issue
body:
  Idea came from a conversation with @hydrosquall - what if a Datasette plugin could say "I'd like the JSON for a page to be included in a variable on the HTML page"?

  `datasette-cluster-map` already needs this - the first thing it does when the page loads is `fetch()` a JSON representation of that same data.

  This idea fits with my overall goals to unify the JSON and HTML context too.

  Refs:
  - #1711

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1942/reactions", "total_count": 1, "+1": 0, "-1": 0, "laugh": 0, "hooray": 1, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5YrV9X
title: Drop support for Python 3.6
state: closed
created_at: 2022-12-10T01:23:31Z
updated_at: 2022-12-10T01:36:36Z
closed_at: 2022-12-10T01:36:36Z
author_association: OWNER
type: issue
state_reason: completed
body:
  CI has started failing for Python 3.6: https://github.com/simonw/sqlite-utils/actions/runs/3576322798

  <img width="945" alt="image" src="https://user-images.githubusercontent.com/9599/206821688-e4176cb3-ea82-460d-8e93-626fb4fa0269.png">

  It's fixable by swiching away from `ubuntu-latest` according to:

  - https://github.com/actions/setup-python/issues/355#issuecomment-1335042510

  But https://endoflife.date/python says that 3.6 end of life was almost 6 years ago, and end of security support nearly 1 year ago.

  So I'm OK dropping support entirely - Python 3.6 users will still be able to install version 3.30, just not any releases that come next.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/517/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5YrXyU
title: flake8 ValueError: Error code '#' supplied to 'extend-ignore' option...
state: closed
created_at: 2022-12-10T01:30:24Z
updated_at: 2022-12-10T01:36:46Z
closed_at: 2022-12-10T01:36:46Z
author_association: OWNER
type: issue
state_reason: completed
body:
  > `Error code '#' supplied to 'extend-ignore' option does not match '^[A-Z]{1,3}[0-9]{0,3}$'`

  https://github.com/simonw/sqlite-utils/actions/runs/3662011265/jobs/6190770361

  I think from this:

  https://github.com/simonw/sqlite-utils/blob/e660635cea6c32f4022818380b1e1ee88e7c93a6/setup.cfg#L1-L3

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/518/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Y2GWy
title: `/-/permissions` should list available permissions
state: open
created_at: 2022-12-11T23:38:03Z
updated_at: 2022-12-15T00:41:37Z
author_association: OWNER
type: issue
body:
  > Idea: a `/-/permissions` introspection endpoint for listing registered permissions

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1939#issuecomment-1345691103_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1943/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5FMKSG
title: Bump black from 22.10.0 to 22.12.0
state: closed
created_at: 2022-12-12T13:05:11Z
updated_at: 2022-12-13T05:23:31Z
closed_at: 2022-12-13T05:23:30Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1944
type: pull
body:
  Bumps [black](https://github.com/psf/black) from 22.10.0 to 22.12.0.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/psf/black/releases">black's releases</a>.</em></p>
  <blockquote>
  <h2>22.12.0</h2>
  <h3>Preview style</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Enforce empty lines before classes and functions with sticky leading comments (<a href="https://github-redirect.dependabot.com/psf/black/issues/3302">#3302</a>)</li>
  <li>Reformat empty and whitespace-only files as either an empty file (if no newline is
  present) or as a single newline character (if a newline is present) (<a href="https://github-redirect.dependabot.com/psf/black/issues/3348">#3348</a>)</li>
  <li>Implicitly concatenated strings used as function args are now wrapped inside
  parentheses (<a href="https://github-redirect.dependabot.com/psf/black/issues/3307">#3307</a>)</li>
  <li>Correctly handle trailing commas that are inside a line's leading non-nested parens
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3370">#3370</a>)</li>
  </ul>
  <h3>Configuration</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Fix incorrectly applied <code>.gitignore</code> rules by considering the <code>.gitignore</code> location
  and the relative path to the target file (<a href="https://github-redirect.dependabot.com/psf/black/issues/3338">#3338</a>)</li>
  <li>Fix incorrectly ignoring <code>.gitignore</code> presence when more than one source directory is
  specified (<a href="https://github-redirect.dependabot.com/psf/black/issues/3336">#3336</a>)</li>
  </ul>
  <h3>Parser</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Parsing support has been added for walruses inside generator expression that are
  passed as function args (for example,
  <code>any(match := my_re.match(text) for text in texts)</code>) (<a href="https://github-redirect.dependabot.com/psf/black/issues/3327">#3327</a>).</li>
  </ul>
  <h3>Integrations</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Vim plugin: Optionally allow using the system installation of Black via
  <code>let g:black_use_virtualenv = 0</code>(<a href="https://github-redirect.dependabot.com/psf/black/issues/3309">#3309</a>)</li>
  </ul>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/psf/black/blob/main/CHANGES.md">black's changelog</a>.</em></p>
  <blockquote>
  <h2>22.12.0</h2>
  <h3>Preview style</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Enforce empty lines before classes and functions with sticky leading comments (<a href="https://github-redirect.dependabot.com/psf/black/issues/3302">#3302</a>)</li>
  <li>Reformat empty and whitespace-only files as either an empty file (if no newline is
  present) or as a single newline character (if a newline is present) (<a href="https://github-redirect.dependabot.com/psf/black/issues/3348">#3348</a>)</li>
  <li>Implicitly concatenated strings used as function args are now wrapped inside
  parentheses (<a href="https://github-redirect.dependabot.com/psf/black/issues/3307">#3307</a>)</li>
  <li>Correctly handle trailing commas that are inside a line's leading non-nested parens
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3370">#3370</a>)</li>
  </ul>
  <h3>Configuration</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Fix incorrectly applied <code>.gitignore</code> rules by considering the <code>.gitignore</code> location
  and the relative path to the target file (<a href="https://github-redirect.dependabot.com/psf/black/issues/3338">#3338</a>)</li>
  <li>Fix incorrectly ignoring <code>.gitignore</code> presence when more than one source directory is
  specified (<a href="https://github-redirect.dependabot.com/psf/black/issues/3336">#3336</a>)</li>
  </ul>
  <h3>Parser</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Parsing support has been added for walruses inside generator expression that are
  passed as function args (for example,
  <code>any(match := my_re.match(text) for text in texts)</code>) (<a href="https://github-redirect.dependabot.com/psf/black/issues/3327">#3327</a>).</li>
  </ul>
  <h3>Integrations</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Vim plugin: Optionally allow using the system installation of Black via
  <code>let g:black_use_virtualenv = 0</code>(<a href="https://github-redirect.dependabot.com/psf/black/issues/3309">#3309</a>)</li>
  </ul>
  </blockquote>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/psf/black/commit/2ddea293a88919650266472186620a98a4a8bb37"><code>2ddea29</code></a> Prepare release 22.12.0 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3413">#3413</a>)</li>
  <li><a href="https://github.com/psf/black/commit/5b1443aefd9ad2bbaa20a76997183225dbfcc0fb"><code>5b1443a</code></a> release: skip bad macos wheels for now (<a href="https://github-redirect.dependabot.com/psf/black/issues/3411">#3411</a>)</li>
  <li><a href="https://github.com/psf/black/commit/9ace064d85e1fb0497db635e485fdab1e174e737"><code>9ace064</code></a> Bump peter-evans/find-comment from 2.0.1 to 2.1.0 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3404">#3404</a>)</li>
  <li><a href="https://github.com/psf/black/commit/19c5fe429e355a53ff320065d22e661785040b4c"><code>19c5fe4</code></a> Fix CI with latest flake8-bugbear (<a href="https://github-redirect.dependabot.com/psf/black/issues/3412">#3412</a>)</li>
  <li><a href="https://github.com/psf/black/commit/d4a85643a465f5fae2113d07d22d021d4af4795a"><code>d4a8564</code></a> Bump sphinx-copybutton from 0.5.0 to 0.5.1 in /docs (<a href="https://github-redirect.dependabot.com/psf/black/issues/3390">#3390</a>)</li>
  <li><a href="https://github.com/psf/black/commit/27932494bcefac03497dd92dcf0c59a04c10d757"><code>2793249</code></a> Wordsmith current_style.md (<a href="https://github-redirect.dependabot.com/psf/black/issues/3383">#3383</a>)</li>
  <li><a href="https://github.com/psf/black/commit/d97b7898b34b67eb3c6839998920e17ac8c77908"><code>d97b789</code></a> Remove whitespaces of whitespace-only files (<a href="https://github-redirect.dependabot.com/psf/black/issues/3348">#3348</a>)</li>
  <li><a href="https://github.com/psf/black/commit/c23a5c15aac963b460fdb1327ae875aafafafd41"><code>c23a5c1</code></a> Clarify that Black runs with --safe by default (<a href="https://github-redirect.dependabot.com/psf/black/issues/3378">#3378</a>)</li>
  <li><a href="https://github.com/psf/black/commit/8091b2503d12dd0110e0f1a9ed1e6b830aa668ed"><code>8091b25</code></a> Correctly handle trailing commas that are inside a line's leading non-nested ...</li>
  <li><a href="https://github.com/psf/black/commit/ffaaf4838228c922b586a87f717ed402031fcc0a"><code>ffaaf48</code></a> Compare each .gitignore found with an appropiate relative path (<a href="https://github-redirect.dependabot.com/psf/black/issues/3338">#3338</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/psf/black/compare/22.10.0...22.12.0">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=black&package-manager=pip&previous-version=22.10.0&new-version=22.12.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1944/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZAg0f
title: `view-instance` should not be checked for /-/actor.json
state: closed
created_at: 2022-12-13T04:01:46Z
updated_at: 2022-12-13T04:11:56Z
closed_at: 2022-12-13T04:11:56Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Spotted this while testing:

  - #1855
  ```
  export TOKEN=$(datasette create-token root --secret s -a foo)
  curl -H "Authorization: Bearer $TOKEN" http://localhost:8002/-/actor.json
  ```
  Returned a Forbidden error (and not in JSON either).

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1945/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZAoxG
title: `datasette --get` mechanism for sending tokens
state: closed
created_at: 2022-12-13T04:25:05Z
updated_at: 2022-12-13T04:36:57Z
closed_at: 2022-12-13T04:36:57Z
author_association: OWNER
type: issue
state_reason: completed
body:
  > For the tests for `datasette create-token` it would be useful if `datasette --get` had a mechanism for sending an `Authorization: Bearer X` header.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1855#issuecomment-1347731288_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1946/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZA1Zb
title: UI to create reduced scope tokens from the `/-/create-token` page
state: closed
created_at: 2022-12-13T05:10:48Z
updated_at: 2022-12-14T05:22:00Z
closed_at: 2022-12-14T05:13:24Z
author_association: OWNER
body:
  Split from:
  - #1855

type: issue
state_reason: completed
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1947/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZA4sH
title: 500 error on permission debug page when testing actors with _r
state: open
created_at: 2022-12-13T05:22:03Z
updated_at: 2022-12-13T05:22:19Z
author_association: OWNER
type: issue
body:
  <img width="1272" alt="image" src="https://user-images.githubusercontent.com/9599/207233390-ecb1b81b-c9f4-40a3-8131-5537ab23e9fc.png">

  The 500 error is silent unless you are looking at the DevTools network pane.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1948/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZBI_1
title: `.json` errors should be returned as JSON
state: open
created_at: 2022-12-13T06:14:12Z
updated_at: 2022-12-15T00:46:27Z
author_association: OWNER
body:
  Eg the error in this issue:
  - #1945

type: issue
reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1949/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZH5HK
title: Bad ?_sort returns a 500 error, should be a 400
state: closed
created_at: 2022-12-13T22:08:16Z
updated_at: 2022-12-13T22:23:22Z
closed_at: 2022-12-13T22:23:22Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://latest.datasette.io/fixtures/facetable?_sort=bad

  <img width="453" alt="image" src="https://user-images.githubusercontent.com/9599/207454481-2ba2e2bd-7400-47a6-b8a1-f898a2d364d8.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1950/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZInr8
title: `datasette.create_token(...)` method for creating signed API tokens
state: closed
created_at: 2022-12-14T01:25:34Z
updated_at: 2022-12-14T02:43:45Z
closed_at: 2022-12-14T02:42:05Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I need this for:
  - #1947

  And I can refactor this to use it too:
  - #1855

  By making this a documented internal API it can be used by other plugins too. It's also going to be really useful for writing tests.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1951/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZJtGT
title: Improvements to /-/create-token restrictions interface
state: open
created_at: 2022-12-14T05:22:39Z
updated_at: 2022-12-14T05:23:13Z
author_association: OWNER
type: issue
body:
  > It would be neat not to show write permissions against immutable databases too - and not hard from a performance perspective since it doesn't involve hundreds more permission checks.
  >
  > That will need permissions to grow a flag for if they need a mutable database though, which is a bigger job.

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1947#issuecomment-1350414402_

  Also, DO show the `_memory` database there if Datasette was started in `--crossdb` mode.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1952/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZKG0n
title: Release notes for Datasette 1.0a2
state: closed
created_at: 2022-12-14T06:26:40Z
updated_at: 2022-12-15T02:02:15Z
closed_at: 2022-12-15T02:01:08Z
author_association: OWNER
type: issue
state_reason: completed
body:
  https://github.com/simonw/datasette/milestone/27?closed=1

  https://github.com/simonw/datasette/compare/1.0a1...9ad76d279e2c3874ca5070626a25458ce129f126

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1953/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZNRtO
state: closed
created_at: 2022-12-14T13:39:56Z
updated_at: 2022-12-19T04:34:16Z
closed_at: 2022-12-18T02:45:18Z
author_association: NONE
type: issue
state_reason: completed
title:
  invoke_startup() is not run in some conditions, e.g. gunicorn/uvicorn workers, breaking lots of things

body:
  In the past (pre-september 14, #1809) I had a running deployment of Datasette on Azure WebApps by emulating the call in cli.py to Gunicorn: `gunicorn -w 2 -k uvicorn.workers.UvicornWorker app:app`.

  My most recent deployment, however, fails loudly by shouting that `Datasette.invoke_startup()` was not called. It does not seem to be possible to call `invoke_startup` when running using a uvicorn command directly like this (I've reproduced this locally using `uvicorn`).  Two candidates that I have tried:
  * Uvicorn has a `--factory` option, but the app factory has to be synchronous, so no `await invoke_startup` there
  * `asyncio.get_event_loop().run_until_complete` is also not an option because `uvicorn` already has the event loop running.

  One additional option is:
  * Use Gunicorn's [server hooks](https://docs.gunicorn.org/en/stable/settings.html#server-hooks) to call `invoke_startup`. These are also synchronous, but I might be able to get ahead of the event loop starting here.

  In my current deployment setup, it does not appear to be possible to use `datasette serve` directly, so I'm stuck either
  * Trying to rework my complete deployment setup, for instance, using Azure functions as described [here](https://github.com/simonw/azure-functions-datasette))
  * Or dig into the ASGI spec and write a wrapper for the sole purpose of launching Datasette using a direct Uvicorn invocation.

  Questions for the maintainers:
  * Is this intended behaviour/will not support/etc.? If so, I'd be happy to add a PR with a couple lines in the documentation.
  * if this is not intended behaviour, what is a good way to fix it? I could have a go at the ASGI spec thing (I think the Azure Functions thing is related) and provide a PR with the wrapper here, but I'm all ears!

  Almost forgot, minimal reproducer:
  ```python
  from datasette import Datasette

  ds = Datasette(files=['./global-power-plants.db'])]
  app = ds.app()
  ```

  Save as app.py in the same folder as global-power-plants.db, and then try running
  `uvicorn app:app`.

  Opening the resulting Datasette instance in the browser will show the error message.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1955/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZPs_a
title: Handle abbreviations properly in permission_allowed_actor_restrictions
state: closed
created_at: 2022-12-14T19:54:21Z
updated_at: 2022-12-14T20:04:29Z
closed_at: 2022-12-14T20:04:28Z
author_association: OWNER
type: issue
state_reason: completed
body:
  This code currently assumes abbreviations are:

   ```pyton
  action_initials = "".join([word[0] for word in action.split("-")])
  ```

  https://github.com/simonw/datasette/blob/1a3dcf494376e32f7cff110c86a88e5b0a3f3924/datasette/default_permissions.py#L182-L208

  That's no longer correct, they are now registered by the new plugin hook:
  - #1939 

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1956/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZQzY5
title: Reconsider row value truncation on query page
state: open
created_at: 2022-12-14T23:49:47Z
updated_at: 2022-12-14T23:50:50Z
author_association: OWNER
type: issue
body:
  Consider this example: https://ripgrep.datasette.io/repos?sql=select+json_group_array%28full_name%29+from+repos

  ```sql
  select json_group_array(full_name) from repos
  ```

  ![CleanShot 2022-12-14 at 15 48 32@2x](https://user-images.githubusercontent.com/9599/207739709-8177f683-f938-49a1-8225-42791fad88fe.png)

  My intention here was to get a string of JSON I can copy and paste elsewhere - see: https://til.simonwillison.net/sqlite/compare-before-after-json

  The truncation isn't helping here.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1957/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZSEom
title: datasette --root running in Docker doesn't reliably show the magic URL
state: closed
created_at: 2022-12-13T16:29:13Z
updated_at: 2022-12-16T00:59:12Z
closed_at: 2022-12-16T00:55:19Z
author_association: NONE
type: issue
state_reason: completed
body:
  I followed these steps:

  `docker run datasetteproject/datasette  pip install datasette-upload-csvs`

  `docker commit $(docker ps -lq) datasette-with-plugins`

  `docker run -p 8001:8001 -v $(pwd):/mnt   datasette-with-plugins   datasette --root -p 8001 -h 0.0.0.0`

  Visited: http://127.0.0.1:8001/-/plugins

  ![image](https://user-images.githubusercontent.com/11729897/207392071-d939cd5e-1d96-4e11-b0be-dc06dd207866.png)


  Visited: http://localhost:8001/-/upload-csvs

  ![image](https://user-images.githubusercontent.com/11729897/207389241-3e96ca66-ca74-4a16-8b7d-4427ee862c5e.png)

  I may have missed a step?

  Thank you.

  ---

  Ubuntu 22.04.1 LTS

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1958/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZWivA
title: Refactor test suite to use mostly `async def` tests
state: closed
created_at: 2022-12-15T21:02:54Z
updated_at: 2022-12-17T21:49:37Z
closed_at: 2022-12-17T21:49:36Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I got blocked working on this issue due to weird and hard-to-debug test suite problems:

  - #1955 

  The test suite has needed a major upgrade for several years now. It has a LOT of `def test_...` synchronous functions that could be upgraded to `async def` for better performance and less test complexity - I've used the new `async def` pattern in plugins and new tests for a couple of years now.

  Hopefully I can get more of the tests to use in-memory named databases too, ideally so I can fix this consistent problem:

  - #1843

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1959/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5FlZmG
title: Port as many tests as possible to async def tests against ds_client
state: closed
created_at: 2022-12-15T21:45:53Z
updated_at: 2022-12-17T21:47:56Z
closed_at: 2022-12-17T21:47:55Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1960
type: pull
body:
  Refs:
  - #1959

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1960.org.readthedocs.build/en/1960/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1960/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5FmNXs
title: Use click.echo() instead of print() for --root option
state: closed
created_at: 2022-12-16T00:54:56Z
updated_at: 2022-12-16T00:55:19Z
closed_at: 2022-12-16T00:55:18Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1961
type: pull
body:
  This ensures the URL is output correctly when running under Docker.

  Closes #1958

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1961.org.readthedocs.build/en/1961/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1961/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Zcec2
title: Alternative, async-friendly pattern for `make_app_client()` and similar - fully retire `TestClient`
state: open
created_at: 2022-12-16T17:56:51Z
updated_at: 2022-12-16T21:55:29Z
author_association: OWNER
type: issue
body:
  In this issue I replaced a whole bunch of places that used the non-async `app_client` fixture with an async `ds_client` fixture instead:
  - #1959

  But I didn't get everything, and a lot of tests are still using the old `TestClient` mechanism as a result.

  The main work here is replacing all of the `app_client_...` fixtures which use variants on the default client - and changing the tests that call `make_app_client()` to do something else instead.

  This requires some careful thought. I need to come up with a really nice pattern for creating variants on the `ds_client` default fixture - and do so in a way that minimizes the number of open files, refs:

  - #1843

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1962/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZglOI
title: 0.63.3 bugfix release
state: closed
created_at: 2022-12-18T02:48:15Z
updated_at: 2022-12-18T03:26:55Z
closed_at: 2022-12-18T03:26:55Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I'm going to ship a release which back-ports these two fixes:

  - https://github.com/simonw/datasette/issues/1958
  - https://github.com/simonw/datasette/issues/1955

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1963/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Zg1LX
title: Cog menu is not keyboard accessible (also no ARIA)
state: open
created_at: 2022-12-18T06:36:28Z
updated_at: 2022-12-18T06:37:28Z
author_association: OWNER
type: issue
body:
  This menu here: https://latest.datasette.io/fixtures/attraction_characteristic

  You can tab to it (see the outline) and hit space or enter to open it, but you can't then navigate the items in the open menu using the keyboard.

  ![cog-menu](https://user-images.githubusercontent.com/9599/208284973-2a04cdab-ed95-4316-979c-67fe5f7787db.gif)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1964/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5FuaJm
title: Detect server start/stop more reliably.
state: closed
created_at: 2022-12-18T10:03:42Z
updated_at: 2022-12-20T19:08:26Z
closed_at: 2022-12-18T16:01:51Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1965
type: pull
body:
  This is useful, especially in testing, since your test hosts might not reliabliy start the server within two seconds, so we do a definite check before progressing.

  By the same token, after `kill $server_pid` wait for the pid to be gone from the process list.

  Since now the script can end prematurely, I also added a cleanup function to make sure the temporary certs are removed in any case.

  n.b. this could also be done with the use of `trap 'fn' ERR` but that felt like a bit too much magic for this short a script.

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1965.org.readthedocs.build/en/1965/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1965/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ZhS0g
title: Broken link to live demo in Getting started docs
state: closed
created_at: 2022-12-18T13:17:00Z
updated_at: 2022-12-31T19:15:19Z
closed_at: 2022-12-31T19:15:10Z
author_association: NONE
type: issue
state_reason: completed
body:
  The link in [Play with a live demo in Getting started](https://github.com/simonw/datasette/blob/main/docs/getting_started.rst#play-with-a-live-demo) to [https://fivethirtyeight.datasettes.com/fivethirtyeight](https://fivethirtyeight.datasettes.com/fivethirtyeight) is broken and the datasette is no longer working (maybe due to the end of the free tier).

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1966/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5FyT3c
title: Add favicon to documentation
state: closed
created_at: 2022-12-19T14:01:04Z
updated_at: 2022-12-31T19:15:51Z
closed_at: 2022-12-31T19:00:31Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1967
type: pull
body:
  I've been browsing the datasette documentation and found it hard to quickly locate tabs with many of them open, because it does not ship a favicon. So this PR:

  - Grabs the favicon `.png` from datasette itself[^1]
  - Adds it to the `_static/` folder
  - Sets `html_favicon` to load it in the docs

  [^1]: I also learned that Chrome can fetch favicons as an internal service! See `chrome://favicon/https://datasette.io/tools/github-to-sqlite`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1967/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Zqpj3
title: Allow to hide some queries in metadata.yml
state: open
created_at: 2022-12-20T10:45:41Z
updated_at: 2022-12-20T10:45:41Z
author_association: NONE
type: issue
body:
  By default all queries are displayed.

  But there are many cases where it would be interesting to hide the queries by default:
  * the website is targeting non-tech people
  * the query is veeeeeery long ([eg.](https://mirabelle.openfoodfacts.org/products/energy_calculator))
  * reading the query is not important for the users, they only want to see the result

  Of course, the user still could have the option to see the query.

  It could be an option in the metadata file:
  ```yml
  databases:
    awesome_db:
      tables:
        products:
          hide_sql: true
      queries:
        great_query:
          hide_sql: true
          sql: select * from products where code = :barcode
  ```

  The priority could be:
  * no option in the metadata and nothing in the URL: query displayed
  * hide_sql in the metadata and nothing in the URL: query displayed as asked in the metadata
  * hide_sql in the metadata and &_hide_sql= in the URL: query as asked in the URL

  See also: #1824

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1968/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODFdgUs5ZusKN
title: self-hosted or corp github enterprise
state: open
created_at: 2022-12-20T22:51:45Z
updated_at: 2022-12-20T22:51:45Z
author_association: NONE
type: issue
body:
  We use github enterprise at work and I would like to use this tool to pull info from that site rather than the public github.com instance.  Is there an option for this?  If not, can one be added for a custom repo URL?

reactions:
  {"url": "https://api.github.com/repos/dogsheep/github-to-sqlite/issues/78/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOCGYnMM5F609a
title: Fixes breaking DEFAULT values
state: closed
created_at: 2022-12-21T01:27:52Z
updated_at: 2023-05-08T21:13:37Z
closed_at: 2023-05-08T21:13:37Z
author_association: CONTRIBUTOR
pull_request: simonw/sqlite-utils/pulls/519
type: pull
body:
  Fixes #509, Fixes #336

  Thanks for the great library!
  I fixed a bug that `sqlite-utils transform` breaks DEFAULT values.
  All tests already present passed  with no changes, and I added some tests for this PR.

  In #509 case, fixed here.

  ```shell
  $ sqlite3 test.db << EOF
  CREATE TABLE mytable (
      col1 TEXT DEFAULT 'foo',
      col2 TEXT DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))
  )
  EOF

  $ sqlite3 test.db "SELECT sql FROM sqlite_master WHERE name = 'mytable';"
  CREATE TABLE mytable (
      col1 TEXT DEFAULT 'foo',
      col2 TEXT DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))
  )

  $ sqlite3 test.db "INSERT INTO mytable DEFAULT VALUES; SELECT * FROM mytable;"
  foo|2022-12-21 01:15:39.669

  $ sqlite-utils transform test.db mytable --rename col1 renamedcol1
  $ sqlite3 test.db "SELECT sql FROM sqlite_master WHERE name = 'mytable';"
  CREATE TABLE "mytable" (
     [renamedcol1] TEXT DEFAULT 'foo',
     [col2] TEXT DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))  # ← Non-String Value
  )

  $ sqlite3 test.db "INSERT INTO mytable DEFAULT VALUES; SELECT * FROM mytable;"
  foo|2022-12-21 01:15:39.669
  foo|2022-12-21 01:15:56.432
  ```

  And #336 case also fixed.
  Special values are described [here](https://www.sqlite.org/lang_createtable.html).

  > 3.2. The DEFAULT clause
  > ... A default value may also be one of the special case-independent keywords CURRENT_TIME, CURRENT_DATE or CURRENT_TIMESTAMP.

  ```shell
  $ echo 'create table bar (baz text, created_at timestamp default CURRENT_TIMESTAMP)' | sqlite3 foo.db
  $ sqlite3 foo.db
  SQLite version 3.39.5 2022-10-14 20:58:05
  Enter ".help" for usage hints.
  sqlite> .schema bar
  CREATE TABLE bar (baz text, created_at timestamp default CURRENT_TIMESTAMP);
  sqlite> .exit

  $ sqlite-utils transform foo.db bar --column-order baz
  $ sqlite3 foo.db
  SQLite version 3.39.5 2022-10-14 20:58:05
  Enter ".help" for usage hints.
  sqlite> .schema bar
  CREATE TABLE IF NOT EXISTS "bar" (
     [baz] TEXT,
     [created_at] FLOAT DEFAULT CURRENT_TIMESTAMP
  );
  sqlite> .exit

  $ sqlite-utils transform foo.db bar --column-order baz
  $ sqlite3 foo.db
  SQLite version 3.39.5 2022-10-14 20:58:05
  Enter ".help" for usage hints.
  sqlite> .schema bar
  CREATE TABLE IF NOT EXISTS "bar" (
     [baz] TEXT,
     [created_at] FLOAT DEFAULT CURRENT_TIMESTAMP  # ← Non-String Value
  );
  ```


  <!-- readthedocs-preview sqlite-utils start -->
  ----
  :books: Documentation preview :books:: https://sqlite-utils--519.org.readthedocs.build/en/519/

  <!-- readthedocs-preview sqlite-utils end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/519/reactions", "total_count": 3, "+1": 3, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5Z_XYt
title: sql-formatter javascript is not now working with CloudFlare rocketloader
state: open
created_at: 2022-12-23T21:14:06Z
updated_at: 2023-01-10T01:56:33Z
author_association: CONTRIBUTOR
type: issue
body:
  This is probably not a bug with datasette, but I thought you might want to know, @simonw.

  I noticed today that my CloudFlare proxied datasette instance lost the "Format SQL" option. I'm pretty sure it was there last week.

  In the CloudFlare settings, if I turn off [Rocket Loader](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/), I get the "Format SQL" option back.

  Rocket Loader works by asynchronously loading the javascript, so maybe there was a recent change that doesn't play well with the asynch loading?

  I'm up to date with https://github.com/simonw/datasette/commit/e03aed00026cc2e59c09ca41f69a247e1a85cc89

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1969/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODEm0Qs5GUoG_
title: Add support for app-only bearer tokens
state: open
created_at: 2022-12-28T23:31:20Z
updated_at: 2022-12-28T23:31:20Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/twitter-to-sqlite/pulls/67
type: pull
body:
  Previously, twitter-to-sqlite only supported OAuth1 authentication, and the token must be on behalf of a user.  However, Twitter also supports application-only bearer tokens, documented here:
  https://developer.twitter.com/en/docs/authentication/oauth-2-0/bearer-tokens This PR adds support to twitter-to-sqlite for using application-only bearer tokens.  To use, the auth.json file just needs to contain a "bearer_token" key instead of "api_key", "api_secret_key", etc.

reactions:
  {"url": "https://api.github.com/repos/dogsheep/twitter-to-sqlite/issues/67/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODEm0Qs5GUoKL
title: Archive: Import mute table
state: open
created_at: 2022-12-28T23:32:06Z
updated_at: 2022-12-28T23:32:06Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/twitter-to-sqlite/pulls/68
type: pull
reactions:
  {"url": "https://api.github.com/repos/dogsheep/twitter-to-sqlite/issues/68/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODEm0Qs5GUoMM
title: Archive: Import new tweets table name
state: open
created_at: 2022-12-28T23:32:44Z
updated_at: 2022-12-28T23:32:44Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/twitter-to-sqlite/pulls/69
type: pull
body:
  Given the code here, it seems like in the past this file was named "tweet.js".  In recent exports, it's named "tweets.js".  The archive importer needs to be modified to take this into account.  Existing logic is reused for importing this table.  (However, the resulting table name will be different, matching the different file name -- archive_tweets, rather than archive_tweet).

reactions:
  {"url": "https://api.github.com/repos/dogsheep/twitter-to-sqlite/issues/69/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODEm0Qs5GUoN6
title: Archive: Import Twitter Circle data
state: open
created_at: 2022-12-28T23:33:09Z
updated_at: 2022-12-28T23:33:09Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/twitter-to-sqlite/pulls/70
type: pull
reactions:
  {"url": "https://api.github.com/repos/dogsheep/twitter-to-sqlite/issues/70/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDODEm0Qs5GUoPm
title: Archive: Fix "ni devices" typo in importer
state: open
created_at: 2022-12-28T23:33:31Z
updated_at: 2022-12-28T23:33:31Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/twitter-to-sqlite/pulls/71
type: pull
reactions:
  {"url": "https://api.github.com/repos/dogsheep/twitter-to-sqlite/issues/71/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5aT9uW
title: Path "None" in _internal database table
state: closed
created_at: 2022-12-31T18:51:05Z
updated_at: 2022-12-31T19:22:58Z
closed_at: 2022-12-31T18:52:49Z
author_association: OWNER
type: issue
state_reason: completed
body:
  See https://latest.datasette.io/_internal/databases (after https://latest.datasette.io/login-as-root)

  <img width="551" alt="image" src="https://user-images.githubusercontent.com/9599/210153171-625d3706-8b1a-4c80-9662-46985350f6b6.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1970/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5aT-Tn
title: Upgrade for Sphinx 6.0 (once Furo has support for it)
state: closed
created_at: 2022-12-31T19:04:35Z
updated_at: 2023-01-10T02:02:34Z
closed_at: 2023-01-10T02:02:34Z
author_association: OWNER
type: issue
state_reason: completed
body:
  A deployment of #1967 to ReadTheDocs just failed like this: https://readthedocs.org/projects/datasette/builds/19045460/

  ```
  Running Sphinx v6.0.0
  making output directory... done
  building [mo]: targets for 0 po files that are out of date
  building [html]: targets for 28 source files that are out of date
  updating environment: [new config] 28 added, 0 changed, 0 removed
  reading sources... [  3%] authentication
  reading sources... [  7%] binary_data
  reading sources... [ 10%] changelog

  Traceback (most recent call last):
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 299, in next_line
      self.line = self.input_lines[self.line_offset]
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 1136, in __getitem__
      return self.data[i]
  IndexError: list index out of range

  During handling of the above exception, another exception occurred:

  Traceback (most recent call last):
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 226, in run
      self.next_line()
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 302, in next_line
      raise EOFError
  EOFError

  During handling of the above exception, another exception occurred:

  Traceback (most recent call last):
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/cmd/build.py", line 281, in build_main
      app.build(args.force_all, args.filenames)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/application.py", line 344, in build
      self.builder.build_update()
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 310, in build_update
      self.build(to_build,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 326, in build
      updated_docnames = set(self.read())
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 433, in read
      self._read_serial(docnames)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 454, in _read_serial
      self.read_doc(docname)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 510, in read_doc
      publisher.publish()
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/core.py", line 224, in publish
      self.document = self.reader.read(self.source, self.parser,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/io.py", line 103, in read
      self.parse()
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/readers/__init__.py", line 76, in parse
      self.parser.parse(self.input, document)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/parsers.py", line 78, in parse
      self.statemachine.run(inputlines, document, inliner=self.inliner)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 169, in run
      results = StateMachineWS.run(self, input_lines, input_offset,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 233, in run
      context, next_state, result = self.check_line(
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 445, in check_line
      return method(match, context, next_state)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 3024, in text
      self.section(title.lstrip(), source, style, lineno + 1, messages)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 325, in section
      self.new_subsection(title, lineno, messages)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection
      newabsoffset = self.nested_parse(
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse
      state_machine.run(block, input_offset, memo=self.memo,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 195, in run
      results = StateMachineWS.run(self, input_lines, input_offset)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 233, in run
      context, next_state, result = self.check_line(
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 445, in check_line
      return method(match, context, next_state)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2785, in underline
      self.section(title, source, style, lineno - 1, messages)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 325, in section
      self.new_subsection(title, lineno, messages)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection
      newabsoffset = self.nested_parse(
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse
      state_machine.run(block, input_offset, memo=self.memo,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 195, in run
      results = StateMachineWS.run(self, input_lines, input_offset)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 233, in run
      context, next_state, result = self.check_line(
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 445, in check_line
      return method(match, context, next_state)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 1273, in bullet
      i, blank_finish = self.list_item(match.end())
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 1295, in list_item
      self.nested_parse(indented, input_offset=line_offset,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse
      state_machine.run(block, input_offset, memo=self.memo,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 195, in run
      results = StateMachineWS.run(self, input_lines, input_offset)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/statemachine.py", line 239, in run
      result = state.eof(context)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2725, in eof
      self.blank(None, context, None)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2716, in blank
      paragraph, literalnext = self.paragraph(
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 416, in paragraph
      textnodes, messages = self.inline_text(text, lineno)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 425, in inline_text
      nodes, messages = self.inliner.parse(text, lineno,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 649, in parse
      before, inlines, remaining, sysmessages = method(self, match,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 792, in interpreted_or_phrase_ref
      nodelist, messages = self.interpreted(rawsource, escaped, role,
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 889, in interpreted
      nodes, messages2 = role_fn(role, rawsource, text, lineno, self)
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/ext/extlinks.py", line 101, in role
      title = caption % part
  TypeError: not all arguments converted during string formatting

  Exception occurred:
    File "/home/docs/checkouts/readthedocs.org/user_builds/datasette/envs/latest/lib/python3.9/site-packages/sphinx/ext/extlinks.py", line 101, in role
      title = caption % part
  TypeError: not all arguments converted during string formatting
  The full traceback has been saved in /tmp/sphinx-err-kq7ylgqo.log, if you want to report the issue to the developers.
  Please also report this if it was a user error, so that a better error message can be provided next time.
  A bug report can be filed in the tracker at <https://github.com/sphinx-doc/sphinx/issues>. Thanks! 
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1971/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5aT-mJ
title: Fix Sphinx warning about extlink extension
state: closed
created_at: 2022-12-31T19:12:04Z
updated_at: 2022-12-31T19:13:26Z
closed_at: 2022-12-31T19:13:26Z
author_association: OWNER
type: issue
state_reason: completed
body:
  ```
  [sphinx-autobuild] > sphinx-build -b html /Users/simon/Dropbox/Development/datasette/docs /Users/simon/Dropbox/Development/datasette/docs/_build
  Running Sphinx v5.3.0
  loading pickled environment... done
  WARNING: extlinks: Sphinx-6.0 will require a caption string to contain exactly one '%s' and all other '%' need to be escaped as '%%'.
  ```

  _Originally posted by @simonw in https://github.com/simonw/datasette/issues/1971#issuecomment-1368266904_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1972/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOC8tyDs5Gc-VH
title: Include workout statistics
state: open
created_at: 2023-01-01T17:29:57Z
updated_at: 2023-01-01T17:29:57Z
author_association: FIRST_TIME_CONTRIBUTOR
pull_request: dogsheep/healthkit-to-sqlite/pulls/23
type: pull
body:
  Not sure when this changed (iOS 16 maybe?), but the `WorkoutStatistics` now has a whole bunch of information about workouts, e.g. for runs it contains the distance (as a `<WorkoutStatistics type="HKQuantityTypeIdentifierDistanceWalkingRunning ...>` element).

  Adding it as another column at leat allows me to pull these out (using SQLite's JSON support).
  I'm running with this patch on my own data now.

reactions:
  {"url": "https://api.github.com/repos/dogsheep/healthkit-to-sqlite/issues/23/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5aWYBm
title: render_cell plugin hook's row object is not a sqlite.Row
state: open
created_at: 2023-01-01T20:27:46Z
updated_at: 2023-01-29T00:40:31Z
author_association: CONTRIBUTOR
type: issue
body:
  From https://docs.datasette.io/en/stable/plugin_hooks.html#render-cell-row-value-column-table-database-datasette:

  > row - sqlite.Row
  > The SQLite row object that the value being rendered is part of

  This appears to actually be a [CustomRow](https://github.com/simonw/datasette/blob/f0fadc28ddb9f82e5cc1ecaa51e8a342eb6dc528/datasette/utils/__init__.py#L773-L789), but I think that's unrelated to my issue.

  I have a table:

  ```sql
  CREATE TABLE IF NOT EXISTS "dss_job_stats"(
    job_id integer not null references dss_job(id) on delete cascade,
    host text not null,
    // other columns elided as irrelevant
    primary key (job_id, host)
  );
  ```

  On datasette 0.63.2, the `render_cell` hook receives a `row` value that looks like:

  ```
  CustomRow([('job_id', {'value': 2, 'label': '2'}), ('host', 'cldellow.com')])
  ```

  I expected the `job_id` value to be `2`, but it's actually `{'value': 2, 'label': '2'}`.

  I can work around this, but was wondering if this was intended behaviour?

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1973/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOC8tyDs5aWovO
title: DOC: xml.etree.ElementTree.ParseError due to healthkit version 12
state: open
created_at: 2023-01-01T23:00:38Z
updated_at: 2023-03-30T10:17:31Z
author_association: NONE
type: issue
body:
  Hi @simonw 

  I hope you find this issue ok, the idea is provide some documentation to other users like me about how to solve this problem and save some time.

  Following the instructions from the `README.md` I've faced this error:

  ```bash
  (venv) mgreco@pop-os apple-health master* (23:44|0s)
  $ healthkit-to-sqlite apple_health_export/export.xml healthkit.db --xml
  Importing from HealthKit  [------------------------------------]    0%
  Traceback (most recent call last):
    File "/home/mgreco/github/mmngreco/apple-health/venv/bin/healthkit-to-sqlite", line 33, in <module>
      sys.exit(load_entry_point('healthkit-to-sqlite', 'console_scripts', 'healthkit-to-sqlite')())
    File "/home/mgreco/github/mmngreco/apple-health/venv/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
      return self.main(*args, **kwargs)
    File "/home/mgreco/github/mmngreco/apple-health/venv/lib/python3.10/site-packages/click/core.py", line 1055, in main
      rv = self.invoke(ctx)
    File "/home/mgreco/github/mmngreco/apple-health/venv/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
      return ctx.invoke(self.callback, **ctx.params)
    File "/home/mgreco/github/mmngreco/apple-health/venv/lib/python3.10/site-packages/click/core.py", line 760, in invoke
      return __callback(*args, **kwargs)
    File "/home/mgreco/github/mmngreco/apple-health/.deps/healthkit-to-sqlite/healthkit_to_sqlite/cli.py", line 57, in cli
      convert_xml_to_sqlite(fp, db, progress_callback=bar.update, zipfile=zf)
    File "/home/mgreco/github/mmngreco/apple-health/.deps/healthkit-to-sqlite/healthkit_to_sqlite/utils.py", line 25, in convert_xml_to_sqlite
      for tag, el in find_all_tags(
    File "/home/mgreco/github/mmngreco/apple-health/.deps/healthkit-to-sqlite/healthkit_to_sqlite/utils.py", line 12, in find_all_tags
      for event, el in parser.read_events():
    File "/home/mgreco/github/mmngreco/apple-health/venv/lib/python3.10/xml/etree/ElementTree.py", line 1324, in read_events
      raise event
    File "/home/mgreco/github/mmngreco/apple-health/venv/lib/python3.10/xml/etree/ElementTree.py", line 1296, in feed
      self._parser.feed(data)
  xml.etree.ElementTree.ParseError: syntax error: line 156, column 0
  ```

  So, after debugging and searching on internet I found this useful link: https://discussions.apple.com/thread/254202523 (etresoft, the real hero). Which basically says that the xml given by the health app (healthkit version 12) has some bugs but  fortunately, they can be solved with a couple of commads:

  1. Uncompress the zip and move the new folder where `export.xml` is.
  1. Create a `patch.txt` with the following content

      ```diff
      --- export.xml	2022-09-18 15:17:09.000000000 -0400
      +++ export-fixed.xml	2022-09-18 16:37:08.000000000 -0400
      @@ -15,6 +15,7 @@
         HKCharacteristicTypeIdentifierBiologicalSex       CDATA #REQUIRED
         HKCharacteristicTypeIdentifierBloodType           CDATA #REQUIRED
         HKCharacteristicTypeIdentifierFitzpatrickSkinType CDATA #REQUIRED
      +  HKCharacteristicTypeIdentifierCardioFitnessMedicationsUse CDATA #IMPLIED
       >
       <!ELEMENT Record ((MetadataEntry|HeartRateVariabilityMetadataList)*)>
       <!ATTLIST Record
      @@ -39,7 +40,7 @@
         startDate     CDATA #REQUIRED
         endDate       CDATA #REQUIRED
       >
      -<!ELEMENT Workout ((MetadataEntry|WorkoutEvent|WorkoutRoute)*)>
      +<!ELEMENT Workout ((MetadataEntry|WorkoutEvent|WorkoutRoute|WorkoutStatistics)*)>
       <!ATTLIST Workout
         workoutActivityType   CDATA #REQUIRED
         duration              CDATA #IMPLIED
      @@ -63,7 +64,7 @@
         duration             CDATA #IMPLIED
         durationUnit         CDATA #IMPLIED
       >
      -<!ELEMENT WorkoutEvent EMPTY>
      +<!ELEMENT WorkoutEvent (MetadataEntry?)>
       <!ATTLIST WorkoutEvent
         type                 CDATA #REQUIRED
         date                 CDATA #REQUIRED
      @@ -79,6 +80,7 @@
         minimum              CDATA #IMPLIED
         maximum              CDATA #IMPLIED
         sum                  CDATA #IMPLIED
      +  unit                 CDATA #IMPLIED
       >
       <!ELEMENT WorkoutRoute ((MetadataEntry|FileReference)*)>
       <!ATTLIST WorkoutRoute
      @@ -153,6 +155,7 @@
         dateIssued       CDATA #REQUIRED
         expirationDate   CDATA #REQUIRED
         brand            CDATA #IMPLIED
      +>
       <!ELEMENT RightEye EMPTY>
       <!ATTLIST RightEye
         sphere           CDATA #IMPLIED
      @@ -203,13 +206,6 @@
         diameter         CDATA #IMPLIED
         diameterUnit     CDATA #IMPLIED
       >
      -  device           CDATA #IMPLIED
      -<!ELEMENT MetadataEntry EMPTY>
      -<!ATTLIST MetadataEntry
      -  key              CDATA #IMPLIED
      -  value            CDATA #IMPLIED
      ->
      ->
       ]>
       <HealthData>
        <ExportDate/>
      ```
  1. Apply the path with the command: `patch < patch.txt`
  1. Fix endDates with the command `sed 's/startDate/endDate/2' export.xml > export-fixed.xml`
  1. Try again `healthkit-to-sqlite export-fixed.xml healthkit.db --xml`

reactions:
  {"url": "https://api.github.com/repos/dogsheep/healthkit-to-sqlite/issues/24/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5GfPJL
title: Bump sphinx from 5.3.0 to 6.0.0
state: closed
created_at: 2023-01-02T13:04:26Z
updated_at: 2023-01-05T13:02:42Z
closed_at: 2023-01-05T13:02:40Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1974
type: pull
body:
  Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 5.3.0 to 6.0.0.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/releases">sphinx's releases</a>.</em></p>
  <blockquote>
  <h2>v6.0.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b2</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/blob/master/CHANGES">sphinx's changelog</a>.</em></p>
  <blockquote>
  <h1>Release 6.0.0 (released Dec 29, 2022)</h1>
  <h2>Dependencies</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10468">#10468</a>: Drop Python 3.6 support</li>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10470">#10470</a>: Drop Python 3.7, Docutils 0.14, Docutils 0.15, Docutils 0.16, and
  Docutils 0.17 support. Patch by Adam Turner</li>
  </ul>
  <h2>Incompatible changes</h2>
  <ul>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/7405">#7405</a>: Removed the jQuery and underscore.js JavaScript frameworks.</p>
  <p>These frameworks are no longer be automatically injected into themes from
  Sphinx 6.0. If you develop a theme or extension that uses the
  <code>jQuery</code>, <code>$</code>, or <code>$u</code> global objects, you need to update your
  JavaScript to modern standards, or use the mitigation below.</p>
  <p>The first option is to use the sphinxcontrib.jquery_ extension, which has been
  developed by the Sphinx team and contributors. To use this, add
  <code>sphinxcontrib.jquery</code> to the <code>extensions</code> list in <code>conf.py</code>, or call
  <code>app.setup_extension(&quot;sphinxcontrib.jquery&quot;)</code> if you develop a Sphinx theme
  or extension.</p>
  <p>The second option is to manually ensure that the frameworks are present.
  To re-add jQuery and underscore.js, you will need to copy <code>jquery.js</code> and
  <code>underscore.js</code> from <code>the Sphinx repository</code>_ to your <code>static</code> directory,
  and add the following to your <code>layout.html</code>:</p>
  <p>.. code-block:: html+jinja</p>
  <p>{%- block scripts %}
  <!-- raw HTML omitted --><!-- raw HTML omitted -->
  <!-- raw HTML omitted --><!-- raw HTML omitted -->
  {{ super() }}
  {%- endblock %}</p>
  <p>.. _sphinxcontrib.jquery: <a href="https://github.com/sphinx-contrib/jquery/">https://github.com/sphinx-contrib/jquery/</a></p>
  <p>Patch by Adam Turner.</p>
  </li>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10471">#10471</a>, <a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10565">#10565</a>: Removed deprecated APIs scheduled for removal in Sphinx 6.0. See
  :ref:<code>dev-deprecated-apis</code> for details. Patch by Adam Turner.</p>
  </li>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10901">#10901</a>: C Domain: Remove support for parsing pre-v3 style type directives and
  roles. Also remove associated configuration variables <code>c_allow_pre_v3</code> and
  <code>c_warn_on_allowed_pre_v3</code>. Patch by Adam Turner.</p>
  </li>
  </ul>
  <h2>Features added</h2>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/5b56a231afeb6e96e87871546df3db4463a61c93"><code>5b56a23</code></a> Bump to 6.0.0 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/f1d1e9c997da52134a574a963ed6d1b404830ee0"><code>f1d1e9c</code></a> Update coverage workflow for Tox 4</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/66a738c2bfccd7a28788762c20baeb57b00719c3"><code>66a738c</code></a> Update coverage workflow for new configuration location</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/041e5f826894de99da5af0eb5225b69b8084c49e"><code>041e5f8</code></a> Add test coverage for 'today_fmt' reference substitution (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10980">#10980</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/da25145d0804240de0351d33697539306f3d10a7"><code>da25145</code></a> Remove unnecessary conditional import in <code>sphinx.ext.napoleon</code> (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11043">#11043</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/45a0ea9fc9f0cc509ff385942c275af02591e490"><code>45a0ea9</code></a> Migrate coveragepy config into pyproject.toml (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11025">#11025</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/3ec54f118310119211771133c94f0a836505bb43"><code>3ec54f1</code></a> Create a <code>pydata_sphinx_theme</code> section in usage examples (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11046">#11046</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/32bce8fb7c0b7a2eb89c7e0e3e7ef13fce7f03a6"><code>32bce8f</code></a> Copy edit the tutorial (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11049">#11049</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/984416247370a87ad947d89f334a8ce2d8ea6558"><code>9844162</code></a> Fix example using <code>add_config_value</code> (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10937">#10937</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/bf4a6268268442cc4d6b3bc7c3528bf77ae705db"><code>bf4a626</code></a> RTD builder: add graphviz depedendency (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11040">#11040</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/sphinx-doc/sphinx/compare/v5.3.0...v6.0.0">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sphinx&package-manager=pip&previous-version=5.3.0&new-version=6.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1974.org.readthedocs.build/en/1974/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1974/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5aZip0
title: rows_from_file() raises confusing error if file-like object is not in binary mode
state: closed
created_at: 2023-01-02T19:00:14Z
updated_at: 2023-05-08T22:08:07Z
closed_at: 2023-05-08T22:08:07Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I got this error:

  ```
    File "/Users/simon/Dropbox/Development/openai-to-sqlite/openai_to_sqlite/cli.py", line 27, in embeddings
      rows, _ = rows_from_file(input)
                ^^^^^^^^^^^^^^^^^^^^^
    File "/Users/simon/.local/share/virtualenvs/openai-to-sqlite-jt4obeb2/lib/python3.11/site-packages/sqlite_utils/utils.py", line 305, in rows_from_file
      first_bytes = buffered.peek(2048).strip()
                    ^^^^^^^^^^^^^^^^^^^
  ```
  From this code:
  ```python

  @cli.command()
  @click.argument(
      "db_path",
      type=click.Path(file_okay=True, dir_okay=False, allow_dash=False),
  )
  @click.option(
      "-i",
      "--input",
      type=click.File("r"),
      default="-",
  )
  def embeddings(db_path, input):
      "Store embeddings for one or more text documents"
      click.echo("Here is some output")
      db = sqlite_utils.Database(db_path)
      rows, _ = rows_from_file(input)
      print(list(rows))
  ```
  The error went away when I changed it to `type=click.File("rb")`.

  This should either be called out in the documentation or `rows_from_file()` should be fixed to handle text-mode files in addition to binary files.

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/520/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5aaMTT
title: _col=id can cause id column to export twice in CSV export
state: open
created_at: 2023-01-03T00:25:15Z
updated_at: 2023-01-03T00:25:21Z
author_association: OWNER
type: issue
body:
  https://datasette.simonwillison.net/simonwillisonblog/blog_entry.csv?_col=id&_col=title&_col=body&_labels=on&_size=1

  ```csv
  id,id,title,body
  1,1,WaSP Phase II,"<p>The <a href=""http://www.webstandards.org/"">Web Standards</a> project has launched Phase II.</p>"
  ```
  That should not have two `id` columns.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1975/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5GuDBN
title: Bump sphinx from 5.3.0 to 6.1.0
state: closed
created_at: 2023-01-05T13:02:37Z
updated_at: 2023-01-06T13:02:17Z
closed_at: 2023-01-06T13:02:15Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1976
type: pull
body:
  Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 5.3.0 to 6.1.0.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/releases">sphinx's releases</a>.</em></p>
  <blockquote>
  <h2>v6.1.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b2</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/blob/master/CHANGES">sphinx's changelog</a>.</em></p>
  <blockquote>
  <h1>Release 6.1.0 (released Jan 05, 2023)</h1>
  <h2>Dependencies</h2>
  <ul>
  <li>
  <p>Adopted the <code>Ruff</code>_ code linter.</p>
  <p>.. _Ruff: <a href="https://github.com/charliermarsh/ruff">https://github.com/charliermarsh/ruff</a></p>
  </li>
  </ul>
  <h2>Incompatible changes</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10979">#10979</a>: gettext: Removed support for pluralisation in <code>get_translation</code>.
  This was unused and complicated other changes to <code>sphinx.locale</code>.</li>
  </ul>
  <h2>Deprecated</h2>
  <ul>
  <li>
  <p><code>sphinx.util</code> functions:</p>
  <ul>
  <li>Renamed <code>sphinx.util.typing.stringify()</code>
  to <code>sphinx.util.typing.stringify_annotation()</code></li>
  <li>Moved <code>sphinx.util.xmlname_checker()</code>
  to <code>sphinx.builders.epub3._XML_NAME_PATTERN</code></li>
  </ul>
  <p>Moved to <code>sphinx.util.display</code>:</p>
  <ul>
  <li><code>sphinx.util.status_iterator</code></li>
  <li><code>sphinx.util.display_chunk</code></li>
  <li><code>sphinx.util.SkipProgressMessage</code></li>
  <li><code>sphinx.util.progress_message</code></li>
  </ul>
  <p>Moved to <code>sphinx.util.http_date</code>:</p>
  <ul>
  <li><code>sphinx.util.epoch_to_rfc1123</code></li>
  <li><code>sphinx.util.rfc1123_to_epoch</code></li>
  </ul>
  <p>Moved to <code>sphinx.util.exceptions</code>:</p>
  <ul>
  <li><code>sphinx.util.save_traceback</code></li>
  <li><code>sphinx.util.format_exception_cut_frames</code></li>
  </ul>
  </li>
  </ul>
  <h2>Features added</h2>
  <ul>
  <li>Cache doctrees in the build environment during the writing phase.</li>
  <li>Make all writing phase tasks support parallel execution.</li>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11072">#11072</a>: Use PEP 604 (<code>X | Y</code>) display conventions for <code>typing.Optional</code>
  and <code>typing.Optional</code> types within the Python domain and autodoc.</li>
  </ul>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/4e1004a9c581ff18a66522a426150aba144dc7fe"><code>4e1004a</code></a> Bump to 6.1.0 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/a2176d47b5ddba85fbb0db7658ae67b70e7fb0ca"><code>a2176d4</code></a> Fix deprecation warnings</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/2c104e9838713fdc4bb49ef8df9289f9f0381748"><code>2c104e9</code></a> Merge branch '6.0.x'</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/a27d262ffed11ef5717edfe93ae892c6f6e9fed5"><code>a27d262</code></a> Bump to 6.0.1 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/821569ea8af353a9ca56b44bf19b94be2b37ae22"><code>821569e</code></a> Add note for Pygments</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/222d366eadc1afa6c9344e9f0d3781a11a8c1ac4"><code>222d366</code></a> imgmath: Fix relative file path (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10965">#10965</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/c499f66012acb686442776ac283f5f78b1fd408a"><code>c499f66</code></a> Add SIM113 lint (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11057">#11057</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/0fbd8afc0533eb37d60763017a5f4bae13215796"><code>0fbd8af</code></a> Add missing default arguments in sphinx-apidoc.rst (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11084">#11084</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/f89f94354e70dbd99c47acd826f83b416a59c6b3"><code>f89f943</code></a> Remove flake8 plugins in favour of Ruff (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11085">#11085</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/04791156dbf39f8ca31fa2c4dfe4156c39099c97"><code>0479115</code></a> Suppress lint failures from Ruff 0.0.211 (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11086">#11086</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/sphinx-doc/sphinx/compare/v5.3.0...v6.1.0">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sphinx&package-manager=pip&previous-version=5.3.0&new-version=6.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1976.org.readthedocs.build/en/1976/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1976/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5G0XxH
title: Bump sphinx from 5.3.0 to 6.1.1
state: closed
created_at: 2023-01-06T13:02:12Z
updated_at: 2023-01-09T13:06:17Z
closed_at: 2023-01-09T13:06:14Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1977
type: pull
body:
  Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 5.3.0 to 6.1.1.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/releases">sphinx's releases</a>.</em></p>
  <blockquote>
  <h2>v6.1.1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.1.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b2</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/blob/v6.1.1/CHANGES">sphinx's changelog</a>.</em></p>
  <blockquote>
  <h1>Release 6.1.1 (released Jan 05, 2023)</h1>
  <h2>Bugs fixed</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11091">#11091</a>: Fix <code>util.nodes.apply_source_workaround</code> for <code>literal_block</code> nodes
  with no source information in the node or the node's parents.</li>
  </ul>
  <h1>Release 6.1.0 (released Jan 05, 2023)</h1>
  <h2>Dependencies</h2>
  <ul>
  <li>
  <p>Adopted the <code>Ruff</code>_ code linter.</p>
  <p>.. _Ruff: <a href="https://github.com/charliermarsh/ruff">https://github.com/charliermarsh/ruff</a></p>
  </li>
  </ul>
  <h2>Incompatible changes</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10979">#10979</a>: gettext: Removed support for pluralisation in <code>get_translation</code>.
  This was unused and complicated other changes to <code>sphinx.locale</code>.</li>
  </ul>
  <h2>Deprecated</h2>
  <ul>
  <li>
  <p><code>sphinx.util</code> functions:</p>
  <ul>
  <li>Renamed <code>sphinx.util.typing.stringify()</code>
  to <code>sphinx.util.typing.stringify_annotation()</code></li>
  <li>Moved <code>sphinx.util.xmlname_checker()</code>
  to <code>sphinx.builders.epub3._XML_NAME_PATTERN</code></li>
  </ul>
  <p>Moved to <code>sphinx.util.display</code>:</p>
  <ul>
  <li><code>sphinx.util.status_iterator</code></li>
  <li><code>sphinx.util.display_chunk</code></li>
  <li><code>sphinx.util.SkipProgressMessage</code></li>
  <li><code>sphinx.util.progress_message</code></li>
  </ul>
  <p>Moved to <code>sphinx.util.http_date</code>:</p>
  <ul>
  <li><code>sphinx.util.epoch_to_rfc1123</code></li>
  <li><code>sphinx.util.rfc1123_to_epoch</code></li>
  </ul>
  <p>Moved to <code>sphinx.util.exceptions</code>:</p>
  <ul>
  <li><code>sphinx.util.save_traceback</code></li>
  </ul>
  </li>
  </ul>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/77aaa8696a5554b68e9b7daf691ccd4943e7fe7b"><code>77aaa86</code></a> Bump to 6.1.1 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/476c115b0e080e543066795378c372519feab452"><code>476c115</code></a> Suppress <code>ValueError</code> in <code>apply_source_workaround</code> (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11092">#11092</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/c80d656caf7932595192cee68b076da576ce82cc"><code>c80d656</code></a> Bump version</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/4e1004a9c581ff18a66522a426150aba144dc7fe"><code>4e1004a</code></a> Bump to 6.1.0 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/a2176d47b5ddba85fbb0db7658ae67b70e7fb0ca"><code>a2176d4</code></a> Fix deprecation warnings</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/2c104e9838713fdc4bb49ef8df9289f9f0381748"><code>2c104e9</code></a> Merge branch '6.0.x'</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/a27d262ffed11ef5717edfe93ae892c6f6e9fed5"><code>a27d262</code></a> Bump to 6.0.1 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/821569ea8af353a9ca56b44bf19b94be2b37ae22"><code>821569e</code></a> Add note for Pygments</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/222d366eadc1afa6c9344e9f0d3781a11a8c1ac4"><code>222d366</code></a> imgmath: Fix relative file path (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10965">#10965</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/c499f66012acb686442776ac283f5f78b1fd408a"><code>c499f66</code></a> Add SIM113 lint (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11057">#11057</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/sphinx-doc/sphinx/compare/v5.3.0...v6.1.1">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sphinx&package-manager=pip&previous-version=5.3.0&new-version=6.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1977.org.readthedocs.build/en/1977/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1977/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5aw8Mr
title: Document datasette.urls.row and row_blob
state: closed
created_at: 2023-01-06T15:45:51Z
updated_at: 2023-01-09T14:30:00Z
closed_at: 2023-01-09T14:30:00Z
author_association: CONTRIBUTOR
type: issue
state_reason: not_planned
body:
  These are in the codebase but not in documentation. I think everything else in this class is documented.

  ```python
  class Urls:
      ...
      def row(self, database, table, row_path, format=None):
          path = f"{self.table(database, table)}/{row_path}"
          if format is not None:
              path = path_with_format(path=path, format=format)
          return PrefixedUrlString(path)

      def row_blob(self, database, table, row_path, column):
          return self.table(database, table) + "/{}.blob?_blob_column={}".format(
              row_path, urllib.parse.quote_plus(column)
          )
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1978/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5a15Ar
title: More useful error message if enable_load_extension is not available
state: closed
created_at: 2023-01-07T19:13:19Z
updated_at: 2023-01-08T00:21:23Z
closed_at: 2023-01-08T00:21:23Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I get this from:

      datasette --load-extension spatialite --get /-/versions.json

  ```
    File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/datasette/app.py", line 614, in _prepare_connection
      conn.enable_load_extension(True)
  AttributeError: 'sqlite3.Connection' object has no attribute 'enable_load_extension'
  ```
  It would be useful if Datasette caught this error and output something more friendly.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1979/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODEm0Qs5a3Pu9
title: Import thread, including self- and others' replies
state: open
created_at: 2023-01-08T09:51:06Z
updated_at: 2023-01-08T09:51:06Z
author_association: NONE
type: issue
body:
  statuses-lookup, home-timeline, mentions (only for auth'ed user) don't cover this.

  `twitter-to-sqlite fetch-thread tw-group1.db 1234123412341234`

  twitter-to-sqlite focuses on archiving users, but does not easily support archiving conversations or community activity.

  For reference, this is [implemented in twarc](https://sourcegraph.com/github.com/DocNow/twarc/-/blob/twarc/client.py?L708-766&subtree=true), using a search, optionally recursively.

  Other research suggests that this formerly, or currently, requires a [search query](https://stackoverflow.com/a/30480103/1020467), use of [undocumented `related_results` api](https://stackoverflow.com/a/9419346/1020467), or with requested inclusion of [newer conversation_id](https://stackoverflow.com/a/68115718/1020467) with subsequent query.

reactions:
  {"url": "https://api.github.com/repos/dogsheep/twitter-to-sqlite/issues/72/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5a46Nv
title: "Cannot sort table by id" when sortable_columns is used
state: open
created_at: 2023-01-09T03:21:33Z
updated_at: 2023-01-09T03:23:53Z
author_association: OWNER
type: issue
body:
  I had an instance with this in `metadata.yml`:

  ```yaml
  databases:
    timezones:
      tables:
        timezones:
          sortable_columns:
          - tzid
  ```
  When I clicked on the "Apply" button here:

  <img width="702" alt="image" src="https://user-images.githubusercontent.com/9599/211236149-6c85eca9-5200-440a-9bc8-a913cd8164f5.png">

  It sent me to `/timezones/timezones?_sort=id&id__exact=133` with the error message:

  > 500: Cannot sort table by id

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1980/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5a5Wbw
title: Canned query field labels truncated
state: open
created_at: 2023-01-09T06:04:24Z
updated_at: 2023-01-09T06:05:44Z
author_association: OWNER
type: issue
body:
  Eg here on mobile: https://timezones.datasette.io/timezones/by_point?longitude=-0.1406632&latitude=50.8246776

  ![107A1894-D1DA-4158-9EA3-40C840DD10E3](https://user-images.githubusercontent.com/9599/211248895-c922ce61-95d3-47ca-9314-dcff7c86afab.jpeg)

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1981/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5G-ZsQ
title: Bump sphinx from 5.3.0 to 6.1.2
state: closed
created_at: 2023-01-09T13:06:11Z
updated_at: 2023-01-10T02:03:21Z
closed_at: 2023-01-10T02:03:19Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1982
type: pull
body:
  Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 5.3.0 to 6.1.2.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/releases">sphinx's releases</a>.</em></p>
  <blockquote>
  <h2>v6.1.2</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.1.1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.1.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b2</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  <h2>v6.0.0b1</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/blob/master/CHANGES">sphinx's changelog</a>.</em></p>
  <blockquote>
  <h1>Release 6.1.2 (released Jan 07, 2023)</h1>
  <h2>Bugs fixed</h2>
  <ul>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11101">#11101</a>: LaTeX: <code>div.topic_padding</code> key of sphinxsetup documented at 5.1.0 was
  implemented with name <code>topic_padding</code></p>
  </li>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11099">#11099</a>: LaTeX: <code>shadowrule</code> key of sphinxsetup causes PDF build to crash
  since Sphinx 5.1.0</p>
  </li>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11096">#11096</a>: LaTeX: <code>shadowsize</code> key of sphinxsetup causes PDF build to crash
  since Sphinx 5.1.0</p>
  </li>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11095">#11095</a>: LaTeX: shadow of :dudir:<code>topic</code> and contents_ boxes not in page
  margin since Sphinx 5.1.0</p>
  <p>.. _contents: <a href="https://docutils.sourceforge.io/docs/ref/rst/directives.html#table-of-contents">https://docutils.sourceforge.io/docs/ref/rst/directives.html#table-of-contents</a></p>
  </li>
  <li>
  <p><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11100">#11100</a>: Fix copying images when running under parallel mode.</p>
  </li>
  </ul>
  <h1>Release 6.1.1 (released Jan 05, 2023)</h1>
  <h2>Bugs fixed</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11091">#11091</a>: Fix <code>util.nodes.apply_source_workaround</code> for <code>literal_block</code> nodes
  with no source information in the node or the node's parents.</li>
  </ul>
  <h1>Release 6.1.0 (released Jan 05, 2023)</h1>
  <h2>Dependencies</h2>
  <ul>
  <li>
  <p>Adopted the <code>Ruff</code>_ code linter.</p>
  <p>.. _Ruff: <a href="https://github.com/charliermarsh/ruff">https://github.com/charliermarsh/ruff</a></p>
  </li>
  </ul>
  <h2>Incompatible changes</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/10979">#10979</a>: gettext: Removed support for pluralisation in <code>get_translation</code>.
  This was unused and complicated other changes to <code>sphinx.locale</code>.</li>
  </ul>
  <h2>Deprecated</h2>
  <ul>
  <li>
  <p><code>sphinx.util</code> functions:</p>
  <ul>
  <li>Renamed <code>sphinx.util.typing.stringify()</code>
  to <code>sphinx.util.typing.stringify_annotation()</code></li>
  </ul>
  </li>
  </ul>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/393b40825282311a8ba81c830ef3c6fae9335c32"><code>393b408</code></a> Bump to 6.1.2 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/d8a5dd8364d19f693d5f017f615a8037784a0295"><code>d8a5dd8</code></a> Add note to CHANGES for PR 11100</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/a1cd19e601f89e1796d1992cbeaf6b476e2be6a0"><code>a1cd19e</code></a> Fix copying images under parallel execution (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11100">#11100</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/5008291b3d2ab92309f1dbc087b0c0b1c7f4e29f"><code>5008291</code></a> Ignore more checks in Ruff 0.0.213</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/6259c2b723186558823a9279c229462353b091ca"><code>6259c2b</code></a> Markup typo in docs</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/7945aeb22d21aed44c03eb42c2a64e75c5e8166c"><code>7945aeb</code></a> LaTeX: fix 5.1.0 bugs related to topic and contents boxes (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11102">#11102</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/77aaa8696a5554b68e9b7daf691ccd4943e7fe7b"><code>77aaa86</code></a> Bump to 6.1.1 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/476c115b0e080e543066795378c372519feab452"><code>476c115</code></a> Suppress <code>ValueError</code> in <code>apply_source_workaround</code> (<a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11092">#11092</a>)</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/c80d656caf7932595192cee68b076da576ce82cc"><code>c80d656</code></a> Bump version</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/4e1004a9c581ff18a66522a426150aba144dc7fe"><code>4e1004a</code></a> Bump to 6.1.0 final</li>
  <li>Additional commits viewable in <a href="https://github.com/sphinx-doc/sphinx/compare/v5.3.0...v6.1.2">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sphinx&package-manager=pip&previous-version=5.3.0&new-version=6.1.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1982.org.readthedocs.build/en/1982/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1982/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5a8hqx
title: Make CustomJSONEncoder a documented public API
state: open
created_at: 2023-01-09T15:27:05Z
updated_at: 2023-01-09T15:35:58Z
author_association: OWNER
type: issue
body:
  It's used by `datasette-geojson` here: https://github.com/eyeseast/datasette-geojson/commit/902bf135a5a33a0dc8264673d00a59a67cb05152

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1983/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5HCCY2
title: Upgrade Sphinx
state: closed
created_at: 2023-01-10T02:00:40Z
updated_at: 2023-01-10T02:02:33Z
closed_at: 2023-01-10T02:02:33Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1984
type: pull
body:
  Refs #1971

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1984.org.readthedocs.build/en/1984/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1984/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5bGkaC
title: Don't let Datasette(path) without a list cause weird errors
state: closed
created_at: 2023-01-11T05:17:44Z
updated_at: 2023-01-11T18:25:04Z
closed_at: 2023-01-11T18:25:04Z
author_association: OWNER
type: issue
state_reason: completed
body:
  I got a confusing `sqlite3.OperationalError: disk I/O error` error in my tests, it turned out it was because this:
  ```python
  ds = Datasette(path)
  ```
  Should have been this:
  ```python
  ds = Datasette([path])
  ```

  _Originally posted by @simonw in https://github.com/simonw/datasette-faiss/issues/1#issuecomment-1378252673_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1985/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5HJ55o
title: Bump sphinx from 6.1.2 to 6.1.3
state: closed
created_at: 2023-01-11T13:02:36Z
updated_at: 2023-03-29T06:09:50Z
closed_at: 2023-03-29T06:09:49Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1986
type: pull
body:
  Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 6.1.2 to 6.1.3.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/releases">sphinx's releases</a>.</em></p>
  <blockquote>
  <h2>v6.1.3</h2>
  <p>Changelog: <a href="https://www.sphinx-doc.org/en/master/changes.html">https://www.sphinx-doc.org/en/master/changes.html</a></p>
  </blockquote>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/sphinx-doc/sphinx/blob/master/CHANGES">sphinx's changelog</a>.</em></p>
  <blockquote>
  <h1>Release 6.1.3 (released Jan 10, 2023)</h1>
  <h2>Bugs fixed</h2>
  <ul>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11116">#11116</a>: Reverted to previous Sphinx 5 node copying method</li>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11117">#11117</a>: Reverted changes to parallel image processing from Sphinx 6.1.0</li>
  <li><a href="https://github-redirect.dependabot.com/sphinx-doc/sphinx/issues/11119">#11119</a>: Supress <code>ValueError</code> in the <code>linkcheck</code> builder</li>
  </ul>
  </blockquote>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/776d01eb6229f5d5384da17fc15df9d50fa8e87a"><code>776d01e</code></a> Bump to 6.1.3 final</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/a2e922ac6c58134d8ad19888de93d52c8a1de669"><code>a2e922a</code></a> CHANGES for Sphinx 6.1.3</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/31162a9b6335f2abce9ffb90b905a314f6bdfe6b"><code>31162a9</code></a> Handle exceptions for <code>get_node_source</code> and <code>get_node_line</code></li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/dcb4429abacda015f98875fe9489ced696155bd7"><code>dcb4429</code></a> Restore Sphinx 5 <code>nodes.Element</code> copying behaviour</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/2a7c40d07f4b0e0fd2a4bc942e74634c2df24dee"><code>2a7c40d</code></a> Undo parallel image changes</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/7841d3d9b2db9ed686fec7e2222c720dfa32c1b4"><code>7841d3d</code></a> Ignore more checks in Ruff 0.0.214</li>
  <li><a href="https://github.com/sphinx-doc/sphinx/commit/ddbc5b57f467823d600341ed1cfe5bedde5d7b64"><code>ddbc5b5</code></a> Bump version</li>
  <li>See full diff in <a href="https://github.com/sphinx-doc/sphinx/compare/v6.1.2...v6.1.3">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sphinx&package-manager=pip&previous-version=6.1.2&new-version=6.1.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1986.org.readthedocs.build/en/1986/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1986/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5bKZdT
title: installpython3.com is now a spam website
state: closed
created_at: 2023-01-11T17:55:12Z
updated_at: 2023-01-11T18:29:26Z
closed_at: 2023-01-11T18:29:25Z
author_association: OWNER
type: issue
state_reason: completed
body:
  Need to stop linking to it from the docs.

  I'll link to https://www.python.org/about/gettingstarted/ instead.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1987/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5bLX09
title: Reconsider pattern where plugins could break existing template context
state: open
created_at: 2023-01-11T21:13:43Z
updated_at: 2023-01-11T21:25:05Z
author_association: OWNER
type: issue
body:
  > I hadn't run into an issue with plugins like `datasette-template-sql` interfering with the existing context for other features before! Definitely not a good thing.

  _Originally posted by @simonw in https://github.com/simonw/datasette-write/issues/6#issuecomment-1379490596_
        

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1988/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5bUFUr
title: Suggestion: Hiding columns
state: open
created_at: 2023-01-13T09:33:32Z
updated_at: 2023-03-31T06:18:05Z
author_association: NONE
type: issue
body:
  As there's the possibility of [hiding tables](https://docs.datasette.io/en/stable/metadata.html#hiding-tables) - I've run into the **need of hiding specific columns** - data that's either not relevant for public or can't be shown due to privacy reasons. 

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1989/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5bUHqS
title: Suggestion: Highlight error messages ('These facets timed out')
state: open
created_at: 2023-01-13T09:40:58Z
updated_at: 2023-01-13T09:40:58Z
author_association: NONE
type: issue
body:
  I had trouble figuring out why faceting didn't work in some instances, it took a while before I noticed the _These facets timed out_ notice. 

  It might help if that would be highlighted, or fading out highlight - if one might think it would be too visually disturbing.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1990/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5baf-1
title: fts5 tables are not auto-detected and hidden
state: open
created_at: 2023-01-15T06:00:42Z
updated_at: 2023-01-20T04:54:24Z
author_association: NONE
type: issue
body:
  I set up a [Datasette instance](https://huggingface.co/spaces/Sygil/INE-dataset-explorer/tree/main) and was following the docs on full-text search.

  When I used fts4, datasette automatically hid the FTS tables and added the FTS search box where appropriate, but when I changed to fts5 it no longer does either.

  If I [manually set](https://huggingface.co/spaces/keturn/INED-datasette/blob/main/metadata.json#L9) `fts_table` for a view, then search does work as expected.

  My table and view creation code looks like this:
  ```py
  connection.execute("""CREATE TABLE IF NOT EXISTS
      captions(image_key text PRIMARY KEY, caption text NOT NULL)
  """)
   
  connection.execute("""CREATE VIRTUAL TABLE
      captions_fts USING
      fts5(caption, image_key UNINDEXED, content=captions)
  """)
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1991/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5HdwRg
title: Bump blacken-docs from 1.12.1 to 1.13.0
state: closed
created_at: 2023-01-16T13:05:05Z
updated_at: 2023-03-29T06:11:35Z
closed_at: 2023-03-29T06:11:34Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1992
type: pull
body:
  Bumps [blacken-docs](https://github.com/asottile/blacken-docs) from 1.12.1 to 1.13.0.
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/adamchainz/blacken-docs/blob/main/HISTORY.rst">blacken-docs's changelog</a>.</em></p>
  <blockquote>
  <h2>1.13.0 (2023-01-16)</h2>
  <ul>
  <li>
  <p>Note Adam Johnson is new maintainer.</p>
  </li>
  <li>
  <p>Require Black 22.1.0+.</p>
  </li>
  <li>
  <p>Add <code>--rst-literal-blocks</code> option, to also format text in reStructuredText literal blocks, starting with <code>::</code>.
  Sphinx highlights these with the project’s default language, which defaults to Python.</p>
  </li>
  </ul>
  </blockquote>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/1238e1d8f03e96a7ed9ad44937ea4348eb6b11b8"><code>1238e1d</code></a> Version 1.13.0</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/4e6dc07c9bd600d1bf274a15e314ef26596bf07d"><code>4e6dc07</code></a> Fix setup.cfg long_description_content_type</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/579a71a3572a721f0f910b0231933cce0215dd09"><code>579a71a</code></a> Standardize setup.cfg (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/212">#212</a>)</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/a6b2ba04face950d02af581ab147942b620fdb27"><code>a6b2ba0</code></a> Changelog entry about change in maintenance</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/3cf8b9a15c1f0dd86a6cd50e48eec1000b88059d"><code>3cf8b9a</code></a> Standard pre-commit config (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/211">#211</a>)</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/bcd36699e185fc0376c951650fe0cf13fa526e15"><code>bcd3669</code></a> Standardize test file name (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/210">#210</a>)</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/6d1771d057131075346efd78a7b9010685e137dc"><code>6d1771d</code></a> Remove setup.py (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/209">#209</a>)</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/4e5ab6e608c651ed266fd5a19f22c2f9fa46b5a6"><code>4e5ab6e</code></a> Improve README (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/208">#208</a>)</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/c19c57fdccdc80f8405426de96d8e9d97899d867"><code>c19c57f</code></a> Add support for reStructuredText literal blocks (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/196">#196</a>)</li>
  <li><a href="https://github.com/adamchainz/blacken-docs/commit/6af8099c1d77a9ba7a250b6dc57e44e1a6afa2f1"><code>6af8099</code></a> Move from tmpdir pytest fixture to tmp_path (<a href="https://github-redirect.dependabot.com/asottile/blacken-docs/issues/206">#206</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/asottile/blacken-docs/compare/v1.12.1...1.13.0">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=blacken-docs&package-manager=pip&previous-version=1.12.1&new-version=1.13.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1992.org.readthedocs.build/en/1992/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1992/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5bmn-V
title: Stuck on loading screen
state: open
created_at: 2023-01-17T18:33:49Z
updated_at: 2023-01-23T08:21:08Z
author_association: NONE
type: issue
body:
  Can’t actually open it!

  Downloaded today from the releases tab

  Running macOS13.1 

  ```
  bin/python3.9 --version
  Python 3.9.6
  Took 83ms
  bin/python3.9 --version
  Python 3.9.6
  Took 113ms
  bin/pip install datasette>=0.59 datasette-app-support>=0.11.6 datasette-vega>=0.6.2 datasette-cluster-map>=0.17.1 datasette-pretty-json>=0.2.1 datasette-edit-schema>=0.4 datasette-configure-fts>=1.1 datasette-leaflet>=0.2.2 --disable-pip-version-check
  Requirement already satisfied: datasette>=0.59 in lib/python3.9/site-packages (0.63)
  Requirement already satisfied: datasette-app-support>=0.11.6 in lib/python3.9/site-packages (0.11.6)
  Requirement already satisfied: datasette-vega>=0.6.2 in lib/python3.9/site-packages (0.6.2)
  Requirement already satisfied: datasette-cluster-map>=0.17.1 in lib/python3.9/site-packages (0.17.2)
  Requirement already satisfied: datasette-pretty-json>=0.2.1 in lib/python3.9/site-packages (0.2.2)
  Requirement already satisfied: datasette-edit-schema>=0.4 in lib/python3.9/site-packages (0.5.1)
  Requirement already satisfied: datasette-configure-fts>=1.1 in lib/python3.9/site-packages (1.1)
  Requirement already satisfied: datasette-leaflet>=0.2.2 in lib/python3.9/site-packages (0.2.2)
  Requirement already satisfied: click>=7.1.1 in lib/python3.9/site-packages (from datasette>=0.59) (8.1.3)
  Requirement already satisfied: hupper>=1.9 in lib/python3.9/site-packages (from datasette>=0.59) (1.10.3)
  Requirement already satisfied: pint>=0.9 in lib/python3.9/site-packages (from datasette>=0.59) (0.20.1)
  Requirement already satisfied: PyYAML>=5.3 in lib/python3.9/site-packages (from datasette>=0.59) (6.0)
  Requirement already satisfied: httpx>=0.20 in lib/python3.9/site-packages (from datasette>=0.59) (0.23.0)
  Requirement already satisfied: aiofiles>=0.4 in lib/python3.9/site-packages (from datasette>=0.59) (22.1.0)
  Requirement already satisfied: asgi-csrf>=0.9 in lib/python3.9/site-packages (from datasette>=0.59) (0.9)
  Requirement already satisfied: asgiref>=3.2.10 in lib/python3.9/site-packages (from datasette>=0.59) (3.5.2)
  Requirement already satisfied: uvicorn>=0.11 in lib/python3.9/site-packages (from datasette>=0.59) (0.19.0)
  Requirement already satisfied: itsdangerous>=1.1 in lib/python3.9/site-packages (from datasette>=0.59) (2.1.2)
  Requirement already satisfied: click-default-group-wheel>=1.2.2 in lib/python3.9/site-packages (from datasette>=0.59) (1.2.2)
  Requirement already satisfied: janus>=0.6.2 in lib/python3.9/site-packages (from datasette>=0.59) (1.0.0)
  Requirement already satisfied: pluggy>=1.0 in lib/python3.9/site-packages (from datasette>=0.59) (1.0.0)
  Requirement already satisfied: Jinja2>=2.10.3 in lib/python3.9/site-packages (from datasette>=0.59) (3.1.2)
  Requirement already satisfied: mergedeep>=1.1.1 in lib/python3.9/site-packages (from datasette>=0.59) (1.3.4)
  Requirement already satisfied: sqlite-utils in lib/python3.9/site-packages (from datasette-app-support>=0.11.6) (3.30)
  Requirement already satisfied: packaging in lib/python3.9/site-packages (from datasette-app-support>=0.11.6) (21.3)
  Requirement already satisfied: python-multipart in lib/python3.9/site-packages (from asgi-csrf>=0.9->datasette>=0.59) (0.0.5)
  Requirement already satisfied: httpcore<0.16.0,>=0.15.0 in lib/python3.9/site-packages (from httpx>=0.20->datasette>=0.59) (0.15.0)
  Requirement already satisfied: certifi in lib/python3.9/site-packages (from httpx>=0.20->datasette>=0.59) (2022.9.24)
  Requirement already satisfied: rfc3986[idna2008]<2,>=1.3 in lib/python3.9/site-packages (from httpx>=0.20->datasette>=0.59) (1.5.0)
  Requirement already satisfied: sniffio in lib/python3.9/site-packages (from httpx>=0.20->datasette>=0.59) (1.3.0)
  Requirement already satisfied: h11<0.13,>=0.11 in lib/python3.9/site-packages (from httpcore<0.16.0,>=0.15.0->httpx>=0.20->datasette>=0.59) (0.12.0)
  Requirement already satisfied: anyio==3.* in lib/python3.9/site-packages (from httpcore<0.16.0,>=0.15.0->httpx>=0.20->datasette>=0.59) (3.6.2)
  Requirement already satisfied: idna>=2.8 in lib/python3.9/site-packages (from anyio==3.*->httpcore<0.16.0,>=0.15.0->httpx>=0.20->datasette>=0.59) (3.4)
  Requirement already satisfied: typing-extensions>=3.7.4.3 in lib/python3.9/site-packages (from janus>=0.6.2->datasette>=0.59) (4.4.0)
  Requirement already satisfied: MarkupSafe>=2.0 in lib/python3.9/site-packages (from Jinja2>=2.10.3->datasette>=0.59) (2.1.1)
  Requirement already satisfied: tabulate in lib/python3.9/site-packages (from sqlite-utils->datasette-app-support>=0.11.6) (0.9.0)
  Requirement already satisfied: python-dateutil in lib/python3.9/site-packages (from sqlite-utils->datasette-app-support>=0.11.6) (2.8.2)
  Requirement already satisfied: sqlite-fts4 in lib/python3.9/site-packages (from sqlite-utils->datasette-app-support>=0.11.6) (1.0.3)
  Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in lib/python3.9/site-packages (from packaging->datasette-app-support>=0.11.6) (3.0.9)
  Requirement already satisfied: six>=1.5 in lib/python3.9/site-packages (from python-dateutil->sqlite-utils->datasette-app-support>=0.11.6) (1.16.0)
  Took 784ms
  ```
  STUCK

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1994/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5brwZl
title: foreign_keys error 500
state: open
created_at: 2023-01-18T15:27:36Z
updated_at: 2023-01-18T16:44:01Z
author_association: NONE
type: issue
body:
  **Error 500 expected string or bytes-like object**

  [espial-new.sqlite3.zip](https://github.com/simonw/datasette/files/10447965/espial-new.sqlite3.zip)

  run `datasette espial-new.sqlite3` & click on any table other than `User`

  ```
  /home/jon/.local/lib/python3.10/site-packages/datasette/app.py:814 in           │
  │ expand_foreign_keys                                                             │
  │                                                                                 │
  │    811 │   │   │   from {other_table}                                           │
  │    812 │   │   │   where {other_column} in ({placeholders})                     │
  │    813 │   │   """.format(                                                      │
  │ ❱  814 │   │   │   other_column=escape_sqlite(fk["other_column"]),              │
  │    815 │   │   │   label_column=escape_sqlite(label_column),                    │
  │    816 │   │   │   other_table=escape_sqlite(fk["other_table"]),                │
  │    817 │   │   │   placeholders=", ".join(["?"] * len(set(values))),            │
  │                                                                                 │
  │ ╭───────────────────────────── locals ──────────────────────────────╮           │
  │ │       column = 'user_id'                                          │           │
  │ │     database = 'espial-new'                                       │           │
  │ │           db = <Database: espial-new (mutable, size=53248)>       │           │
  │ │           fk = {                                                  │           │
  │ │                │   'column': 'user_id',                           │           │
  │ │                │   'other_table': 'user',                         │           │
  │ │                │   'other_column': None                           │           │
  │ │                }                                                  │           │
  │ │ foreign_keys = [                                                  │           │
  │ │                │   {                                              │           │
  │ │                │   │   'column': 'user_id',                       │           │
  │ │                │   │   'other_table': 'user',                     │           │
  │ │                │   │   'other_column': None                       │           │
  │ │                │   }                                              │           │
  │ │                ]                                                  │           │
  │ │ label_column = 'name'                                             │           │
  │ │  labeled_fks = {}                                                 │           │
  │ │         self = <datasette.app.Datasette object at 0x7f0f2e77e980> │           │
  │ │        table = 'bookmark'                                         │           │
  │ │       values = []                                                 │           │
  │ ╰───────────────────────────────────────────────────────────────────╯           │
  │                                                                                 │
  │ /home/jon/.local/lib/python3.10/site-packages/datasette/utils/__init__.py:346   │
  │ in escape_sqlite                                                                │
  │                                                                                 │
  │    343                                                                          │
  │    344                                                                          │
  │    345 def escape_sqlite(s):                                                    │
  │ ❱  346 │   if _boring_keyword_re.match(s) and (s.lower() not in reserved_words) │
  │    347 │   │   return s                                                         │
  │    348 │   else:                                                                │
  │    349 │   │   return f"[{s}]"                                                  │
  │                                                                                 │
  │ ╭─ locals ─╮                                                                    │
  │ │ s = None │                                                                    │
  │ ╰──────────╯                                                                    │
  ╰─────────────────────────────────────────────────────────────────────────────────╯
  TypeError: expected string or bytes-like object
  Traceback (most recent call last):
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/app.py", line 1354, in route_path
      response = await view(request, send)
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/views/base.py", line 134, in view
      return await self.dispatch_request(request)
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/views/base.py", line 91, in dispatch_request
      return await handler(request)
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/views/base.py", line 361, in get
      response_or_template_contexts = await self.data(request, **data_kwargs)
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/views/table.py", line 158, in data
      return await self._data_traced(request, default_labels, _next, _size)
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/views/table.py", line 603, in _data_traced
      await self.ds.expand_foreign_keys(
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/app.py", line 814, in expand_foreign_keys
      other_column=escape_sqlite(fk["other_column"]),
    File "/home/jon/.local/lib/python3.10/site-packages/datasette/utils/__init__.py", line 346, in escape_sqlite
      if _boring_keyword_re.match(s) and (s.lower() not in reserved_words):
  TypeError: expected string or bytes-like object
  INFO:     127.0.0.1:38574 - "GET /espial-new/bookmark HTTP/1.1" 500 Internal Server Error
  INFO:     127.0.0.1:38574 - "GET /-/static/app.css?d59929 HTTP/1.1" 200 OK
  ```

  Schema:
  ```
  CREATE TABLE IF NOT EXISTS "user"
    (
       "id"              INTEGER PRIMARY KEY,
       "name"            VARCHAR NOT NULL,
       "password_hash"   VARCHAR NOT NULL,
       "api_token"       VARCHAR NULL,
       "private_default" BOOLEAN NOT NULL,
       "archive_default" BOOLEAN NOT NULL,
       "privacy_lock"    BOOLEAN NOT NULL,
       CONSTRAINT "unique_user_name" UNIQUE ("name")
    );

  CREATE TABLE IF NOT EXISTS "bookmark"
    (
       "id"           INTEGER PRIMARY KEY,
       "user_id"      INTEGER NOT NULL REFERENCES "user" ON DELETE RESTRICT ON UPDATE RESTRICT,
       "slug"         VARCHAR NOT NULL DEFAULT (Lower(Hex(Randomblob(6)))),
       "href"         VARCHAR NOT NULL,
       "description"  VARCHAR NOT NULL,
       "extended"     VARCHAR NOT NULL,
       "time"         TIMESTAMP NOT NULL,
       "shared"       BOOLEAN NOT NULL,
       "to_read"      BOOLEAN NOT NULL,
       "selected"     BOOLEAN NOT NULL,
       "archive_href" VARCHAR NULL,
       CONSTRAINT "unique_user_href" UNIQUE ("user_id", "href"),
       CONSTRAINT "unique_user_slug" UNIQUE ("user_id", "slug")
    );

  CREATE TABLE IF NOT EXISTS "bookmark_tag"
    (
       "id"          INTEGER PRIMARY KEY,
       "user_id"     INTEGER NOT NULL REFERENCES "user" ON DELETE RESTRICT ON UPDATE RESTRICT,
       "tag"         VARCHAR NOT NULL,
       "bookmark_id" INTEGER NOT NULL REFERENCES "bookmark" ON DELETE RESTRICT ON UPDATE RESTRICT,
       "seq"         INTEGER NOT NULL,
       CONSTRAINT "unique_user_tag_bookmark_id" UNIQUE ("user_id", "tag", "bookmark_id"),
       CONSTRAINT "unique_user_bookmark_id_tag_seq" UNIQUE ("user_id", "bookmark_id", "tag", "seq")
    );

  CREATE TABLE IF NOT EXISTS "note"
    (
       "id"          INTEGER PRIMARY KEY,
       "user_id"     INTEGER NOT NULL REFERENCES "user" ON DELETE RESTRICT ON UPDATE RESTRICT,
       "slug"        VARCHAR NOT NULL DEFAULT (Lower(Hex(Randomblob(10)))),
       "length"      INTEGER NOT NULL,
       "title"       VARCHAR NOT NULL,
       "text"        VARCHAR NOT NULL,
       "is_markdown" BOOLEAN NOT NULL,
       "shared"      BOOLEAN NOT NULL DEFAULT false,
       "created"     TIMESTAMP NOT NULL,
       "updated"     TIMESTAMP NOT NULL
    );
  CREATE INDEX idx_bookmark_time ON bookmark (user_id, time DESC);
  CREATE INDEX idx_bookmark_tag_bookmark_id ON bookmark_tag (bookmark_id, id, tag, seq);
  CREATE INDEX idx_note_user_created ON note (user_id, created DESC); 
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1995/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5HpNYo
title: Document custom json encoder
state: open
created_at: 2023-01-18T16:54:14Z
updated_at: 2023-01-19T12:55:57Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/1996
type: pull
body:
  Closes #1983 

  All documentation here. Edits welcome.


  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1996.org.readthedocs.build/en/1996/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1996/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5ca076
title: Custom JSON encoder
state: open
created_at: 2023-01-20T09:19:40Z
updated_at: 2023-01-20T09:19:40Z
author_association: NONE
type: issue
body:
  It would be nice if we could specify a custom encoder (and decoder) for types that will need extra deserialisation – e.g., sets, enums or sparse matrices – or even project-specific types

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/521/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5cdB3R
title: `datasette --version` should also show the SQLite version
state: open
created_at: 2023-01-20T16:11:30Z
updated_at: 2023-01-20T18:19:06Z
author_association: OWNER
type: issue
body:
  Idea came up here: https://discord.com/channels/823971286308356157/823971286941302908/1066026473003159783

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1998/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5IQeKz
title: ?_extra= support (draft)
state: closed
created_at: 2023-01-21T04:55:18Z
updated_at: 2023-03-22T22:49:41Z
closed_at: 2023-03-22T22:49:40Z
author_association: OWNER
pull_request: simonw/datasette/pulls/1999
type: pull
body:
  Refs:
  - #262

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--1999.org.readthedocs.build/en/1999/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/1999/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5ch0G2
title: rewrite_sql hook
state: open
created_at: 2023-01-23T01:02:52Z
updated_at: 2023-01-23T06:08:01Z
author_association: CONTRIBUTOR
type: issue
body:
  I'm not sold that this is a good idea, but thought it'd be worth writing up a ticket. Proposal: add a hook like

  ```python
  def rewrite_sql(datasette, database, request, fn, sql, params)
  ```

  It would be called from Database.execute, Database.execute_write, Database.execute_write_script, Database.execute_write_many before running the user's SQL. `fn` would indicate which method was being used, in case that's relevant for the SQL inspection -- for example `execute` only permits a single statement.

  The hook could return a SQL statement to be executed instead, or an async function to be awaited on that returned the SQL to be executed.

  Plugins that could be written with this hook:

  - https://github.com/cldellow/datasette-ersatz-table-valued-functions would use this to avoid monkey-patching
  - a plugin to inspect and reject unsafe Spatialite function calls (reported by [Simon in Discord](https://discord.com/channels/823971286308356157/823971286941302908/1066438832293159004))
  - a plugin to do more general rewrites of queries to enforce table or row-level security, for example, based on the currently logged in actor's ID
  - a plugin to maintain audit tables when users write to a table
  - a plugin to cache expensive queries (eg the queries that drive facets) - these could allow stale reads if previously cached, then refresh them in an offline queue

  Flaws with this idea:

  `execute_fn` and `execute_write_fn` would not go through this hook, which limits the guarantees you can make about it for security purposes.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2000/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5cl2Q5
title: Add COLUMN_TYPE_MAPPING for timedelta
state: closed
created_at: 2023-01-23T16:49:54Z
updated_at: 2023-11-04T00:49:51Z
closed_at: 2023-11-04T00:49:51Z
author_association: NONE
type: issue
state_reason: completed
body:
  Currently trying to create a column with Python type `datetime.timedelta` results in an error:

  ```
  >>> from sqlite_utils import Database
  >>> db = Database("test.db")
  >>> test_tbl = db['test']
  >>> test_tbl.insert({'col1': datetime.timedelta()})
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/usr/local/lib/python3.10/dist-packages/sqlite_utils/db.py", line 2979, in insert
      return self.insert_all(
    File "/usr/local/lib/python3.10/dist-packages/sqlite_utils/db.py", line 3082, in insert_all
      self.create(
    File "/usr/local/lib/python3.10/dist-packages/sqlite_utils/db.py", line 1574, in create
      self.db.create_table(
    File "/usr/local/lib/python3.10/dist-packages/sqlite_utils/db.py", line 961, in create_table
      sql = self.create_table_sql(
    File "/usr/local/lib/python3.10/dist-packages/sqlite_utils/db.py", line 852, in create_table_sql
      column_type=COLUMN_TYPE_MAPPING[column_type],
  KeyError: <class 'datetime.timedelta'>
  ```

  The reason this would be useful is that `MySQLdb` uses `timedelta` for MySQL `TIME` columns:

  ```
  >>> import MySQLdb
  >>> conn = MySQLdb.connect(host='database', user='user', passwd='pw')
  >>> csr = conn.cursor()
  >>> csr.execute("SELECT CAST('11:20' AS TIME)")
  >>> tuple(csr)
  ((datetime.timedelta(seconds=40800),),)
  ```

  So currently any attempt to convert a MySQL DB with a `TIME` column using `db-to-sqlite` will result in the above error.

  I was rather surprised that `MySQLdb` uses `timedelta` for `TIME` columns but I see that [this column type](https://dev.mysql.com/doc/refman/8.0/en/time.html) is intended for time intervals as well as the time of day so it makes sense. 

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/522/reactions", "total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5cmktY
title: Datasette is not compatible with SQLite's strict quoting compilation option
state: open
created_at: 2023-01-23T19:10:07Z
updated_at: 2023-01-25T04:59:58Z
author_association: NONE
type: issue
body:
  I have linked Python3.11 on macOS against recent SQLite that was compiled using `-DSQLITE_DQS=0`. This option disables interpretation of double-quoted identifiers as string literals, described in the SQLite docs as a "MySQL 3.x misfeature". See https://www.sqlite.org/quirks.html#dblquote for background.

  Datasette uses the double-quote syntax in a number of key places, and is thus completely broken in this environment.

  My experience was to `pip install datasette`, then run `datasette serve -I my-data.db`. When I visit `http://127.0.0.1:8001` I get a 500 response.

  The error: `sqlite3.OperationalError: no such column: geometry_columns`

  The responsible SQL: `'select 1 from sqlite_master where tbl_name = "geometry_columns"'`

  I then installed datasette from GitHub master in development mode and changed the offending SQL to use correct quotes: `"select 1 from sqlite_master where tbl_name = 'geometry_columns'"`.

  With this change, I get a little further, but have the same problem with the first table name in my database (in my case, "Meta"):
  ```
  OperationalError: no such column: Meta
  Traceback (most recent call last):
    File "/Users/gwk/external/datasette/datasette/app.py", line 1522, in route_path
      response = await view(request, send)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/views/base.py", line 151, in view
      return await self.dispatch_request(request)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/views/base.py", line 105, in dispatch_request
      response = await handler(request)
                 ^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/views/index.py", line 70, in get
      "fts_table": await db.fts_table(table),
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/database.py", line 363, in fts_table
      return await self.execute_fn(lambda conn: detect_fts(conn, table))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/database.py", line 213, in execute_fn
      return await asyncio.get_event_loop().run_in_executor(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/local/py/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/thread.py", line 58, in run
      result = self.fn(*self.args, **self.kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/database.py", line 211, in in_thread
      return fn(conn)
             ^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/database.py", line 363, in <lambda>
      return await self.execute_fn(lambda conn: detect_fts(conn, table))
                                                ^^^^^^^^^^^^^^^^^^^^^^^
    File "/Users/gwk/external/datasette/datasette/utils/__init__.py", line 588, in detect_fts
      rows = conn.execute(detect_fts_sql(table)).fetchall()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  sqlite3.OperationalError: no such column: Meta
  INFO:     127.0.0.1:50258 - "GET / HTTP/1.1" 500 Internal Server Error
  ```

  I will try to continue playing with this, but I also hope that the datasette developers will enable this mode in a test environment as I am unlikely to be able to exercise all of the SQL in the codebase, or make a pull request very soon.

  Note that the DQS setting compile-time option can be overridden at runtime with calls to the C API:
  ```
  sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, (void*)0);
  sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, (void*)0);
  ```

  As far as I can tell, `sqlite3_db_config` is not exposed in Python, but perhaps we could figure out how to invoke it using `ctypes`.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2001/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5coKYo
title: Document how actors are displayed
state: open
created_at: 2023-01-24T00:08:49Z
updated_at: 2023-01-24T00:08:49Z
author_association: OWNER
type: issue
body:
  https://github.com/simonw/datasette/blob/e4ebef082de90db4e1b8527abc0d582b7ae0bc9d/datasette/utils/__init__.py#L1052-L1056

  This logic should be reflected in the documentation on https://docs.datasette.io/en/stable/authentication.html#actors

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2002/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5IdsD7
title: Show referring tables and rows when the referring foreign key is compound
state: open
created_at: 2023-01-24T21:31:31Z
updated_at: 2023-01-25T18:44:42Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/2003
type: pull
body:
  sqlite foreign keys can be compound, but that is not as well supported by datasette as single column foreign keys.

  in particular, 

  1. in a table view, there is not a link from the row to the referenced row if the foreign key is compound
  2. in a row view, there is no listing of tables and rows that refer to the focal row if those referencing foreign keys are compound.

  Both of these issues are discussed in #1099. 

  This PR only fixes the second one, because it's not clear what the right UX is for the first issue.

  ![Screenshot 2023-01-24 at 19-47-40 nlrb bargaining_unit](https://user-images.githubusercontent.com/536941/214454749-d53deead-4151-4329-a5d4-8a7a454de7d3.png)

  Some things that might not be desirable about this approach.

  1. it changes the external API, by changing `column` => `columns` and `other_column` => `other_columns` (see inline comment for more discussion.
  2. There are various places where the plural foreign keys have to be checked for length and discarded or transformed to singular. 

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2003/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5Ie5nA
title: use single quotes for string literals, fixes #2001
state: open
created_at: 2023-01-25T05:08:46Z
updated_at: 2023-02-01T06:37:18Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/2004
type: pull
body:
  This modernizes some uses of double quotes for string literals to use only single quotes, fixes simonw/datasette#2001

  While developing it, I manually enabled the stricter mode by using the code snippet at https://gist.github.com/cldellow/85bba507c314b127f85563869cd94820

  I think that code snippet isn't generally safe/portable, so I haven't tried to automate it in the tests.

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--2004.org.readthedocs.build/en/2004/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2004/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5c1azK
title: `extra_template_vars` should be OK to return `None`
state: open
created_at: 2023-01-26T01:40:45Z
updated_at: 2023-01-26T01:41:50Z
author_association: OWNER
type: issue
body:
  Got this exception and had to make sure it always returned `{}`:

  ```
    File ".../python3.11/site-packages/datasette/app.py", line 1049, in render_template
      assert isinstance(extra_vars, dict), "extra_vars is of type {}".format(
  AssertionError: extra_vars is of type <class 'NoneType'>
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2005/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODFE5qs5c1xaF
title: location history changes
state: open
created_at: 2023-01-26T03:57:25Z
updated_at: 2023-01-26T03:57:25Z
author_association: NONE
type: issue
body:
  not sure if each download is unique, but I had to change some things to work with the takeout zip I made 2023-01-25

  filename changed from "Location History.json" to "Records.json"

  `"timestampMs"` is not present, `"timestamp"` is roughly iso timestamp

  ```py
  def get_timestamp_ms(raw_timestamp):
      try:
          return datetime.datetime.strptime(raw_timestamp, "%Y-%m-%dT%H:%M:%SZ").timestamp()
      except ValueError:
          return datetime.datetime.strptime(raw_timestamp, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()

  def save_location_history(db, zf):
      location_history = json.load(
          zf.open("Takeout/Location History/Records.json")
      )
      db["location_history"].upsert_all(
          (
              {
                  "id": id_for_location_history(row),
                  "latitude": row["latitudeE7"] / 1e7,
                  "longitude": row["longitudeE7"] / 1e7,
                  "accuracy": row["accuracy"],
                  "timestampMs": get_timestamp_ms(row["timestamp"]),
                  "when": row["timestamp"],
              }
              for row in location_history["locations"]
          ),
          pk="id",
      )


  def id_for_location_history(row):
      # We want an ID that is unique but can be sorted by in
      # date order - so we use the isoformat date + the first
      # 6 characters of a hash of the JSON
      first_six = hashlib.sha1(
          json.dumps(row, separators=(",", ":"), sort_keys=True).encode("utf8")
      ).hexdigest()[:6]
      return "{}-{}".format(
          row['timestamp'],
          first_six,
      )
  ```

  example locations from mine

  ```json
  {
      "latitudeE7": 427220206,
      "longitudeE7": -923423972,
      "accuracy": 10,
      "deviceTag": -1312429967,
      "deviceDesignation": "PRIMARY",
      "timestamp": "2019-01-08T23:31:50.867Z"
    }
  ```

  ```json
  {
      "latitudeE7": 427011317,
      "longitudeE7": -923448300,
      "accuracy": 5,
      "deviceTag": -1312429967,
      "deviceDesignation": "PRIMARY",
      "timestamp": "2019-01-08T23:33:53Z"
    }, 
  ```

reactions:
  {"url": "https://api.github.com/repos/dogsheep/google-takeout-to-sqlite/issues/12/reactions", "total_count": 2, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 2}


node_id: I_kwDOBm6k_c5c5wUj
title: Teach `datasette publish` to pin to `datasette<1.0` in a 0.x release
state: open
created_at: 2023-01-26T19:17:40Z
updated_at: 2023-01-26T19:20:53Z
author_association: OWNER
type: issue
body:
  I just realized that when I ship Datasette 1.0 there may be automated deployments out there which could deploy the 1.0 version by accident, potentially breaking any customizations that aren't compatible with the 1.0 changes.

  I can hopefully help avoid that by shipping one last entry in the `0.x` series that ensures `datasette publish` pins to `<1.0` when it installs Datasette itself.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2006/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5dBaZW
state: open
created_at: 2023-01-28T02:40:10Z
updated_at: 2023-01-28T02:41:14Z
author_association: CONTRIBUTOR
type: issue
title:
  Feature request: trim all leading and trailing white space for all columns for all tables in a database

body:
  It's pretty common that i need to trim leading or trailing white space from lots of columns in a database a part of an initial ETL.

  I use the following recipe a lot, and it would be great to include this functionality into sqlite-utils

  `trimify.sql`
  ```sql
  select 'select group_concat(''update [' || name || '] set ['' || name || ''] = trim(['' || name || ''])'', '';
  '') || '';
  '' as sql_to_run from pragma_table_info('''||name||''');' from sqlite_schema;
  ```

  then something like:

  ```bash
  	sqlite3 example.db < scripts/trimify.sql > table_trim.sql && \
               sqlite3 $example.db < table_trim.sql > trim.sql && \
               sqlite3 $example.db < trim.sql
  ```

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/523/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5dBdLT
title: `render_cell()` hook should take an optional `request` argument
state: closed
created_at: 2023-01-28T03:13:00Z
updated_at: 2023-08-09T17:15:03Z
closed_at: 2023-01-28T03:34:26Z
author_association: OWNER
type: issue
state_reason: completed
body:
  From Discord: https://discordapp.com/channels/823971286308356157/996877076982415491/1068227071156965486

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2007/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5IvYKw
title: array facet: don't materialize unnecessary columns
state: open
created_at: 2023-01-28T19:33:40Z
updated_at: 2023-01-29T18:17:40Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/2008
type: pull
body:
  The presence of `inner.*` causes SQLite to materialize a row with all the columns. Those columns will be discarded later.

  Instead, we can select only the column we'll use. This lets SQLite's optimizer realize that the other columns in the CTE definition aren't needed.

  On a test table with 278K rows, 98K of which had an array, this speeds up the facet calculation from 4 sec to 1 sec.

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--2008.org.readthedocs.build/en/2008/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2008/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5dLYUB
title: Row page should default to card view
state: open
created_at: 2023-01-30T21:49:37Z
updated_at: 2023-01-30T21:52:06Z
author_association: OWNER
type: issue
body:
  Datasette currently uses the same table layout on the row pages as it does on the table pages:

  https://datasette.io/content/pypi_packages?_sort=name&name__exact=datasette-column-inspect

  <img width="1068" alt="image" src="https://user-images.githubusercontent.com/9599/215602793-b15dad48-c3e9-4f34-9875-3e79b7aa586d.png">

  https://datasette.io/content/pypi_packages/datasette-column-inspect

  <img width="1068" alt="image" src="https://user-images.githubusercontent.com/9599/215602883-9d714eec-3908-493e-93d0-c788af47ba21.png">

  If you shrink down to mobile width you get this instead, on both of those pages:

  <img width="613" alt="image" src="https://user-images.githubusercontent.com/9599/215602964-b95aa089-0269-4647-beae-66fffad332f5.png">

  I think that view, which I think of as the "card view", is plain better if you're looking at just a single row - and it (or a variant of it) should be the default presentation on the row page.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2010/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5dRH7N
title: Applied facet did not result in an "x" icon to dismiss it
state: open
created_at: 2023-01-31T17:57:44Z
updated_at: 2023-01-31T17:58:54Z
author_association: OWNER
type: issue
body:
  ![CleanShot 2023-01-31 at 09 55 56@2x](https://user-images.githubusercontent.com/9599/215843684-1761a230-d490-4f87-be6d-186319366794.png)

  That's against this data https://data.sfgov.org/City-Management-and-Ethics/Supplier-Contracts/cqi5-hm2d imported using https://datasette.io/plugins/datasette-socrata

  It's for `Contract Type` of `Non-Purchasing Contract (Rents, etc.)` - so possible that some of the spaces or punctuation in either the name of the value tripped up the code that decides if the X icon should be displayed.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2011/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5dRJGv
title: Missing space in database summary
state: open
created_at: 2023-01-31T18:01:13Z
updated_at: 2023-01-31T18:01:13Z
author_association: OWNER
type: issue
body:
  Spotted this on an instance index page:

  <img width="441" alt="image" src="https://user-images.githubusercontent.com/9599/215844680-9648fefa-dfbb-4ed6-bbbf-c3891e4dbdcc.png">

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2012/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5dSr_e
title: Datasette uses non-standard quoting for identifiers
state: open
created_at: 2023-02-01T00:05:39Z
updated_at: 2023-02-01T00:06:30Z
author_association: CONTRIBUTOR
type: issue
body:
  Related to #2001, but where #2001 was about literals, this is about identifiers

  From https://www.sqlite.org/lang_keywords.html:

  > "keyword"  A keyword in double-quotes is an identifier.
  > [keyword]   A keyword enclosed in square brackets is an identifier. This is not standard SQL. This quoting mechanism is used by MS Access and SQL Server and is included in SQLite for compatibility.

  Datasette uses this quoting here -- https://github.com/simonw/datasette/blob/0b4a28691468b5c758df74fa1d72a823813c96bf/datasette/utils/__init__.py#L345-L349, in some of the other DB access code, and in some of the test fixtures.

  Migrating to standard double quote identifiers would make it easier to get Datasette working with alternative backends

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2013/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: PR_kwDOBm6k_c5JAcGy
title: Bump black from 22.12.0 to 23.1.0
state: closed
created_at: 2023-02-01T13:06:16Z
updated_at: 2023-03-29T06:09:14Z
closed_at: 2023-03-29T06:09:12Z
author_association: CONTRIBUTOR
pull_request: simonw/datasette/pulls/2014
type: pull
body:
  Bumps [black](https://github.com/psf/black) from 22.12.0 to 23.1.0.
  <details>
  <summary>Release notes</summary>
  <p><em>Sourced from <a href="https://github.com/psf/black/releases">black's releases</a>.</em></p>
  <blockquote>
  <h2>23.1.0</h2>
  <h3>Highlights</h3>
  <p>This is the first release of 2023, and following our <a href="https://black.readthedocs.io/en/stable/the_black_code_style/index.html#stability-policy">stability policy</a>, it comes with a number of improvements to our stable style, notably improvements to empty line handling and the removal of redundant parentheses in several contexts.</p>
  <p>There are also many changes to the preview style; try out <code>black --preview</code> and give us feedback to help us set the stable style for next year.</p>
  <p>In addition to style changes, Black now automatically infers the supported Python versions from your <code>pyproject.toml</code> file, removing the need to set Black's target versions separately.</p>
  <h3>Stable style</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Introduce the 2023 stable style, which incorporates most aspects of last year's preview style (<a href="https://github-redirect.dependabot.com/psf/black/issues/3418">#3418</a>). Specific changes:
  <ul>
  <li>Enforce empty lines before classes and functions with sticky leading comments (<a href="https://github-redirect.dependabot.com/psf/black/issues/3302">#3302</a>) (22.12.0)</li>
  <li>Reformat empty and whitespace-only files as either an empty file (if no newline is present) or as a single newline character (if a newline is present) (<a href="https://github-redirect.dependabot.com/psf/black/issues/3348">#3348</a>) (22.12.0)</li>
  <li>Correctly handle trailing commas that are inside a line's leading non-nested parens (<a href="https://github-redirect.dependabot.com/psf/black/issues/3370">#3370</a>) (22.12.0)</li>
  <li><code>--skip-string-normalization</code> / <code>-S</code> now prevents docstring prefixes from being normalized as expected (<a href="https://github-redirect.dependabot.com/psf/black/issues/3168">#3168</a>) (since 22.8.0)</li>
  <li>When using <code>--skip-magic-trailing-comma</code> or <code>-C</code>, trailing commas are stripped from subscript expressions with more than 1 element (<a href="https://github-redirect.dependabot.com/psf/black/issues/3209">#3209</a>) (22.8.0)</li>
  <li>Fix a string merging/split issue when a comment is present in the middle of implicitly concatenated strings on its own line (<a href="https://github-redirect.dependabot.com/psf/black/issues/3227">#3227</a>) (22.8.0)</li>
  <li>Docstring quotes are no longer moved if it would violate the line length limit (<a href="https://github-redirect.dependabot.com/psf/black/issues/3044">#3044</a>, <a href="https://github-redirect.dependabot.com/psf/black/issues/3430">#3430</a>) (22.6.0)</li>
  <li>Parentheses around return annotations are now managed (<a href="https://github-redirect.dependabot.com/psf/black/issues/2990">#2990</a>) (22.6.0)</li>
  <li>Remove unnecessary parentheses around awaited objects (<a href="https://github-redirect.dependabot.com/psf/black/issues/2991">#2991</a>) (22.6.0)</li>
  <li>Remove unnecessary parentheses in <code>with</code> statements (<a href="https://github-redirect.dependabot.com/psf/black/issues/2926">#2926</a>) (22.6.0)</li>
  <li>Remove trailing newlines after code block open (<a href="https://github-redirect.dependabot.com/psf/black/issues/3035">#3035</a>) (22.6.0)</li>
  <li>Code cell separators <code>#%%</code> are now standardised to <code># %%</code> (<a href="https://github-redirect.dependabot.com/psf/black/issues/2919">#2919</a>) (22.3.0)</li>
  <li>Remove unnecessary parentheses from <code>except</code> statements (<a href="https://github-redirect.dependabot.com/psf/black/issues/2939">#2939</a>) (22.3.0)</li>
  <li>Remove unnecessary parentheses from tuple unpacking in <code>for</code> loops (<a href="https://github-redirect.dependabot.com/psf/black/issues/2945">#2945</a>) (22.3.0)</li>
  <li>Avoid magic-trailing-comma in single-element subscripts (<a href="https://github-redirect.dependabot.com/psf/black/issues/2942">#2942</a>) (22.3.0)</li>
  </ul>
  </li>
  <li>Fix a crash when a colon line is marked between <code># fmt: off</code> and <code># fmt: on</code> (<a href="https://github-redirect.dependabot.com/psf/black/issues/3439">#3439</a>)</li>
  </ul>
  <h3>Preview style</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Format hex codes in unicode escape sequences in string literals (<a href="https://github-redirect.dependabot.com/psf/black/issues/2916">#2916</a>)</li>
  <li>Add parentheses around <code>if</code>-<code>else</code> expressions (<a href="https://github-redirect.dependabot.com/psf/black/issues/2278">#2278</a>)</li>
  <li>Improve performance on large expressions that contain many strings (<a href="https://github-redirect.dependabot.com/psf/black/issues/3467">#3467</a>)</li>
  <li>Fix a crash in preview style with assert + parenthesized string (<a href="https://github-redirect.dependabot.com/psf/black/issues/3415">#3415</a>)</li>
  <li>Fix crashes in preview style with walrus operators used in function return annotations and except clauses (<a href="https://github-redirect.dependabot.com/psf/black/issues/3423">#3423</a>)</li>
  <li>Fix a crash in preview advanced string processing where mixed implicitly concatenated regular and f-strings start with an empty span (<a href="https://github-redirect.dependabot.com/psf/black/issues/3463">#3463</a>)</li>
  <li>Fix a crash in preview advanced string processing where a standalone comment is placed before a dict's value (<a href="https://github-redirect.dependabot.com/psf/black/issues/3469">#3469</a>)</li>
  <li>Fix an issue where extra empty lines are added when a decorator has <code># fmt: skip</code> applied or there is a standalone comment between decorators (<a href="https://github-redirect.dependabot.com/psf/black/issues/3470">#3470</a>)</li>
  <li>Do not put the closing quotes in a docstring on a separate line, even if the line is too long (<a href="https://github-redirect.dependabot.com/psf/black/issues/3430">#3430</a>)</li>
  <li>Long values in dict literals are now wrapped in parentheses; correspondingly unnecessary parentheses around short values in dict literals are now removed; long string lambda values are now wrapped in parentheses (<a href="https://github-redirect.dependabot.com/psf/black/issues/3440">#3440</a>)</li>
  <li>Fix two crashes in preview style involving edge cases with docstrings (<a href="https://github-redirect.dependabot.com/psf/black/issues/3451">#3451</a>)</li>
  <li>Exclude string type annotations from improved string processing; fix crash when the return type annotation is stringified and spans across multiple lines (<a href="https://github-redirect.dependabot.com/psf/black/issues/3462">#3462</a>)</li>
  <li>Wrap multiple context managers in parentheses when targeting Python 3.9+ (<a href="https://github-redirect.dependabot.com/psf/black/issues/3489">#3489</a>)</li>
  <li>Fix several crashes in preview style with walrus operators used in <code>with</code> statements or tuples (<a href="https://github-redirect.dependabot.com/psf/black/issues/3473">#3473</a>)</li>
  <li>Fix an invalid quote escaping bug in f-string expressions where it produced invalid code. Implicitly concatenated f-strings with different quotes can now be merged or quote-normalized by changing the quotes used in expressions. (<a href="https://github-redirect.dependabot.com/psf/black/issues/3509">#3509</a>)</li>
  </ul>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Changelog</summary>
  <p><em>Sourced from <a href="https://github.com/psf/black/blob/main/CHANGES.md">black's changelog</a>.</em></p>
  <blockquote>
  <h2>23.1.0</h2>
  <h3>Highlights</h3>
  <p>This is the first release of 2023, and following our
  <a href="https://black.readthedocs.io/en/stable/the_black_code_style/index.html#stability-policy">stability policy</a>,
  it comes with a number of improvements to our stable style, including improvements to
  empty line handling, removal of redundant parentheses in several contexts, and output
  that highlights implicitly concatenated strings better.</p>
  <p>There are also many changes to the preview style; try out <code>black --preview</code> and give us
  feedback to help us set the stable style for next year.</p>
  <p>In addition to style changes, Black now automatically infers the supported Python
  versions from your <code>pyproject.toml</code> file, removing the need to set Black's target
  versions separately.</p>
  <h3>Stable style</h3>
  <!-- raw HTML omitted -->
  <ul>
  <li>Introduce the 2023 stable style, which incorporates most aspects of last year's
  preview style (<a href="https://github-redirect.dependabot.com/psf/black/issues/3418">#3418</a>). Specific changes:
  <ul>
  <li>Enforce empty lines before classes and functions with sticky leading comments
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3302">#3302</a>) (22.12.0)</li>
  <li>Reformat empty and whitespace-only files as either an empty file (if no newline is
  present) or as a single newline character (if a newline is present) (<a href="https://github-redirect.dependabot.com/psf/black/issues/3348">#3348</a>)
  (22.12.0)</li>
  <li>Implicitly concatenated strings used as function args are now wrapped inside
  parentheses (<a href="https://github-redirect.dependabot.com/psf/black/issues/3307">#3307</a>) (22.12.0)</li>
  <li>Correctly handle trailing commas that are inside a line's leading non-nested parens
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3370">#3370</a>) (22.12.0)</li>
  <li><code>--skip-string-normalization</code> / <code>-S</code> now prevents docstring prefixes from being
  normalized as expected (<a href="https://github-redirect.dependabot.com/psf/black/issues/3168">#3168</a>) (since 22.8.0)</li>
  <li>When using <code>--skip-magic-trailing-comma</code> or <code>-C</code>, trailing commas are stripped from
  subscript expressions with more than 1 element (<a href="https://github-redirect.dependabot.com/psf/black/issues/3209">#3209</a>) (22.8.0)</li>
  <li>Implicitly concatenated strings inside a list, set, or tuple are now wrapped inside
  parentheses (<a href="https://github-redirect.dependabot.com/psf/black/issues/3162">#3162</a>) (22.8.0)</li>
  <li>Fix a string merging/split issue when a comment is present in the middle of
  implicitly concatenated strings on its own line (<a href="https://github-redirect.dependabot.com/psf/black/issues/3227">#3227</a>) (22.8.0)</li>
  <li>Docstring quotes are no longer moved if it would violate the line length limit
  (<a href="https://github-redirect.dependabot.com/psf/black/issues/3044">#3044</a>, <a href="https://github-redirect.dependabot.com/psf/black/issues/3430">#3430</a>) (22.6.0)</li>
  <li>Parentheses around return annotations are now managed (<a href="https://github-redirect.dependabot.com/psf/black/issues/2990">#2990</a>) (22.6.0)</li>
  <li>Remove unnecessary parentheses around awaited objects (<a href="https://github-redirect.dependabot.com/psf/black/issues/2991">#2991</a>) (22.6.0)</li>
  <li>Remove unnecessary parentheses in <code>with</code> statements (<a href="https://github-redirect.dependabot.com/psf/black/issues/2926">#2926</a>) (22.6.0)</li>
  <li>Remove trailing newlines after code block open (<a href="https://github-redirect.dependabot.com/psf/black/issues/3035">#3035</a>) (22.6.0)</li>
  <li>Code cell separators <code>#%%</code> are now standardised to <code># %%</code> (<a href="https://github-redirect.dependabot.com/psf/black/issues/2919">#2919</a>) (22.3.0)</li>
  <li>Remove unnecessary parentheses from <code>except</code> statements (<a href="https://github-redirect.dependabot.com/psf/black/issues/2939">#2939</a>) (22.3.0)</li>
  <li>Remove unnecessary parentheses from tuple unpacking in <code>for</code> loops (<a href="https://github-redirect.dependabot.com/psf/black/issues/2945">#2945</a>) (22.3.0)</li>
  <li>Avoid magic-trailing-comma in single-element subscripts (<a href="https://github-redirect.dependabot.com/psf/black/issues/2942">#2942</a>) (22.3.0)</li>
  </ul>
  </li>
  </ul>
  <!-- raw HTML omitted -->
  </blockquote>
  <p>... (truncated)</p>
  </details>
  <details>
  <summary>Commits</summary>
  <ul>
  <li><a href="https://github.com/psf/black/commit/b0d1fba7ac3be53c71fb0d3211d911e629f8aecb"><code>b0d1fba</code></a> Prepare release 23.1.0 (<a href="https://github-redirect.dependabot.com/psf/black/issues/3536">#3536</a>)</li>
  <li><a href="https://github.com/psf/black/commit/69ca0a4c7a365c5f5eea519a90980bab72cab764"><code>69ca0a4</code></a> Infer target version based on project metadata (<a href="https://github-redirect.dependabot.com/psf/black/issues/3219">#3219</a>)</li>
  <li><a href="https://github.com/psf/black/commit/c4bd2e31ceeac84d68592986fe70920f3d3d0443"><code>c4bd2e3</code></a> Draft for Black 2023 stable style (<a href="https://github-redirect.dependabot.com/psf/black/issues/3418">#3418</a>)</li>
  <li><a href="https://github.com/psf/black/commit/226cbf0226ee3bc26972357ba54c36409e9a84ae"><code>226cbf0</code></a> Fix unsafe cast in linegen.py w/ await yield handling (<a href="https://github-redirect.dependabot.com/psf/black/issues/3533">#3533</a>)</li>
  <li><a href="https://github.com/psf/black/commit/f4ebc683208d095b252b87147d002e925c9c1171"><code>f4ebc68</code></a> Upgrade isort (<a href="https://github-redirect.dependabot.com/psf/black/issues/3534">#3534</a>)</li>
  <li><a href="https://github.com/psf/black/commit/6407ebb870afe0062ee581abdea07c1ef5213d31"><code>6407ebb</code></a> Remove Python version in the_basics.md (<a href="https://github-redirect.dependabot.com/psf/black/issues/3528">#3528</a>)</li>
  <li><a href="https://github.com/psf/black/commit/196b1f349eb2baa9bbbc483226874cc01fb7567d"><code>196b1f3</code></a> Fix <code>black --help</code> output for <code>--python-cell-magics</code> option to be reproducibl...</li>
  <li><a href="https://github.com/psf/black/commit/d950f15987a49a5f3e37127ec718b4c12666b8cf"><code>d950f15</code></a> Update document now that paren wrapping CMs on Python 3.9+ is implemented (<a href="https://github-redirect.dependabot.com/psf/black/issues/3">#3</a>...</li>
  <li><a href="https://github.com/psf/black/commit/a36878eb2f375e2ac1e13052f663909f3835ec46"><code>a36878e</code></a> Fix an invalid quote escaping bug in f-string expressions (<a href="https://github-redirect.dependabot.com/psf/black/issues/3509">#3509</a>)</li>
  <li><a href="https://github.com/psf/black/commit/eabff673b37c5430d4cf72fa050a189a57be2deb"><code>eabff67</code></a> Format hex code in unicode escape sequences in string literals (<a href="https://github-redirect.dependabot.com/psf/black/issues/2916">#2916</a>)</li>
  <li>Additional commits viewable in <a href="https://github.com/psf/black/compare/22.12.0...23.1.0">compare view</a></li>
  </ul>
  </details>
  <br />


  [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=black&package-manager=pip&previous-version=22.12.0&new-version=23.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

  Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

  [//]: # (dependabot-automerge-start)
  [//]: # (dependabot-automerge-end)

  ---

  <details>
  <summary>Dependabot commands and options</summary>
  <br />

  You can trigger Dependabot actions by commenting on this PR:
  - `@dependabot rebase` will rebase this PR
  - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
  - `@dependabot merge` will merge this PR after your CI passes on it
  - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
  - `@dependabot cancel merge` will cancel a previously requested merge and block automerging
  - `@dependabot reopen` will reopen this PR if it is closed
  - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


  </details>

  <!-- readthedocs-preview datasette start -->
  ----
  :books: Documentation preview :books:: https://datasette--2014.org.readthedocs.build/en/2014/

  <!-- readthedocs-preview datasette end -->

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2014/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDODFdgUs5dmgiA
title: Deploy demo job is failing due to rate limit
state: open
created_at: 2023-02-03T20:05:01Z
updated_at: 2023-12-08T14:50:15Z
author_association: MEMBER
body: https://github.com/dogsheep/github-to-sqlite/actions/runs/4080058087/jobs/7032116511
type: issue
reactions:
  {"url": "https://api.github.com/repos/dogsheep/github-to-sqlite/issues/79/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5dprer
title: Database metadata fields like description are not available in the index page template's context
state: open
created_at: 2023-02-05T02:25:53Z
updated_at: 2023-02-05T22:56:43Z
author_association: NONE
type: issue
body:
  When looping through `databases` in the index.html template, I'd like to print the description of each database alongside its name. But it appears that isn't passed in from the view, unless I'm missing it. It would be great to have that.

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2016/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOBm6k_c5drmtA
title: `check_visibility` gives confusing (wrong?) results if permission is `None`
state: open
created_at: 2023-02-06T01:03:08Z
updated_at: 2023-02-06T01:03:46Z
author_association: CONTRIBUTOR
type: issue
body:
  I'm trying to gate access to an edit UI on the user having `update-row` on the underlying view or table.

  I expected [datasette.check_visibility](https://docs.datasette.io/en/latest/internals.html#await-check-visibility-actor-action-none-resource-none-permissions-none) to be a good way to do this:

  ```python
      visible, private = await datasette.check_visibility(
          request.actor,
          permissions=[
              ("update-row", (database, table)),
          ],
      )

      if not visible:
          return None
  ```

  But `visible` is returning true, even when there is no explicit `update-row` permission. (In this case, `request.actor` is `None`.)

  Based on [the update-row permissions docs](https://docs.datasette.io/en/latest/authentication.html#update-row), I expected this to be default deny, and so no explicit permission would result in false.

  I think the root cause is that `check_visibility` calls `ensure_permissions` and expects it to throw if the permission is not available.

  But `ensure_permissions` does not throw when `permission_allowed` returns None: https://github.com/simonw/datasette/blob/1.0a2/datasette/app.py#L825-L829

reactions:
  {"url": "https://api.github.com/repos/simonw/datasette/issues/2018/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


node_id: I_kwDOCGYnMM5dvoL8
title: Transformation type `--type DATETIME`
state: closed
created_at: 2023-02-06T15:18:42Z
updated_at: 2023-02-15T12:10:54Z
closed_at: 2023-02-15T12:10:54Z
author_association: NONE
type: issue
state_reason: completed
body:
  Hey. Currently i do transformation with the type `--type TEXT`, but i noticed using the sqlalchemy based library [dataset](https://github.com/pudo/dataset) that is reading and writing differ depending on the column types `TEXT`, `DATETIME`.

  Is it possible to alter a column type to `DATETIME` somehow using Sqlite-Utils?

reactions:
  {"url": "https://api.github.com/repos/simonw/sqlite-utils/issues/524/reactions", "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0}


