{"html_url": "https://github.com/simonw/sqlite-utils/issues/297#issuecomment-1732018273", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/297", "id": 1732018273, "node_id": "IC_kwDOCGYnMM5nPIBh", "user": {"value": 1108600, "label": "radusuciu"}, "created_at": "2023-09-22T20:49:51Z", "updated_at": "2023-09-22T20:49:51Z", "author_association": "NONE", "body": "This would be awesome to have for multi-gig tsv and csv files! I'm currently looking at a 10 hour countdown for one such important. Not a problem because I'm lazy and happy to let it run and check on it tomorrow..", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 944846776, "label": "Option for importing CSV data using the SQLite .import mechanism"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730458954", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730458954, "node_id": "IC_kwDOBm6k_c5nJLVK", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:57:39Z", "updated_at": "2023-09-21T22:57:48Z", "author_association": "OWNER", "body": "Worth noting that it already sets `--cors` automatically without you needing to specify it:\r\n\r\nhttps://github.com/simonw/datasette/blob/d97e82df3c8a3f2e97038d7080167be9bb74a68d/datasette/utils/__init__.py#L374-L374\r\n\r\nI wonder if that's actually surprising behaviour that we should change before 1.0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730457374", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730457374, "node_id": "IC_kwDOBm6k_c5nJK8e", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:56:18Z", "updated_at": "2023-09-21T22:56:18Z", "author_association": "OWNER", "body": "Maybe I should add `--cors` and `--crossdb` to `datasette publish cloudrun` as well?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730446937", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730446937, "node_id": "IC_kwDOBm6k_c5nJIZZ", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:46:42Z", "updated_at": "2023-09-21T22:46:52Z", "author_association": "OWNER", "body": "Found more when I [searched for YAML](https://github.com/search?q=datasette+publish+extra-options++language%3AYAML&type=code).\r\n\r\nHere's the most interesting: https://github.com/labordata/warehouse/blob/0029a72fc1ceae9091932da6566f891167179012/.github/workflows/build.yml#L59\r\n\r\n`--extra-options=\"--crossdb --setting sql_time_limit_ms 100000 --cors --setting facet_time_limit_ms 500 --setting allow_facet off --setting trace_debug 1\"`\r\n\r\nUses both `--cors` and `--crossdb`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730441613", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730441613, "node_id": "IC_kwDOBm6k_c5nJHGN", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:42:12Z", "updated_at": "2023-09-21T22:42:12Z", "author_association": "OWNER", "body": "https://github.com/search?q=datasette+publish+extra-options+language%3AShell&type=code&l=Shell shows 17 matches, I'll copy in illustrative examples here:\r\n\r\n```\r\n--extra-options=\"--setting sql_time_limit_ms 5000\"\r\n--extra-options=\"--config default_cache_ttl:3600 --config hash_urls:1\"\r\n--extra-options \"--setting sql_time_limit_ms 3500 --setting default_page_size 20 --setting trace_debug 1\"\r\n--extra-options=\"--config default_page_size:50 --config sql_time_limit_ms:30000 --config facet_time_limit_ms:10000\"\r\n--extra-options=\"--setting sql_time_limit_ms 5000\"\r\n--extra-options \"--setting suggest_facets off --setting allow_download on --setting truncate_cells_html 0 --setting max_csv_mb 0 --setting sql_time_limit_ms 2000\"\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730438503", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730438503, "node_id": "IC_kwDOBm6k_c5nJGVn", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:38:10Z", "updated_at": "2023-09-21T22:38:10Z", "author_association": "OWNER", "body": "I'd really like to remove `--extra-options`. I think the new design makes that completely obsolete?\r\n\r\nMaybe it doesn't. You still need `--extra-options` for the `--crossdb` option for example.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730437934", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730437934, "node_id": "IC_kwDOBm6k_c5nJGMu", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:37:22Z", "updated_at": "2023-09-21T22:37:22Z", "author_association": "OWNER", "body": "Here's the full help for Cloud Run at the moment:\r\n```bash\r\ndatasette publish cloudrun --help\r\n```\r\n```\r\nUsage: datasette publish cloudrun [OPTIONS] [FILES]...\r\n\r\n Publish databases to Datasette running on Cloud Run\r\n\r\nOptions:\r\n -m, --metadata FILENAME Path to JSON/YAML file containing metadata\r\n to publish\r\n --extra-options TEXT Extra options to pass to datasette serve\r\n --branch TEXT Install datasette from a GitHub branch e.g.\r\n main\r\n --template-dir DIRECTORY Path to directory containing custom\r\n templates\r\n --plugins-dir DIRECTORY Path to directory containing custom plugins\r\n --static MOUNT:DIRECTORY Serve static files from this directory at\r\n /MOUNT/...\r\n --install TEXT Additional packages (e.g. plugins) to\r\n install\r\n --plugin-secret ...\r\n Secrets to pass to plugins, e.g. --plugin-\r\n secret datasette-auth-github client_id xxx\r\n --version-note TEXT Additional note to show on /-/versions\r\n --secret TEXT Secret used for signing secure values, such\r\n as signed cookies\r\n --title TEXT Title for metadata\r\n --license TEXT License label for metadata\r\n --license_url TEXT License URL for metadata\r\n --source TEXT Source label for metadata\r\n --source_url TEXT Source URL for metadata\r\n --about TEXT About label for metadata\r\n --about_url TEXT About URL for metadata\r\n -n, --name TEXT Application name to use when building\r\n --service TEXT Cloud Run service to deploy (or over-write)\r\n --spatialite Enable SpatialLite extension\r\n --show-files Output the generated Dockerfile and\r\n metadata.json\r\n --memory TEXT Memory to allocate in Cloud Run, e.g. 1Gi\r\n --cpu [1|2|4] Number of vCPUs to allocate in Cloud Run\r\n --timeout INTEGER Build timeout in seconds\r\n --apt-get-install TEXT Additional packages to apt-get install\r\n --max-instances INTEGER Maximum Cloud Run instances\r\n --min-instances INTEGER Minimum Cloud Run instances\r\n --help Show this message and exit.\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730437237", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730437237, "node_id": "IC_kwDOBm6k_c5nJGB1", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:36:22Z", "updated_at": "2023-09-21T22:36:22Z", "author_association": "OWNER", "body": "I think the actual design of this is pretty simple. Current help starts like this:\r\n\r\n```\r\nUsage: datasette publish cloudrun [OPTIONS] [FILES]...\r\n\r\n Publish databases to Datasette running on Cloud Run\r\n\r\nOptions:\r\n -m, --metadata FILENAME Path to JSON/YAML file containing metadata\r\n to publish\r\n --extra-options TEXT Extra options to pass to datasette serve\r\n```\r\nThe `-s` and `-c` short options are not being used.\r\n\r\nSo I think `-c/--config` can point to a JSON or YAML `datasette.yaml` file, and `-s/--setting key value` can mirror the new `-s/--setting` option in `datasette serve` itself (a shortcut for populating the config file directly from the CLI).\r\n\r\nHere's the relevant help section from `datasette serve`:\r\n```\r\n -m, --metadata FILENAME Path to JSON/YAML file containing\r\n license/source metadata\r\n -c, --config FILENAME Path to JSON/YAML Datasette configuration\r\n file\r\n -s, --setting SETTING... nested.key, value setting to use in\r\n Datasette configuration\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1730388418", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1730388418, "node_id": "IC_kwDOBm6k_c5nI6HC", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:26:19Z", "updated_at": "2023-09-21T22:26:19Z", "author_association": "OWNER", "body": "1.0a7 is out with this fix as well now: https://docs.datasette.io/en/1.0a7/changelog.html#a7-2023-09-21", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730363182", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730363182, "node_id": "IC_kwDOBm6k_c5nIz8u", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:09:10Z", "updated_at": "2023-09-21T22:09:10Z", "author_association": "OWNER", "body": "Tests all pass now.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730362441", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730362441, "node_id": "IC_kwDOBm6k_c5nIzxJ", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:08:19Z", "updated_at": "2023-09-21T22:08:19Z", "author_association": "OWNER", "body": "That worked\r\n\r\nhttps://github.com/simonw/datasette/commit/e4f868801a6633400045f59584cfe650961c3fa6 is the latest commit right now and https://latest.datasette.io/-/versions shows that as the deployed version.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730356422", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730356422, "node_id": "IC_kwDOBm6k_c5nIyTG", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T22:01:00Z", "updated_at": "2023-09-21T22:01:00Z", "author_association": "OWNER", "body": "Tested that locally with Python 3.9 from `pyenv` and it worked.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730353462", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730353462, "node_id": "IC_kwDOBm6k_c5nIxk2", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T21:57:17Z", "updated_at": "2023-09-21T21:57:17Z", "author_association": "OWNER", "body": "Still fails in Python 3.9: https://github.com/simonw/datasette/actions/runs/6266752548/job/17018363302\r\n```\r\n plugin_info[\"name\"] = distinfo.name or distinfo.project_name\r\nAttributeError: 'PathDistribution' object has no attribute 'name'\r\nTest failed: datasette-json-html should not have been loaded\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2193#issuecomment-1730353006", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2193", "id": 1730353006, "node_id": "IC_kwDOBm6k_c5nIxdu", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T21:56:43Z", "updated_at": "2023-09-21T21:56:43Z", "author_association": "OWNER", "body": "The test fails as expected now. Closing this issue, will solve the remaining problems in:\r\n- #2057", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907655261, "label": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2193#issuecomment-1730352111", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2193", "id": 1730352111, "node_id": "IC_kwDOBm6k_c5nIxPv", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T21:55:41Z", "updated_at": "2023-09-21T21:55:41Z", "author_association": "OWNER", "body": "https://github.com/simonw/datasette/actions/runs/6267146158/job/17019594849 failed on 3.9 this time.\r\n\r\n```\r\n plugin_info[\"name\"] = distinfo.name or distinfo.project_name\r\nAttributeError: 'PathDistribution' object has no attribute 'name'\r\nTest failed: datasette-json-html should not have been loaded\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907655261, "label": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730313565", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730313565, "node_id": "IC_kwDOBm6k_c5nIn1d", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T21:16:31Z", "updated_at": "2023-09-21T21:16:31Z", "author_association": "OWNER", "body": "The `@add_common_publish_arguments_and_options` decorator described here is bad. If I update it to support a new `config` option all plugins that use it will break.\r\n\r\nhttps://github.com/simonw/datasette/blob/f130c7c0a88e50cea4121ea18d1f6db2431b6fab/docs/plugin_hooks.rst#L347-L355\r\n\r\nI want to deprecate it and switch to a different, better design to address the same problem.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2195#issuecomment-1730312128", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2195", "id": 1730312128, "node_id": "IC_kwDOBm6k_c5nInfA", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T21:15:11Z", "updated_at": "2023-09-21T21:15:11Z", "author_association": "OWNER", "body": "As soon as `datasette publish cloudrun` has this I can re-enable this bit of the demo deploy:\r\n\r\nhttps://github.com/simonw/datasette/blob/2da1a6acec915b81a16127008fd739c7d6075681/.github/workflows/deploy-latest.yml#L91-L97\r\n\r\nWhich should fix this broken demo from https://simonwillison.net/2022/Dec/2/datasette-write-api/\r\n\r\nhttps://todomvc.datasette.io/", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907765514, "label": "`datasette publish` needs support for the new config/metadata split"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730305920", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730305920, "node_id": "IC_kwDOBm6k_c5nIl-A", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T21:09:21Z", "updated_at": "2023-09-21T21:09:21Z", "author_association": "OWNER", "body": "I'm going to disable this bit of the deploy for the moment, which will break the demo linked to from https://simonwillison.net/2022/Dec/2/datasette-write-api/\r\n\r\nhttps://github.com/simonw/datasette/blob/2da1a6acec915b81a16127008fd739c7d6075681/.github/workflows/deploy-latest.yml#L91-L97\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730259871", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730259871, "node_id": "IC_kwDOBm6k_c5nIauf", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:34:09Z", "updated_at": "2023-09-21T20:34:09Z", "author_association": "OWNER", "body": "... which raises the challenge that `datasette publish` doesn't yet know what to do with a config file!\r\n\r\nhttps://github.com/simonw/datasette/blob/2da1a6acec915b81a16127008fd739c7d6075681/.github/workflows/deploy-latest.yml#L114-L122", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730258302", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730258302, "node_id": "IC_kwDOBm6k_c5nIaV-", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:32:53Z", "updated_at": "2023-09-21T20:33:02Z", "author_association": "OWNER", "body": "Correct usage is now:\r\n```bash\r\npython tests/fixtures.py fixtures.db fixtures-config.json fixtures-metadata.json \\\r\n plugins --extra-db-filename extra_database.db\r\n```\r\n```\r\nTest tables written to fixtures.db\r\n- metadata written to fixtures-metadata.json\r\n- config written to fixtures-config.json\r\n Wrote plugin: plugins/register_output_renderer.py\r\n Wrote plugin: plugins/view_name.py\r\n Wrote plugin: plugins/my_plugin.py\r\n Wrote plugin: plugins/messages_output_renderer.py\r\n Wrote plugin: plugins/sleep_sql_function.py\r\n Wrote plugin: plugins/my_plugin_2.py\r\nTest tables written to extra_database.db\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730256435", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730256435, "node_id": "IC_kwDOBm6k_c5nIZ4z", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:31:22Z", "updated_at": "2023-09-21T20:31:31Z", "author_association": "OWNER", "body": "New error: \"Error: Metadata should end with .json\"\r\n\r\nhttps://github.com/simonw/datasette/actions/runs/6266720924/job/17018265851\r\n\r\n\"CleanShot", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730250337", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730250337, "node_id": "IC_kwDOBm6k_c5nIYZh", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:26:12Z", "updated_at": "2023-09-21T20:26:12Z", "author_association": "OWNER", "body": "That does seem to fix the problem! ", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730247545", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730247545, "node_id": "IC_kwDOBm6k_c5nIXt5", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:23:47Z", "updated_at": "2023-09-21T20:23:47Z", "author_association": "OWNER", "body": "Hunch: https://pypi.org/project/importlib-metadata/ may help here.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730245204", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730245204, "node_id": "IC_kwDOBm6k_c5nIXJU", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:21:42Z", "updated_at": "2023-09-21T20:21:42Z", "author_association": "OWNER", "body": "I think I see the problem - it's from here: https://github.com/simonw/datasette/commit/b2ec8717c3619260a1b535eea20e618bf95aa30b#diff-5dbc88d6e5c3615caf10e32a9d6fc6ff683f5b5814948928cb84c3ab91c038b6L770\r\n\r\nThe `config` and `metadata` Click options are the wrong way round:\r\n\r\nhttps://github.com/simonw/datasette/blob/80a9cd9620fddf2695d12d8386a91e7c6b145ef2/tests/fixtures.py#L785-L786\r\n\r\nhttps://github.com/simonw/datasette/blob/80a9cd9620fddf2695d12d8386a91e7c6b145ef2/tests/fixtures.py#L801", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730242734", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730242734, "node_id": "IC_kwDOBm6k_c5nIWiu", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:19:29Z", "updated_at": "2023-09-21T20:19:29Z", "author_association": "OWNER", "body": "Maybe `plugins/` does not exist? It should have been created by this line:\r\n\r\nhttps://github.com/simonw/datasette/blob/80a9cd9620fddf2695d12d8386a91e7c6b145ef2/.github/workflows/deploy-latest.yml#L41-L42", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2194#issuecomment-1730241813", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2194", "id": 1730241813, "node_id": "IC_kwDOBm6k_c5nIWUV", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:18:40Z", "updated_at": "2023-09-21T20:18:40Z", "author_association": "OWNER", "body": "This looks to be the step that is failing:\r\n\r\nhttps://github.com/simonw/datasette/blob/80a9cd9620fddf2695d12d8386a91e7c6b145ef2/.github/workflows/deploy-latest.yml#L50-L60", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907695234, "label": "Deploy failing with \"plugins/alternative_route.py: Not a directory\""}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1730232308", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1730232308, "node_id": "IC_kwDOBm6k_c5nIT_0", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:11:16Z", "updated_at": "2023-09-21T20:11:16Z", "author_association": "OWNER", "body": "We're planning a breaking change in `1.0a7`:\r\n- #2191 \r\n\r\nSince that's a breaking change I'm going to ship 1.0a7 right now with this fix, then ship that breaking change as `1.0a8` instead.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1730231404", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1730231404, "node_id": "IC_kwDOBm6k_c5nITxs", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:10:28Z", "updated_at": "2023-09-21T20:10:28Z", "author_association": "OWNER", "body": "Release 0.64.4: https://docs.datasette.io/en/stable/changelog.html#v0-64-4", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730226107", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730226107, "node_id": "IC_kwDOBm6k_c5nISe7", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:06:19Z", "updated_at": "2023-09-21T20:06:19Z", "author_association": "OWNER", "body": "No that's not it actually, it's something else.\r\n\r\nGot to this point:\r\n```bash\r\nDATASETTE_LOAD_PLUGINS=datasette-init python -i $(which datasette) plugins\r\n```\r\nThat fails and drops me into a debugger:\r\n\r\n```\r\n File \"/Users/simon/Dropbox/Development/datasette/datasette/cli.py\", line 186, in plugins\r\n app = Datasette([], plugins_dir=plugins_dir)\r\n File \"/Users/simon/Dropbox/Development/datasette/datasette/app.py\", line 405, in __init__\r\n for plugin in get_plugins()\r\n File \"/Users/simon/Dropbox/Development/datasette/datasette/plugins.py\", line 89, in get_plugins\r\n plugin_info[\"name\"] = distinfo.name or distinfo.project_name\r\nAttributeError: 'PathDistribution' object has no attribute 'name'\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730219703", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730219703, "node_id": "IC_kwDOBm6k_c5nIQ63", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T20:01:54Z", "updated_at": "2023-09-21T20:01:54Z", "author_association": "OWNER", "body": "The problem is here:\r\n```\r\n 86 \t distinfo = plugin_to_distinfo.get(plugin)\r\n 87 \t if distinfo is None:\r\n 88 \t breakpoint()\r\n 89 ->\t assert False\r\n 90 \t if distinfo.name is None:\r\n 91 \t breakpoint()\r\n 92 \t assert False\r\n 93 \t if distinfo:\r\n 94 \t plugin_info[\"version\"] = distinfo.version\r\n(Pdb) distinfo\r\n(Pdb) plugin\r\n\r\n```\r\nThat `plugin_to_distinfo` is missing some stuff.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730214654", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730214654, "node_id": "IC_kwDOBm6k_c5nIPr-", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:59:51Z", "updated_at": "2023-09-21T19:59:51Z", "author_association": "OWNER", "body": "So the problem is the `get_plugins()` function returning plugins with `None` for their name:\r\n\r\nhttps://github.com/simonw/datasette/blob/80a9cd9620fddf2695d12d8386a91e7c6b145ef2/datasette/plugins.py#L61-L91", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730212597", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730212597, "node_id": "IC_kwDOBm6k_c5nIPL1", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:58:38Z", "updated_at": "2023-09-21T19:58:38Z", "author_association": "OWNER", "body": "Relevant code: https://github.com/simonw/datasette/blob/80a9cd9620fddf2695d12d8386a91e7c6b145ef2/datasette/app.py#L1127-L1146", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730211445", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730211445, "node_id": "IC_kwDOBm6k_c5nIO51", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:57:44Z", "updated_at": "2023-09-21T19:57:44Z", "author_association": "OWNER", "body": "In the debugger:\r\n```\r\n>>> import pdb\r\n>>> pdb.pm()\r\n> /Users/simon/Dropbox/Development/datasette/datasette/app.py(1136)_plugins()\r\n-> ps.sort(key=lambda p: p[\"name\"])\r\n(Pdb) ps\r\n[{'name': None, 'static_path': None, 'templates_path': None, 'hooks': ['prepare_connection', 'render_cell'], 'version': '1.0.1'}, {'name': None, 'static_path': None, 'templates_path': None, 'hooks': ['startup'], 'version': '0.2'}]\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730210728", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730210728, "node_id": "IC_kwDOBm6k_c5nIOuo", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:57:08Z", "updated_at": "2023-09-21T19:57:08Z", "author_association": "OWNER", "body": "In my Python 3.8 environment I ran:\r\n```bash\r\ndatasette install datasette-init datasette-json-html\r\n```\r\nAnd now `datasette plugins` produces this error:\r\n```\r\n File \"/Users/simon/Dropbox/Development/datasette/datasette/cli.py\", line 192, in plugins\r\n click.echo(json.dumps(app._plugins(all=all), indent=4))\r\n File \"/Users/simon/Dropbox/Development/datasette/datasette/app.py\", line 1136, in _plugins\r\n ps.sort(key=lambda p: p[\"name\"])\r\nTypeError: '<' not supported between instances of 'NoneType' and 'NoneType'\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2193#issuecomment-1730208566", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2193", "id": 1730208566, "node_id": "IC_kwDOBm6k_c5nIOM2", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:55:19Z", "updated_at": "2023-09-21T19:55:19Z", "author_association": "OWNER", "body": "Yes, the new script seems to work. On Python 3.11:\r\n\r\n```\r\ntests/test-datasette-load-plugins.sh \r\necho $?\r\n0\r\n```\r\nOn Python 3.8:\r\n```\r\ntests/test-datasette-load-plugins.sh\r\nTest failed: datasette-json-html not found\r\necho $?\r\n1\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907655261, "label": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2193#issuecomment-1730206629", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2193", "id": 1730206629, "node_id": "IC_kwDOBm6k_c5nINul", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:53:39Z", "updated_at": "2023-09-21T19:53:39Z", "author_association": "OWNER", "body": "[GPT-4 says](https://chat.openai.com/share/65a95561-8f3c-4f9b-a4ab-c2508e87d2a9):\r\n\r\n> In the script, you're using a subshell `( ... )` to group commands. If you `exit 1` within the subshell, it will only exit the subshell and not the main script. This is why GitHub Actions does not see it as a failure.\r\n\r\nIt suggested doing this instead:\r\n\r\n```bash\r\n#!/bin/bash\r\n\r\nPLUGINS=$(datasette plugins)\r\nif ! echo \"$PLUGINS\" | jq 'any(.[]; .name == \"datasette-json-html\")' | grep -q true; then\r\n echo \"Test failed: datasette-json-html not found\"\r\n exit 1\r\nfi\r\n\r\nPLUGINS2=$(DATASETTE_LOAD_PLUGINS=datasette-init datasette plugins)\r\nif ! echo \"$PLUGINS2\" | jq 'any(.[]; .name == \"datasette-json-html\")' | grep -q false; then\r\n echo \"Test failed: datasette-json-html should not have been loaded\"\r\n exit 1\r\nfi\r\n\r\nif ! echo \"$PLUGINS2\" | jq 'any(.[]; .name == \"datasette-init\")' | grep -q true; then\r\n echo \"Test failed: datasette-init should have been loaded\"\r\n exit 1\r\nfi\r\n\r\nPLUGINS3=$(DATASETTE_LOAD_PLUGINS='' datasette plugins)\r\nif ! echo \"$PLUGINS3\" | grep -q '\\[\\]'; then\r\n echo \"Test failed: datasette plugins should have returned []\"\r\n exit 1\r\nfi\r\n```\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907655261, "label": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2193#issuecomment-1730203356", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2193", "id": 1730203356, "node_id": "IC_kwDOBm6k_c5nIM7c", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:51:04Z", "updated_at": "2023-09-21T19:51:04Z", "author_association": "OWNER", "body": "The script:\r\n\r\nhttps://github.com/simonw/datasette/blob/b0d0a0e5de8bb5b9b6c253e8af451a532266bcf1/tests/test-datasette-load-plugins.sh#L1-L29\r\n\r\nI'm not sure why those `exit 1` lines did not cause a CI failure.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907655261, "label": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2193#issuecomment-1730202533", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2193", "id": 1730202533, "node_id": "IC_kwDOBm6k_c5nIMul", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:50:22Z", "updated_at": "2023-09-21T19:50:22Z", "author_association": "OWNER", "body": "Here's the failure in CI, which did not cause the workflow to fail even though it should have:\r\n\r\n\"CleanShot\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1907655261, "label": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730201226", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730201226, "node_id": "IC_kwDOBm6k_c5nIMaK", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:49:20Z", "updated_at": "2023-09-21T19:49:20Z", "author_association": "OWNER", "body": "That passed on 3.8 but should have failed: https://github.com/simonw/datasette/actions/runs/6266341481/job/17017099801 - the \"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730188367", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730188367, "node_id": "IC_kwDOBm6k_c5nIJRP", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:38:28Z", "updated_at": "2023-09-21T19:40:38Z", "author_association": "OWNER", "body": "I'll imitate `certbot`:\r\n\r\nhttps://github.com/certbot/certbot/blob/694c758db7fcd8410b5dadcd136c61b3eb028fdc/certbot-ci/setup.py#L9\r\n\r\n```python\r\n 'importlib_resources>=1.3.1; python_version < \"3.9\"',\r\n```\r\nLooks like `1.3` is the minimum version needed for compatibility with the 3.9 standard library, according to https://github.com/python/importlib_resources/blob/main/README.rst#compatibility\r\n\r\nhttps://github.com/certbot/certbot/blob/694c758db7fcd8410b5dadcd136c61b3eb028fdc/certbot/certbot/_internal/constants.py#L13C29-L16\r\n\r\n```python\r\nif sys.version_info >= (3, 9): # pragma: no cover\r\n import importlib.resources as importlib_resources\r\nelse: # pragma: no cover\r\n import importlib_resources\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730185322", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730185322, "node_id": "IC_kwDOBm6k_c5nIIhq", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:35:49Z", "updated_at": "2023-09-21T19:35:49Z", "author_association": "OWNER", "body": "I think I can fix this using https://importlib-resources.readthedocs.io/en/latest/using.html - maybe as a dependency only installed if the Python version is less than 3.9.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730183405", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730183405, "node_id": "IC_kwDOBm6k_c5nIIDt", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:34:09Z", "updated_at": "2023-09-21T19:34:09Z", "author_association": "OWNER", "body": "Confirmed: https://docs.python.org/3/library/importlib.resources.html#importlib.resources.files\r\n\r\n> `importlib.resources.files(package)`\r\n> [...]\r\n> New in version 3.9.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1730171241", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1730171241, "node_id": "IC_kwDOBm6k_c5nIFFp", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:27:25Z", "updated_at": "2023-09-21T19:27:25Z", "author_association": "OWNER", "body": "This broke in Python 3.8:\r\n\r\n```\r\nif plugin.__name__ not in DEFAULT_PLUGINS:\r\n try:\r\n if (importlib.resources.files(plugin.__name__) / \"static\").is_dir():\r\nE AttributeError: module 'importlib.resources' has no attribute 'files'\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1730162283", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1730162283, "node_id": "IC_kwDOBm6k_c5nIC5r", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-21T19:19:47Z", "updated_at": "2023-09-21T19:19:47Z", "author_association": "OWNER", "body": "I'm going to release this in `1.0a7`, and I'll backport it to a `0.64.4` release too.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2190#issuecomment-1729961503", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2190", "id": 1729961503, "node_id": "IC_kwDOBm6k_c5nHR4f", "user": {"value": 15178711, "label": "asg017"}, "created_at": "2023-09-21T16:56:57Z", "updated_at": "2023-09-21T16:56:57Z", "author_association": "CONTRIBUTOR", "body": "TODO: add similar checks for permissions/allow/canned queries", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901483874, "label": "Raise an exception if a \"plugins\" block exists in metadata.json"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2191#issuecomment-1728504633", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2191", "id": 1728504633, "node_id": "IC_kwDOBm6k_c5nBuM5", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-20T22:24:51Z", "updated_at": "2023-09-20T22:25:16Z", "author_association": "OWNER", "body": "The `{\"units\": {\"distance\": \"m\", \"frequency\": \"Hz\"}}` bit is for the [units feature](https://docs.datasette.io/en/1.0a6/metadata.html#specifying-units-for-a-column) which I've half-disabled already and would like to remove before 1.0, though ideally turning that functionality into a plugin instead (if I can figure out how to do that).", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901768721, "label": "DRAFT: Move `permissions` and `allow` blocks out of `metadata.yaml` and into `datasette.yaml`"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2191#issuecomment-1728503623", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2191", "id": 1728503623, "node_id": "IC_kwDOBm6k_c5nBt9H", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-20T22:23:33Z", "updated_at": "2023-09-20T22:24:10Z", "author_association": "OWNER", "body": "This is one of the most interesting illustrative examples in the new code:\r\n\r\nhttps://github.com/simonw/datasette/blob/f7bdedff779606466b580d8528e5a44509291002/tests/fixtures.py#L301-L349\r\n\r\nInteresting to note that it now has canned queries in it, which include this bit:\r\n\r\nhttps://github.com/simonw/datasette/blob/f7bdedff779606466b580d8528e5a44509291002/tests/fixtures.py#L341-L342\r\n\r\nIt looks like metadata, but in this case it's configuration. That blur between metadata and configuration at the canned query level still feels a little bit odd to me, but I still think we're going in the right direction with it.\r\n\r\nAlso interesting, from that same file:\r\n\r\nhttps://github.com/simonw/datasette/blob/f7bdedff779606466b580d8528e5a44509291002/tests/fixtures.py#L351-L399\r\n\r\nThere are a few things in that metadata block that are arguably configuration, not metadata - for example:\r\n\r\nhttps://github.com/simonw/datasette/blob/f7bdedff779606466b580d8528e5a44509291002/tests/fixtures.py#L360\r\n\r\nI think `extra_css_urls` is definitely configuration, not metadata.\r\n\r\nhttps://github.com/simonw/datasette/blob/f7bdedff779606466b580d8528e5a44509291002/tests/fixtures.py#L369-L395\r\n\r\nMost of that stuff is arguably configuration too, with the exception of the `roadside_attractions.columns` bit which is metadata about those columns.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901768721, "label": "DRAFT: Move `permissions` and `allow` blocks out of `metadata.yaml` and into `datasette.yaml`"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2191#issuecomment-1728498221", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2191", "id": 1728498221, "node_id": "IC_kwDOBm6k_c5nBsot", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-20T22:17:26Z", "updated_at": "2023-09-20T22:17:26Z", "author_association": "OWNER", "body": "I tested this locally for permissions like this. `datasette.yml`:\r\n\r\n```yaml\r\ndatabases:\r\n content:\r\n allow:\r\n id: root\r\n```\r\nStarted Datasette like this:\r\n```bash\r\ndatasette --root content.db pottery2.db -c datasette.yml\r\n```\r\nAs root I could see this (note the padlock):\r\n\r\n\"CleanShot\r\n\r\nhttp://127.0.0.1:8001/-/metadata returned `{}` showing that the permissions must have come from the config file instead.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901768721, "label": "DRAFT: Move `permissions` and `allow` blocks out of `metadata.yaml` and into `datasette.yaml`"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1728192688", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1728192688, "node_id": "IC_kwDOBm6k_c5nAiCw", "user": {"value": 173848, "label": "yozlet"}, "created_at": "2023-09-20T17:53:31Z", "updated_at": "2023-09-20T17:53:31Z", "author_association": "NONE", "body": "`/me munches popcorn at a furious rate, utterly entralled`", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2192#issuecomment-1726754119", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2192", "id": 1726754119, "node_id": "IC_kwDOBm6k_c5m7C1H", "user": {"value": 22429695, "label": "codecov[bot]"}, "created_at": "2023-09-20T01:35:45Z", "updated_at": "2023-09-20T01:35:45Z", "author_association": "NONE", "body": "## [Codecov](https://app.codecov.io/gh/simonw/datasette/pull/2192?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) Report\nPatch coverage: **`100.00%`** and project coverage change: **`+0.02%`** :tada:\n> Comparison is base [(`6ed7908`)](https://app.codecov.io/gh/simonw/datasette/commit/6ed7908580fa2ba9297c3225d85c56f8b08b9937?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.69% compared to head [(`4e6a341`)](https://app.codecov.io/gh/simonw/datasette/pull/2192?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.72%.\n\n
Additional details and impacted files\n\n\n```diff\n@@ Coverage Diff @@\n## main #2192 +/- ##\n==========================================\n+ Coverage 92.69% 92.72% +0.02% \n==========================================\n Files 40 40 \n Lines 6039 6036 -3 \n==========================================\n- Hits 5598 5597 -1 \n+ Misses 441 439 -2 \n```\n\n\n| [Files Changed](https://app.codecov.io/gh/simonw/datasette/pull/2192?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) | Coverage \u0394 | |\n|---|---|---|\n| [datasette/views/table.py](https://app.codecov.io/gh/simonw/datasette/pull/2192?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3ZpZXdzL3RhYmxlLnB5) | `96.31% <100.00%> (+0.51%)` | :arrow_up: |\n\n... and [1 file with indirect coverage changes](https://app.codecov.io/gh/simonw/datasette/pull/2192/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison)\n\n\n
\n\n[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simonw/datasette/pull/2192?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison). \n:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1903932086, "label": "Stop using parallel SQL queries for tables"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1726749355", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1726749355, "node_id": "IC_kwDOBm6k_c5m7Bqr", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-20T01:28:16Z", "updated_at": "2023-09-20T01:28:16Z", "author_association": "OWNER", "body": "Added a note to that example in the documentation: https://github.com/simonw/datasette/blob/4e6a34179eaedec44c1263275d7592fd83d7e2ac/docs/internals.rst?plain=1#L1320", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2185#issuecomment-1719468727", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2185", "id": 1719468727, "node_id": "IC_kwDOBm6k_c5mfQK3", "user": {"value": 22429695, "label": "codecov[bot]"}, "created_at": "2023-09-14T13:36:07Z", "updated_at": "2023-09-19T13:42:35Z", "author_association": "NONE", "body": "## [Codecov](https://app.codecov.io/gh/simonw/datasette/pull/2185?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) Report\nPatch coverage has no change and project coverage change: **`-0.04%`** :warning:\n> Comparison is base [(`6ed7908`)](https://app.codecov.io/gh/simonw/datasette/commit/6ed7908580fa2ba9297c3225d85c56f8b08b9937?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.69% compared to head [(`fe5f881`)](https://app.codecov.io/gh/simonw/datasette/pull/2185?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.66%.\n\n
Additional details and impacted files\n\n\n```diff\n@@ Coverage Diff @@\n## main #2185 +/- ##\n==========================================\n- Coverage 92.69% 92.66% -0.04% \n==========================================\n Files 40 40 \n Lines 6039 6039 \n==========================================\n- Hits 5598 5596 -2 \n- Misses 441 443 +2 \n```\n\n\n[see 1 file with indirect coverage changes](https://app.codecov.io/gh/simonw/datasette/pull/2185/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison)\n\n\n
\n\n[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simonw/datasette/pull/2185?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison). \n:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1896578249, "label": "Bump the python-packages group with 3 updates"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2191#issuecomment-1724480716", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2191", "id": 1724480716, "node_id": "IC_kwDOBm6k_c5myXzM", "user": {"value": 22429695, "label": "codecov[bot]"}, "created_at": "2023-09-18T21:28:36Z", "updated_at": "2023-09-18T21:28:36Z", "author_association": "NONE", "body": "## [Codecov](https://app.codecov.io/gh/simonw/datasette/pull/2191?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) Report\nPatch coverage: **`100.00%`** and project coverage change: **`-0.05%`** :warning:\n> Comparison is base [(`6ed7908`)](https://app.codecov.io/gh/simonw/datasette/commit/6ed7908580fa2ba9297c3225d85c56f8b08b9937?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.69% compared to head [(`f7bdedf`)](https://app.codecov.io/gh/simonw/datasette/pull/2191?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.64%.\n\n
Additional details and impacted files\n\n\n```diff\n@@ Coverage Diff @@\n## main #2191 +/- ##\n==========================================\n- Coverage 92.69% 92.64% -0.05% \n==========================================\n Files 40 40 \n Lines 6039 6040 +1 \n==========================================\n- Hits 5598 5596 -2 \n- Misses 441 444 +3 \n```\n\n\n| [Files Changed](https://app.codecov.io/gh/simonw/datasette/pull/2191?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) | Coverage \u0394 | |\n|---|---|---|\n| [datasette/app.py](https://app.codecov.io/gh/simonw/datasette/pull/2191?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2FwcC5weQ==) | `94.09% <100.00%> (-0.11%)` | :arrow_down: |\n| [datasette/default\\_permissions.py](https://app.codecov.io/gh/simonw/datasette/pull/2191?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2RlZmF1bHRfcGVybWlzc2lvbnMucHk=) | `97.36% <100.00%> (+0.01%)` | :arrow_up: |\n\n... and [1 file with indirect coverage changes](https://app.codecov.io/gh/simonw/datasette/pull/2191/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison)\n\n\n
\n\n[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simonw/datasette/pull/2191?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison). \n:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901768721, "label": "DRAFT: Move `permissions` and `allow` blocks out of `metadata.yaml` and into `datasette.yaml`"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724325068", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724325068, "node_id": "IC_kwDOBm6k_c5mxxzM", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T20:29:41Z", "updated_at": "2023-09-18T20:29:41Z", "author_association": "OWNER", "body": "The one other thing affected by this change is this documentation, which suggests a not-actually-safe pattern: https://github.com/simonw/datasette/blob/6ed7908580fa2ba9297c3225d85c56f8b08b9937/docs/internals.rst#L1292-L1321", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724317367", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724317367, "node_id": "IC_kwDOBm6k_c5mxv63", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T20:25:44Z", "updated_at": "2023-09-18T20:25:44Z", "author_association": "OWNER", "body": "My current hunch is that SQLite gets unhappy if multiple threads access the same underlying C object - which sometimes happens with in-memory connections and Datasette presumably because they are faster than file-backed databases.\r\n\r\nI'm going to remove the `asyncio.gather()` code from the table view. I'll ship a 0.x release with that fix too.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724315591", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724315591, "node_id": "IC_kwDOBm6k_c5mxvfH", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T20:24:30Z", "updated_at": "2023-09-18T20:24:30Z", "author_association": "OWNER", "body": "[Using SQLite In Multi-Threaded Applications](https://www.sqlite.org/threadsafe.html)\r\n\r\nThat indicates that there's a SQLite option for \"Serialized\" mode where it's safe to access anything SQLite provides from multiple threads, but as far as I can tell Python doesn't give you an option to turn that mode on or off for a connection - you can read `sqlite3.threadsafet`y to see if that mode was compiled in or not, but not actually change it.\r\n\r\nOn my Mac `sqlite3.threadsafety` returns 1 which means https://docs.python.org/3/library/sqlite3.html#sqlite3.threadsafety \"Multi-thread: In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.\" - it would need to return 3 for that serialized mode.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724305169", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724305169, "node_id": "IC_kwDOBm6k_c5mxs8R", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T20:16:22Z", "updated_at": "2023-09-18T20:16:36Z", "author_association": "OWNER", "body": "Looking again at this code:\r\n\r\nhttps://github.com/simonw/datasette/blob/6ed7908580fa2ba9297c3225d85c56f8b08b9937/datasette/database.py#L87-L117\r\n\r\n`check_same_thread=False` really stands out here.\r\n\r\nPython docs at https://docs.python.org/3/library/sqlite3.html\r\n\r\n> **check_same_thread** ([*bool*](https://docs.python.org/3/library/functions.html#bool \"bool\")) -- If `True` (default), [`ProgrammingError`](https://docs.python.org/3/library/sqlite3.html#sqlite3.ProgrammingError \"sqlite3.ProgrammingError\") will be raised if the database connection is used by a thread other than the one that created it. If `False`, the connection may be accessed in multiple threads; write operations may need to be serialized by the user to avoid data corruption. See [`threadsafety`](https://docs.python.org/3/library/sqlite3.html#sqlite3.threadsafety \"sqlite3.threadsafety\") for more information.\r\n\r\nI think I'm playing with fire by allowing multiple threads to access the same connection without doing my own serialization of those requests.\r\n\r\nI _do_ do that using the write connection - and in this particular case the bug isn't coming from write queries, it's coming from read queries - but perhaps SQLite has issues with threading for reads, too.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724298817", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724298817, "node_id": "IC_kwDOBm6k_c5mxrZB", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T20:11:26Z", "updated_at": "2023-09-18T20:11:26Z", "author_association": "OWNER", "body": "Now that I've confirmed that parallel query execution of the kind introduced in https://github.com/simonw/datasette/commit/942411ef946e9a34a2094944d3423cddad27efd3 can cause hangs (presumably some kind of locking issue) against in-memory databases, some options:\r\n\r\n1. Disable parallel execution entirely and rip out related code.\r\n2. Disable parallel execution entirely by leaving that code but having it always behave as if `_noparallel=1`\r\n3. Continue digging and try and find some way to avoid this problem\r\n\r\nThe parallel execution work is something I was playing with last year in the hope of speeding up Datasette pages like the table page which need to execute a bunch of queries - one for each facet, plus one for each column to see if it should be suggested as a facet.\r\n\r\nI wrote about this at the time here: https://simonwillison.net/2022/May/6/weeknotes/\r\n\r\nMy hope was that despite Python's GIL this optimization would still help, because the SQLite C module releases the GIL once it gets to SQLite.\r\n\r\nBut... that didn't hold up. It looked like enough work was happening in Python land with the GIL that the optimization didn't improve things.\r\n\r\nRunning the `nogil` fork of Python DID improve things though! I left the code in partly on the hope that the `nogil` fork would be accepted into Python core.\r\n\r\n... which it now has! But it will still be a year or two before it fully lands: https://discuss.python.org/t/a-steering-council-notice-about-pep-703-making-the-global-interpreter-lock-optional-in-cpython/30474\r\n\r\nSo I'm not particularly concerned about dropping the parallel execution. If I do drop it though do I leave the potentially complex code in that relates to it?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724281824", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724281824, "node_id": "IC_kwDOBm6k_c5mxnPg", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:58:06Z", "updated_at": "2023-09-18T19:58:06Z", "author_association": "OWNER", "body": "I also confirmed that `http://127.0.0.1:8064/airtable_refs/airtable_refs?_noparallel=1` does not trigger the bug but `http://127.0.0.1:8064/airtable_refs/airtable_refs` does.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724278386", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724278386, "node_id": "IC_kwDOBm6k_c5mxmZy", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:55:32Z", "updated_at": "2023-09-18T19:55:32Z", "author_association": "OWNER", "body": "OK it looks like it found it!\r\n\r\n```\r\n942411ef946e9a34a2094944d3423cddad27efd3 is the first bad commit\r\ncommit \r\n\r\nAuthor: Simon Willison \r\nDate: Tue Apr 26 15:48:56 2022 -0700\r\n\r\n Execute some TableView queries in parallel\r\n \r\n Use ?_noparallel=1 to opt out (undocumented, useful for benchmark comparisons)\r\n \r\n Refs #1723, #1715\r\n\r\n datasette/views/table.py | 93 ++++++++++++++++++++++++++++++++++--------------\r\n 1 file changed, 67 insertions(+), 26 deletions(-)\r\nbisect found first bad commit\r\n```\r\nhttps://github.com/simonw/datasette/commit/942411ef946e9a34a2094944d3423cddad27efd3 does look like the cause of this problem.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724276917", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724276917, "node_id": "IC_kwDOBm6k_c5mxmC1", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:54:23Z", "updated_at": "2023-09-18T19:54:23Z", "author_association": "OWNER", "body": "Turned out I wasn't running the `datasette` from the current directory, so it was not testing what I intended.\r\n\r\nFIxed that with `pip install -e .` in the `datasette/` directory.\r\n\r\nNow I'm seeing some passes, which look like this:\r\n```\r\nrunning '../airtable-export/testit.sh'\r\nINFO: Started server process [77810]\r\nINFO: Waiting for application startup.\r\nINFO: Application startup complete.\r\nINFO: Uvicorn running on http://127.0.0.1:8064 (Press CTRL+C to quit)\r\n Running curls\r\nINFO: 127.0.0.1:59439 - \"GET /airtable_refs/airtable_refs HTTP/1.1\" 200 OK\r\nINFO: 127.0.0.1:59440 - \"GET /airtable_refs/airtable_refs HTTP/1.1\" 200 OK\r\nINFO: 127.0.0.1:59441 - \"GET /airtable_refs/airtable_refs HTTP/1.1\" 200 OK\r\n All curl succeeded\r\nKilling datasette server with PID 77810\r\n../airtable-export/testit.sh: line 54: 77810 Killed: 9 datasette pottery2.db -p $port\r\nAll three curls succeeded.\r\nBisecting: 4 revisions left to test after this (roughly 2 steps)\r\n[7463b051cf8d7f856df5eba9f7aa944183ebabe5] Cosmetic tweaks after blacken-docs, refs #1718\r\nrunning '../airtable-export/testit.sh'\r\nINFO: Started server process [77826]\r\nINFO: Waiting for application startup.\r\nINFO: Application startup complete.\r\nINFO: Uvicorn running on http://127.0.0.1:8064 (Press CTRL+C to quit)\r\n Running curls\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724257290", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724257290, "node_id": "IC_kwDOBm6k_c5mxhQK", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:39:27Z", "updated_at": "2023-09-18T19:44:26Z", "author_association": "OWNER", "body": "I'm now trying this test script:\r\n```bash\r\n#!/bin/bash\r\n\r\nport=8064\r\n# Start datasette server in the background and get its PID\r\ndatasette pottery2.db -p $port &\r\nserver_pid=$!\r\n\r\n# Wait for a moment to ensure the server has time to start up\r\nsleep 2\r\n\r\n# Initialize counters and parameters\r\nretry_count=0\r\nmax_retries=3\r\nsuccess_count=0\r\npath=\"/airtable_refs/airtable_refs\"\r\n\r\n# Function to run curl with a timeout\r\nfunction test_curl {\r\n # Run the curl command with a timeout of 3 seconds\r\n timeout 3s curl -s \"http://localhost:${port}${path}\" > /dev/null\r\n if [ $? -eq 0 ]; then\r\n # Curl was successful\r\n ((success_count++))\r\n fi\r\n}\r\n\r\n# Try three parallel curl requests\r\nwhile [[ $retry_count -lt $max_retries ]]; do\r\n # Reset the success counter\r\n success_count=0\r\n\r\n # Run the curls in parallel\r\n echo \" Running curls\"\r\n test_curl\r\n test_curl\r\n test_curl # & test_curl & test_curl &\r\n\r\n # Wait for all curls to finish\r\n #wait\r\n\r\n # Check the success count\r\n if [[ $success_count -eq 3 ]]; then\r\n # All curls succeeded, break out of the loop\r\n echo \" All curl succeeded\"\r\n break\r\n fi\r\n\r\n ((retry_count++))\r\ndone\r\n\r\n# Kill the datasette server\r\necho \"Killing datasette server with PID $server_pid\"\r\nkill -9 $server_pid\r\nsleep 2\r\n\r\n# Print result\r\nif [[ $success_count -eq 3 ]]; then\r\n echo \"All three curls succeeded.\"\r\n exit 0\r\nelse\r\n echo \"Error: Not all curls succeeded after $retry_count attempts.\"\r\n exit 1\r\nfi\r\n```\r\nI run it like this:\r\n```bash\r\ngit bisect reset\r\ngit bisect start\r\ngit bisect good 0.59.4\r\ngit bisect bad 1.0a6\r\ngit bisect run ../airtable-export/testit.sh\r\n```\r\nBut... it's not having the desired result, I think because the bug is intermittent so each time I run it the bisect spits out a different commit as the one that is to blame.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724263390", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724263390, "node_id": "IC_kwDOBm6k_c5mxive", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:44:03Z", "updated_at": "2023-09-18T19:44:03Z", "author_association": "OWNER", "body": "I knocked it down to 1 retry just to see what happened.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724259229", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724259229, "node_id": "IC_kwDOBm6k_c5mxhud", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:40:56Z", "updated_at": "2023-09-18T19:40:56Z", "author_association": "OWNER", "body": "I tried it with a path of `/` and everything passed - so it's definitely the path of `/airtable_refs/airtable_refs` (an in-memory database created by an experimental branch of https://github.com/simonw/airtable-export) that triggers the problem.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724258279", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724258279, "node_id": "IC_kwDOBm6k_c5mxhfn", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T19:40:13Z", "updated_at": "2023-09-18T19:40:13Z", "author_association": "OWNER", "body": "Output while it is running looks like this:\r\n```\r\nrunning '../airtable-export/testit.sh'\r\nINFO: Started server process [75649]\r\nINFO: Waiting for application startup.\r\nINFO: Application startup complete.\r\nINFO: Uvicorn running on http://127.0.0.1:8064 (Press CTRL+C to quit)\r\n Running curls\r\n Running curls\r\n Running curls\r\nKilling datasette server with PID 75649\r\n../airtable-export/testit.sh: line 54: 75649 Killed: 9 datasette pottery2.db -p $port\r\nError: Not all curls succeeded after 3 attempts.\r\nBisecting: 155 revisions left to test after this (roughly 7 steps)\r\n[247e460e08bf823142f7b84058fe44e43626787f] Update beautifulsoup4 requirement (#1703)\r\nrunning '../airtable-export/testit.sh'\r\nINFO: Started server process [75722]\r\nINFO: Waiting for application startup.\r\nINFO: Application startup complete.\r\nINFO: Uvicorn running on http://127.0.0.1:8064 (Press CTRL+C to quit)\r\n Running curls\r\n Running curls\r\n Running curls\r\nKilling datasette server with PID 75722\r\n../airtable-export/testit.sh: line 54: 75722 Killed: 9 datasette pottery2.db -p $port\r\nError: Not all curls succeeded after 3 attempts.\r\nBisecting: 77 revisions left to test after this (roughly 6 steps)\r\n[3ef47a0896c7e63404a34e465b7160c80eaa571d] Link rel=alternate header for tables and rows\r\nrunning '../airtable-export/testit.sh'\r\nINFO: Started server process [75818]\r\nINFO: Waiting for application startup.\r\nINFO: Application startup complete.\r\nINFO: Uvicorn running on http://127.0.0.1:8064 (Press CTRL+C to quit)\r\n Running curls\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2190#issuecomment-1724169693", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2190", "id": 1724169693, "node_id": "IC_kwDOBm6k_c5mxL3d", "user": {"value": 22429695, "label": "codecov[bot]"}, "created_at": "2023-09-18T18:39:19Z", "updated_at": "2023-09-18T18:39:19Z", "author_association": "NONE", "body": "## [Codecov](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) Report\nPatch coverage: **`100.00%`** and project coverage change: **`-0.03%`** :warning:\n> Comparison is base [(`6ed7908`)](https://app.codecov.io/gh/simonw/datasette/commit/6ed7908580fa2ba9297c3225d85c56f8b08b9937?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.69% compared to head [(`fc7dbe0`)](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.67%.\n\n
Additional details and impacted files\n\n\n```diff\n@@ Coverage Diff @@\n## main #2190 +/- ##\n==========================================\n- Coverage 92.69% 92.67% -0.03% \n==========================================\n Files 40 40 \n Lines 6039 6044 +5 \n==========================================\n+ Hits 5598 5601 +3 \n- Misses 441 443 +2 \n```\n\n\n| [Files Changed](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) | Coverage \u0394 | |\n|---|---|---|\n| [datasette/app.py](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2FwcC5weQ==) | `94.19% <100.00%> (\u00f8)` | |\n| [datasette/cli.py](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2NsaS5weQ==) | `82.53% <100.00%> (\u00f8)` | |\n| [datasette/utils/\\_\\_init\\_\\_.py](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3V0aWxzL19faW5pdF9fLnB5) | `94.83% <100.00%> (+0.03%)` | :arrow_up: |\n\n... and [1 file with indirect coverage changes](https://app.codecov.io/gh/simonw/datasette/pull/2190/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison)\n\n\n
\n\n[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simonw/datasette/pull/2190?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison). \n:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901483874, "label": "Raise an exception if a \"plugins\" block exists in metadata.json"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724159882", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724159882, "node_id": "IC_kwDOBm6k_c5mxJeK", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T18:32:29Z", "updated_at": "2023-09-18T18:32:29Z", "author_association": "OWNER", "body": "This worked, including on macOS even though GPT-4 thought `timeout` would not work there: https://chat.openai.com/share/cc4628e9-5240-4f35-b640-16a9c178b315\r\n```bash\r\n#!/bin/bash\r\n\r\n# Run the command with a timeout of 5 seconds\r\ntimeout 5s datasette pottery2.db -p 8045 --get /airtable_refs/airtable_refs\r\n\r\n# Check the exit code from timeout\r\nif [ $? -eq 124 ]; then\r\n echo \"Error: Command timed out after 5 seconds.\"\r\n exit 1\r\nfi\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724157182", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724157182, "node_id": "IC_kwDOBm6k_c5mxIz-", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T18:30:30Z", "updated_at": "2023-09-18T18:30:30Z", "author_association": "OWNER", "body": "OK, I can trigger the bug like this:\r\n\r\n```bash\r\ndatasette pottery2.db -p 8045 --get /airtable_refs/airtable_refs\r\n```\r\nCan I write a bash script that fails (and terminates the process) if it takes longer than X seconds?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724089666", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724089666, "node_id": "IC_kwDOBm6k_c5mw4VC", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:49:24Z", "updated_at": "2023-09-18T17:49:24Z", "author_association": "OWNER", "body": "I switched that particular implementation to using an on-disk database instead of an in-memory database and could no longer recreate the bug.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724084199", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724084199, "node_id": "IC_kwDOBm6k_c5mw2_n", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:47:01Z", "updated_at": "2023-09-18T17:47:01Z", "author_association": "OWNER", "body": "I managed to trigger it by loading `http://127.0.0.1:8045/airtable_refs/airtable_refs` - which worked - and then hitting refresh on that page a bunch of times until it hung.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724083324", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724083324, "node_id": "IC_kwDOBm6k_c5mw2x8", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:46:21Z", "updated_at": "2023-09-18T17:46:21Z", "author_association": "OWNER", "body": "Sometimes it takes a few clicks for the bug to occur, but it does seem to always be within the in-memory database.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724081909", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724081909, "node_id": "IC_kwDOBm6k_c5mw2b1", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:45:27Z", "updated_at": "2023-09-18T17:45:27Z", "author_association": "OWNER", "body": "Maybe it's not related to faceting - I just got it on a hit to `http://127.0.0.1:8045/airtable_refs/airtable_refs` instead.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724072390", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724072390, "node_id": "IC_kwDOBm6k_c5mw0HG", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:39:06Z", "updated_at": "2023-09-18T17:39:06Z", "author_association": "OWNER", "body": "Landing a version of that test anyway.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724064440", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724064440, "node_id": "IC_kwDOBm6k_c5mwyK4", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:36:00Z", "updated_at": "2023-09-18T17:36:00Z", "author_association": "OWNER", "body": "I wrote this test, but it passes:\r\n```python\r\n@pytest.mark.asyncio\r\nasync def test_facet_against_in_memory_database():\r\n ds = Datasette()\r\n db = ds.add_memory_database(\"mem\")\r\n await db.execute_write(\"create table t (id integer primary key, name text)\")\r\n await db.execute_write_many(\r\n \"insert into t (name) values (?)\", [[\"one\"], [\"one\"], [\"two\"]]\r\n )\r\n response1 = await ds.client.get(\"/mem/t.json\")\r\n assert response1.status_code == 200\r\n response2 = await ds.client.get(\"/mem/t.json?_facet=name\")\r\n assert response2.status_code == 200\r\n assert response2.json() == {\r\n \"ok\": True,\r\n \"next\": None,\r\n \"facet_results\": {\r\n \"results\": {\r\n \"name\": {\r\n \"name\": \"name\",\r\n \"type\": \"column\",\r\n \"hideable\": True,\r\n \"toggle_url\": \"/mem/t.json\",\r\n \"results\": [\r\n {\r\n \"value\": \"one\",\r\n \"label\": \"one\",\r\n \"count\": 2,\r\n \"toggle_url\": \"http://localhost/mem/t.json?_facet=name&name=one\",\r\n \"selected\": False,\r\n },\r\n {\r\n \"value\": \"two\",\r\n \"label\": \"two\",\r\n \"count\": 1,\r\n \"toggle_url\": \"http://localhost/mem/t.json?_facet=name&name=two\",\r\n \"selected\": False,\r\n },\r\n ],\r\n \"truncated\": False,\r\n }\r\n },\r\n \"timed_out\": [],\r\n },\r\n \"rows\": [\r\n {\"id\": 1, \"name\": \"one\"},\r\n {\"id\": 2, \"name\": \"one\"},\r\n {\"id\": 3, \"name\": \"two\"},\r\n ],\r\n \"truncated\": False,\r\n }\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724055823", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724055823, "node_id": "IC_kwDOBm6k_c5mwwEP", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:31:10Z", "updated_at": "2023-09-18T17:31:10Z", "author_association": "OWNER", "body": "That line was added in https://github.com/simonw/datasette/commit/942411ef946e9a34a2094944d3423cddad27efd3 which first shipped in 0.62a0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724051886", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724051886, "node_id": "IC_kwDOBm6k_c5mwvGu", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:28:20Z", "updated_at": "2023-09-18T17:30:30Z", "author_association": "OWNER", "body": "The bug exhibits when I try to add a facet. I think it's caused by the parallel query execution I added to facets at some point.\r\n\r\nhttp://127.0.0.1:8045/airtable_refs/airtable_refs - no error\r\nhttp://127.0.0.1:8045/airtable_refs/airtable_refs?_facet=table_name#facet-table_name - hangs the server\r\n\r\nCrucial line in the traceback:\r\n```\r\n await gather(execute_facets(), execute_suggested_facets())\r\n```\r\nFrom here: https://github.com/simonw/datasette/blob/917272c864ad7b8a00c48c77f5c2944093babb4e/datasette/views/table.py#L568", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724049538", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724049538, "node_id": "IC_kwDOBm6k_c5mwuiC", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:26:44Z", "updated_at": "2023-09-18T17:26:44Z", "author_association": "OWNER", "body": "Just managed to get this exception trace:\r\n```\r\n return await self.route_path(scope, receive, send, path)\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/app.py\", line 1354, in route_path\r\n response = await view(request, send)\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/views/base.py\", line 134, in view\r\n return await self.dispatch_request(request)\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/views/base.py\", line 91, in dispatch_request\r\n return await handler(request)\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/views/base.py\", line 361, in get\r\n response_or_template_contexts = await self.data(request, **data_kwargs)\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/views/table.py\", line 158, in data\r\n return await self._data_traced(request, default_labels, _next, _size)\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/views/table.py\", line 568, in _data_traced\r\n await gather(execute_facets(), execute_suggested_facets())\r\n File \"/Users/simon/.local/share/virtualenvs/airtable-export-Ca4U-3qk/lib/python3.8/site-packages/datasette/views/table.py\", line 177, in _gather_parallel\r\n return await asyncio.gather(*args)\r\nasyncio.exceptions.CancelledError\r\nINFO: 127.0.0.1:64109 - \"GET /airtable_refs/airtable_refs?_facet=table_name&table_name=Sessions HTTP/1.1\" 500 Internal Server Error\r\n^CError in atexit._run_exitfuncs:\r\nTraceback (most recent call last):\r\n File \"/Users/simon/.pyenv/versions/3.8.17/lib/python3.8/concurrent/futures/thread.py\", line 40, in _python_exit\r\n t.join()\r\n File \"/Users/simon/.pyenv/versions/3.8.17/lib/python3.8/threading.py\", line 1011, in join\r\n self._wait_for_tstate_lock()\r\n File \"/Users/simon/.pyenv/versions/3.8.17/lib/python3.8/threading.py\", line 1027, in _wait_for_tstate_lock\r\n elif lock.acquire(block, timeout):\r\nKeyboardInterrupt\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724048314", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724048314, "node_id": "IC_kwDOBm6k_c5mwuO6", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:25:55Z", "updated_at": "2023-09-18T17:25:55Z", "author_association": "OWNER", "body": "The good news is that this bug is currently unlikely to affect most users since named in-memory databases (created using `datasette.add_memory_database(\"airtable_refs\")` ([docs](https://docs.datasette.io/en/stable/internals.html#add-memory-database-name)) are a pretty obscure feature, only available to plugins.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2189#issuecomment-1724045748", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2189", "id": 1724045748, "node_id": "IC_kwDOBm6k_c5mwtm0", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T17:24:07Z", "updated_at": "2023-09-18T17:24:07Z", "author_association": "OWNER", "body": "I need reliable steps to reproduce, then I can bisect and figure out which exact version of Datasette introduced the problem.\r\n\r\nI have a hunch that it relates to changes made to the `datasette/database.py` module, maybe one of these changes here: https://github.com/simonw/datasette/compare/0.61...0.63.1#diff-4e20309c969326a0008dc9237f6807f48d55783315fbfc1e7dfa480b550e16f9", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1901416155, "label": "Server hang on parallel execution of queries to named in-memory databases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2123#issuecomment-1723362847", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2123", "id": 1723362847, "node_id": "IC_kwDOBm6k_c5muG4f", "user": {"value": 6523121, "label": "hueyy"}, "created_at": "2023-09-18T13:02:46Z", "updated_at": "2023-09-18T13:02:46Z", "author_association": "NONE", "body": "Can confirm that this bug can be reproduced as follows:\r\n\r\n```\r\ndocker run datasetteproject/datasette datasette serve --reload \r\n```\r\n\r\nwhich produces the following output:\r\n\r\n> Starting monitor for PID 10.\r\n> Error: Invalid value for '[FILES]...': Path 'serve' does not exist.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1825007061, "label": "datasette serve when invoked with --reload interprets the serve command as a file"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2052#issuecomment-1722943484", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2052", "id": 1722943484, "node_id": "IC_kwDOBm6k_c5msgf8", "user": {"value": 30934, "label": "20after4"}, "created_at": "2023-09-18T08:14:47Z", "updated_at": "2023-09-18T08:14:47Z", "author_association": "NONE", "body": "This is such a well thought out contribution. I don't think I've seen such a thoroughly considered PR on any project in recent memory.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1651082214, "label": "feat: Javascript Plugin API (Custom panels, column menu items with JS actions)"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2188#issuecomment-1722848454", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2188", "id": 1722848454, "node_id": "IC_kwDOBm6k_c5msJTG", "user": {"value": 15178711, "label": "asg017"}, "created_at": "2023-09-18T06:58:53Z", "updated_at": "2023-09-18T06:58:53Z", "author_association": "CONTRIBUTOR", "body": "Thinking about this more, here a list of things I imagine a \"compile-to-sql\" plugin would want to do:\r\n\r\n1. Attach itself to the SQL code editor (switch from SQL -> PRQL/Logica, additional syntax highlighting)\r\n2. Add \"Query using PRQL\" buttons in various parts of Datasette's UI, like `/dbname` page\r\n3. Use `$LANGUAGE=` instead of `sql=` in the JSON API and the SQL results pages\r\n4. Have their own dedicated code editor page\r\n\r\n\r\n1) and 2) would be difficult to do with current plugin hooks, unless we add the concept of \"slots\" and get the JS plugin support in. 3) could maybe be done with the [`asgi_wrapper(datasette)`](https://docs.datasette.io/en/stable/plugin_hooks.html#asgi-wrapper-datasette) hook? And 4) ca n be done easily with the `register_routes()` hooks. \r\n\r\nSo it really only sounds like extending the SQL editor will be the hard part. In #2094 I want to add JavaScript plugin hooks for extending the SQL editor, which may work here. \r\n\r\nIf I get the time/motivation, I might try out a `datasette-prql` extension, just because I like playing with it. It'd be really cool if I can get the `asgi_wrapper()` hook to work right there...", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1900026059, "label": "Plugin Hooks for \"compile to SQL\" languages"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1191#issuecomment-1722845490", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1191", "id": 1722845490, "node_id": "IC_kwDOBm6k_c5msIky", "user": {"value": 15178711, "label": "asg017"}, "created_at": "2023-09-18T06:55:52Z", "updated_at": "2023-09-18T06:55:52Z", "author_association": "CONTRIBUTOR", "body": "One note here: this feature could be called \"slots\", similar to [Layout Slots](https://vitepress.dev/guide/extending-default-theme#layout-slots) in Vitepress.\r\n\r\nIn Vitepress, you can add custom components/widget/gadgets into determined named \"slots\", like so:\r\n\r\n```\r\ndoc-top\r\ndoc-bottom\r\ndoc-footer-before\r\ndoc-before\r\ndoc-after\r\n...\r\n```\r\n\r\nWould be great to do in both Python and Javascript, with the upcoming JavaScript API #2052. In `datasette-write-ui`, all we do is add a few \"Insert row\" and \"edit this row\" buttons and that required completely capturing the `table.html` template, which isn't great for other plugins. But having \"slots\" like `table-footer-before` or `table-row-id` or something would be great to work with.\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 787098345, "label": "Ability for plugins to collaborate when adding extra HTML to blocks in default templates"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2188#issuecomment-1722662413", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2188", "id": 1722662413, "node_id": "IC_kwDOBm6k_c5mrb4N", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-18T02:01:34Z", "updated_at": "2023-09-18T02:01:34Z", "author_association": "OWNER", "body": "I'm not interested in these in Datasette core itself, but I think they have a ton of potential for plugins.\r\n\r\nI wonder what the best way to handle that would be?\r\n\r\nRight now it's possible to write a plugin that [adds extra routes](https://docs.datasette.io/en/stable/plugin_hooks.html#register-routes-datasette), so someone could build a `/dbname/-/prql?query=xxx` endpoint.\r\n\r\nIf this could return JSON, they could add JavaScript to the `/dbname` page that provided a UI for kicking off one of those queries.\r\n\r\nSomething that could make that more ergonomic might be the plugin hook that allows plugins to add extra HTML to different core database pages - e.g. adding a \"Query this database using PRQL\" button or link or even a full form at the top of that database page. That's this issue here:\r\n\r\n- #1191", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1900026059, "label": "Plugin Hooks for \"compile to SQL\" languages"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1722323967", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1722323967, "node_id": "IC_kwDOBm6k_c5mqJP_", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-16T21:54:33Z", "updated_at": "2023-09-16T21:54:33Z", "author_association": "OWNER", "body": "Just found this migration guide: https://importlib-metadata.readthedocs.io/en/latest/migration.html", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1722266942", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1722266942, "node_id": "IC_kwDOBm6k_c5mp7U-", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-16T16:38:27Z", "updated_at": "2023-09-16T16:38:27Z", "author_association": "OWNER", "body": "The `importlib.metadata.entry_points()` function is pretty interesting:\r\n```pycon\r\n>>> import importlib.metadata\r\n>>> from pprint import pprint\r\n>>> pprint(importlib.metadata.entry_points())\r\n{'babel.checkers': [EntryPoint(name='num_plurals', value='babel.messages.checkers:num_plurals', group='babel.checkers'),\r\n EntryPoint(name='python_format', value='babel.messages.checkers:python_format', group='babel.checkers')],\r\n 'babel.extractors': [EntryPoint(name='jinja2', value='jinja2.ext:babel_extract[i18n]', group='babel.extractors'),\r\n EntryPoint(name='ignore', value='babel.messages.extract:extract_nothing', group='babel.extractors'),\r\n EntryPoint(name='javascript', value='babel.messages.extract:extract_javascript', group='babel.extractors'),\r\n EntryPoint(name='python', value='babel.messages.extract:extract_python', group='babel.extractors')],\r\n 'console_scripts': [EntryPoint(name='datasette', value='datasette.cli:cli', group='console_scripts'),\r\n EntryPoint(name='normalizer', value='charset_normalizer.cli.normalizer:cli_detect', group='console_scripts'),\r\n EntryPoint(name='pypprint', value='pprintpp:console', group='console_scripts'),\r\n EntryPoint(name='cog', value='cogapp:main', group='console_scripts'),\r\n EntryPoint(name='icdiff', value='icdiff:start', group='console_scripts'),\r\n EntryPoint(name='pycodestyle', value='pycodestyle:_main', group='console_scripts'),\r\n EntryPoint(name='sphinx-autobuild', value='sphinx_autobuild.__main__:main', group='console_scripts'),\r\n EntryPoint(name='sphinx-apidoc', value='sphinx.ext.apidoc:main', group='console_scripts'),\r\n EntryPoint(name='sphinx-autogen', value='sphinx.ext.autosummary.generate:main', group='console_scripts'),\r\n EntryPoint(name='sphinx-build', value='sphinx.cmd.build:main', group='console_scripts'),\r\n EntryPoint(name='sphinx-quickstart', value='sphinx.cmd.quickstart:main', group='console_scripts'),\r\n EntryPoint(name='sphinx-to-sqlite', value='sphinx_to_sqlite.cli:cli', group='console_scripts'),\r\n EntryPoint(name='pybabel', value='babel.messages.frontend:main', group='console_scripts'),\r\n EntryPoint(name='docutils', value='docutils.__main__:main', group='console_scripts'),\r\n EntryPoint(name='isort', value='isort.main:main', group='console_scripts'),\r\n EntryPoint(name='isort-identify-imports', value='isort.main:identify_imports_main', group='console_scripts'),\r\n EntryPoint(name='hupper', value='hupper.cli:main', group='console_scripts'),\r\n EntryPoint(name='sqlite-utils', value='sqlite_utils.cli:cli', group='console_scripts'),\r\n EntryPoint(name='py.test', value='pytest:console_main', group='console_scripts'),\r\n EntryPoint(name='pytest', value='pytest:console_main', group='console_scripts'),\r\n EntryPoint(name='pyflakes', value='pyflakes.api:main', group='console_scripts'),\r\n EntryPoint(name='livereload', value='livereload.cli:main', group='console_scripts'),\r\n EntryPoint(name='uvicorn', value='uvicorn.main:main', group='console_scripts'),\r\n EntryPoint(name='httpx', value='httpx:main', group='console_scripts'),\r\n EntryPoint(name='flake8', value='flake8.main.cli:main', group='console_scripts'),\r\n EntryPoint(name='blacken-docs', value='blacken_docs:main', group='console_scripts'),\r\n EntryPoint(name='pip', value='pip._internal.cli.main:main', group='console_scripts'),\r\n EntryPoint(name='pip3', value='pip._internal.cli.main:main', group='console_scripts'),\r\n EntryPoint(name='pip3.10', value='pip._internal.cli.main:main', group='console_scripts'),\r\n EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts'),\r\n EntryPoint(name='pygmentize', value='pygments.cmdline:main', group='console_scripts'),\r\n EntryPoint(name='black', value='black:patched_main', group='console_scripts'),\r\n EntryPoint(name='blackd', value='blackd:patched_main [d]', group='console_scripts'),\r\n EntryPoint(name='codespell', value='codespell_lib:_script_main', group='console_scripts'),\r\n EntryPoint(name='tabulate', value='tabulate:_main', group='console_scripts')],\r\n 'datasette': [EntryPoint(name='debug_permissions', value='datasette_debug_permissions', group='datasette'),\r\n EntryPoint(name='codespaces', value='datasette_codespaces', group='datasette'),\r\n EntryPoint(name='vega', value='datasette_vega', group='datasette'),\r\n EntryPoint(name='x_forwarded_host', value='datasette_x_forwarded_host', group='datasette'),\r\n EntryPoint(name='json_html', value='datasette_json_html', group='datasette'),\r\n EntryPoint(name='datasette_write_ui', value='datasette_write_ui', group='datasette'),\r\n EntryPoint(name='pretty_json', value='datasette_pretty_json', group='datasette'),\r\n EntryPoint(name='graphql', value='datasette_graphql', group='datasette')],\r\n 'distutils.commands': [EntryPoint(name='compile_catalog', value='babel.messages.frontend:compile_catalog', group='distutils.commands'),\r\n EntryPoint(name='extract_messages', value='babel.messages.frontend:extract_messages', group='distutils.commands'),\r\n EntryPoint(name='init_catalog', value='babel.messages.frontend:init_catalog', group='distutils.commands'),\r\n EntryPoint(name='update_catalog', value='babel.messages.frontend:update_catalog', group='distutils.commands'),\r\n EntryPoint(name='isort', value='isort.setuptools_commands:ISortCommand', group='distutils.commands'),\r\n EntryPoint(name='alias', value='setuptools.command.alias:alias', group='distutils.commands'),\r\n EntryPoint(name='bdist_egg', value='setuptools.command.bdist_egg:bdist_egg', group='distutils.commands'),\r\n EntryPoint(name='bdist_rpm', value='setuptools.command.bdist_rpm:bdist_rpm', group='distutils.commands'),\r\n EntryPoint(name='build', value='setuptools.command.build:build', group='distutils.commands'),\r\n EntryPoint(name='build_clib', value='setuptools.command.build_clib:build_clib', group='distutils.commands'),\r\n EntryPoint(name='build_ext', value='setuptools.command.build_ext:build_ext', group='distutils.commands'),\r\n EntryPoint(name='build_py', value='setuptools.command.build_py:build_py', group='distutils.commands'),\r\n EntryPoint(name='develop', value='setuptools.command.develop:develop', group='distutils.commands'),\r\n EntryPoint(name='dist_info', value='setuptools.command.dist_info:dist_info', group='distutils.commands'),\r\n EntryPoint(name='easy_install', value='setuptools.command.easy_install:easy_install', group='distutils.commands'),\r\n EntryPoint(name='editable_wheel', value='setuptools.command.editable_wheel:editable_wheel', group='distutils.commands'),\r\n EntryPoint(name='egg_info', value='setuptools.command.egg_info:egg_info', group='distutils.commands'),\r\n EntryPoint(name='install', value='setuptools.command.install:install', group='distutils.commands'),\r\n EntryPoint(name='install_egg_info', value='setuptools.command.install_egg_info:install_egg_info', group='distutils.commands'),\r\n EntryPoint(name='install_lib', value='setuptools.command.install_lib:install_lib', group='distutils.commands'),\r\n EntryPoint(name='install_scripts', value='setuptools.command.install_scripts:install_scripts', group='distutils.commands'),\r\n EntryPoint(name='rotate', value='setuptools.command.rotate:rotate', group='distutils.commands'),\r\n EntryPoint(name='saveopts', value='setuptools.command.saveopts:saveopts', group='distutils.commands'),\r\n EntryPoint(name='sdist', value='setuptools.command.sdist:sdist', group='distutils.commands'),\r\n EntryPoint(name='setopt', value='setuptools.command.setopt:setopt', group='distutils.commands'),\r\n EntryPoint(name='test', value='setuptools.command.test:test', group='distutils.commands'),\r\n EntryPoint(name='upload_docs', value='setuptools.command.upload_docs:upload_docs', group='distutils.commands'),\r\n EntryPoint(name='bdist_wheel', value='wheel.bdist_wheel:bdist_wheel', group='distutils.commands')],\r\n 'distutils.setup_keywords': [EntryPoint(name='message_extractors', value='babel.messages.frontend:check_message_extractors', group='distutils.setup_keywords'),\r\n EntryPoint(name='cffi_modules', value='cffi.setuptools_ext:cffi_modules', group='distutils.setup_keywords'),\r\n EntryPoint(name='dependency_links', value='setuptools.dist:assert_string_list', group='distutils.setup_keywords'),\r\n EntryPoint(name='eager_resources', value='setuptools.dist:assert_string_list', group='distutils.setup_keywords'),\r\n EntryPoint(name='entry_points', value='setuptools.dist:check_entry_points', group='distutils.setup_keywords'),\r\n EntryPoint(name='exclude_package_data', value='setuptools.dist:check_package_data', group='distutils.setup_keywords'),\r\n EntryPoint(name='extras_require', value='setuptools.dist:check_extras', group='distutils.setup_keywords'),\r\n EntryPoint(name='include_package_data', value='setuptools.dist:assert_bool', group='distutils.setup_keywords'),\r\n EntryPoint(name='install_requires', value='setuptools.dist:check_requirements', group='distutils.setup_keywords'),\r\n EntryPoint(name='namespace_packages', value='setuptools.dist:check_nsp', group='distutils.setup_keywords'),\r\n EntryPoint(name='package_data', value='setuptools.dist:check_package_data', group='distutils.setup_keywords'),\r\n EntryPoint(name='packages', value='setuptools.dist:check_packages', group='distutils.setup_keywords'),\r\n EntryPoint(name='python_requires', value='setuptools.dist:check_specifier', group='distutils.setup_keywords'),\r\n EntryPoint(name='setup_requires', value='setuptools.dist:check_requirements', group='distutils.setup_keywords'),\r\n EntryPoint(name='test_loader', value='setuptools.dist:check_importable', group='distutils.setup_keywords'),\r\n EntryPoint(name='test_runner', value='setuptools.dist:check_importable', group='distutils.setup_keywords'),\r\n EntryPoint(name='test_suite', value='setuptools.dist:check_test_suite', group='distutils.setup_keywords'),\r\n EntryPoint(name='tests_require', value='setuptools.dist:check_requirements', group='distutils.setup_keywords'),\r\n EntryPoint(name='use_2to3', value='setuptools.dist:invalid_unless_false', group='distutils.setup_keywords'),\r\n EntryPoint(name='zip_safe', value='setuptools.dist:assert_bool', group='distutils.setup_keywords')],\r\n 'egg_info.writers': [EntryPoint(name='PKG-INFO', value='setuptools.command.egg_info:write_pkg_info', group='egg_info.writers'),\r\n EntryPoint(name='dependency_links.txt', value='setuptools.command.egg_info:overwrite_arg', group='egg_info.writers'),\r\n EntryPoint(name='depends.txt', value='setuptools.command.egg_info:warn_depends_obsolete', group='egg_info.writers'),\r\n EntryPoint(name='eager_resources.txt', value='setuptools.command.egg_info:overwrite_arg', group='egg_info.writers'),\r\n EntryPoint(name='entry_points.txt', value='setuptools.command.egg_info:write_entries', group='egg_info.writers'),\r\n EntryPoint(name='namespace_packages.txt', value='setuptools.command.egg_info:overwrite_arg', group='egg_info.writers'),\r\n EntryPoint(name='requires.txt', value='setuptools.command.egg_info:write_requirements', group='egg_info.writers'),\r\n EntryPoint(name='top_level.txt', value='setuptools.command.egg_info:write_toplevel_names', group='egg_info.writers')],\r\n 'flake8.extension': [EntryPoint(name='C90', value='mccabe:McCabeChecker', group='flake8.extension'),\r\n EntryPoint(name='E', value='flake8.plugins.pycodestyle:pycodestyle_logical', group='flake8.extension'),\r\n EntryPoint(name='F', value='flake8.plugins.pyflakes:FlakesChecker', group='flake8.extension'),\r\n EntryPoint(name='W', value='flake8.plugins.pycodestyle:pycodestyle_physical', group='flake8.extension')],\r\n 'flake8.report': [EntryPoint(name='default', value='flake8.formatting.default:Default', group='flake8.report'),\r\n EntryPoint(name='pylint', value='flake8.formatting.default:Pylint', group='flake8.report'),\r\n EntryPoint(name='quiet-filename', value='flake8.formatting.default:FilenameOnly', group='flake8.report'),\r\n EntryPoint(name='quiet-nothing', value='flake8.formatting.default:Nothing', group='flake8.report')],\r\n 'pylama.linter': [EntryPoint(name='isort', value='isort.pylama_isort:Linter', group='pylama.linter')],\r\n 'pytest11': [EntryPoint(name='icdiff', value='pytest_icdiff', group='pytest11'),\r\n EntryPoint(name='asyncio', value='pytest_asyncio.plugin', group='pytest11'),\r\n EntryPoint(name='xdist', value='xdist.plugin', group='pytest11'),\r\n EntryPoint(name='xdist.looponfail', value='xdist.looponfail', group='pytest11'),\r\n EntryPoint(name='timeout', value='pytest_timeout', group='pytest11'),\r\n EntryPoint(name='anyio', value='anyio.pytest_plugin', group='pytest11')],\r\n 'setuptools.finalize_distribution_options': [EntryPoint(name='keywords', value='setuptools.dist:Distribution._finalize_setup_keywords', group='setuptools.finalize_distribution_options'),\r\n EntryPoint(name='parent_finalize', value='setuptools.dist:_Distribution.finalize_options', group='setuptools.finalize_distribution_options')],\r\n 'sphinx.html_themes': [EntryPoint(name='alabaster', value='alabaster', group='sphinx.html_themes'),\r\n EntryPoint(name='basic-ng', value='sphinx_basic_ng', group='sphinx.html_themes'),\r\n EntryPoint(name='furo', value='furo', group='sphinx.html_themes')],\r\n 'sqlite_utils': [EntryPoint(name='hello_world', value='sqlite_utils_hello_world', group='sqlite_utils')]}\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1722266513", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1722266513, "node_id": "IC_kwDOBm6k_c5mp7OR", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-16T16:36:09Z", "updated_at": "2023-09-16T16:36:09Z", "author_association": "OWNER", "body": "Now I need to switch out `pkg_resources` in `plugins.py`:\r\n\r\nhttps://github.com/simonw/datasette/blob/852f5014853943fa27f43ddaa2d442545b3259fb/datasette/plugins.py#L33-L74", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1722265848", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1722265848, "node_id": "IC_kwDOBm6k_c5mp7D4", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-16T16:32:42Z", "updated_at": "2023-09-16T16:32:42Z", "author_association": "OWNER", "body": "Here's the exception it uses:\r\n```pycon\r\n>>> importlib.metadata.version(\"datasette\")\r\n'1.0a6'\r\n>>> importlib.metadata.version(\"datasette2\")\r\nTraceback (most recent call last):\r\n File \"\", line 1, in \r\n File \"/opt/homebrew/Caskroom/miniconda/base/lib/python3.10/importlib/metadata/__init__.py\", line 996, in version\r\n return distribution(distribution_name).version\r\n File \"/opt/homebrew/Caskroom/miniconda/base/lib/python3.10/importlib/metadata/__init__.py\", line 969, in distribution\r\n return Distribution.from_name(distribution_name)\r\n File \"/opt/homebrew/Caskroom/miniconda/base/lib/python3.10/importlib/metadata/__init__.py\", line 548, in from_name\r\n raise PackageNotFoundError(name)\r\nimportlib.metadata.PackageNotFoundError: No package metadata was found for datasette2\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1722258980", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1722258980, "node_id": "IC_kwDOBm6k_c5mp5Yk", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-16T15:56:45Z", "updated_at": "2023-09-16T15:56:45Z", "author_association": "OWNER", "body": "Weird, I still can't get the warning to show even with this:\r\n```python\r\n@pytest.mark.asyncio\r\nasync def test_plugin_is_installed():\r\n datasette = Datasette(memory=True)\r\n\r\n class DummyPlugin:\r\n __name__ = \"DummyPlugin\"\r\n\r\n @hookimpl\r\n def actors_from_ids(self, datasette, actor_ids):\r\n return {}\r\n\r\n try:\r\n pm.register(DummyPlugin(), name=\"DummyPlugin\")\r\n response = await datasette.client.get(\"/-/plugins.json\")\r\n assert response.status_code == 200\r\n installed_plugins = {p[\"name\"] for p in response.json()}\r\n assert \"DummyPlugin\" in installed_plugins\r\n\r\n finally:\r\n pm.unregister(name=\"ReturnNothingPlugin\")\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2057#issuecomment-1722257328", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2057", "id": 1722257328, "node_id": "IC_kwDOBm6k_c5mp4-w", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-16T15:47:32Z", "updated_at": "2023-09-16T15:47:32Z", "author_association": "OWNER", "body": "Frustrating that this warning doesn't show up in the Datasette test suite itself. It shows up in plugin test suites that run this test:\r\n```python\r\n@pytest.mark.asyncio\r\nasync def test_plugin_is_installed():\r\n datasette = Datasette(memory=True)\r\n response = await datasette.client.get(\"/-/plugins.json\")\r\n assert response.status_code == 200\r\n installed_plugins = {p[\"name\"] for p in response.json()}\r\n assert \"datasette-chronicle\" in installed_plugins\r\n```\r\nIf you run that test inside Datasette core `installed_plugins` is an empty set, which presumably is why the warning doesn't get triggered there.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1662951875, "label": "DeprecationWarning: pkg_resources is deprecated as an API"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2186#issuecomment-1721742055", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2186", "id": 1721742055, "node_id": "IC_kwDOBm6k_c5mn7Ln", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-15T19:27:59Z", "updated_at": "2023-09-15T19:27:59Z", "author_association": "OWNER", "body": "This feels like it might be quite a nice pattern generally - providing optional arguments to plugins and views that can be `await get_x()` called to run an extra calculation.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1898927976, "label": "Mechanism for register_output_renderer hooks to access full count"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2186#issuecomment-1721740872", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2186", "id": 1721740872, "node_id": "IC_kwDOBm6k_c5mn65I", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-15T19:26:51Z", "updated_at": "2023-09-15T19:27:19Z", "author_association": "OWNER", "body": "Here's where it's called at the moment: https://github.com/simonw/datasette/blob/16f0b6d8222d06682a31b904d0a402c391ae1c1c/datasette/views/base.py#L297-L313\r\n\r\nAnd the docs: https://github.com/simonw/datasette/blob/1.0a6/docs/plugin_hooks.rst#register-output-renderer-datasette\r\n\r\nI'm tempted to add a `get_count` argument which, when awaited, returns the full count. Then plugins could do this:\r\n\r\n```python\r\nasync def render_notebook(datasette, request, get_count, rows):\r\n count = await get_count()\r\n # ...\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1898927976, "label": "Mechanism for register_output_renderer hooks to access full count"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2182#issuecomment-1719451803", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2182", "id": 1719451803, "node_id": "IC_kwDOBm6k_c5mfMCb", "user": {"value": 49699333, "label": "dependabot[bot]"}, "created_at": "2023-09-14T13:27:26Z", "updated_at": "2023-09-14T13:27:26Z", "author_association": "CONTRIBUTOR", "body": "Looks like these dependencies are updatable in another way, so this is no longer needed.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1890593563, "label": "Bump the python-packages group with 2 updates"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2183#issuecomment-1718316733", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2183", "id": 1718316733, "node_id": "IC_kwDOBm6k_c5ma269", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-13T21:05:36Z", "updated_at": "2023-09-13T21:05:36Z", "author_association": "OWNER", "body": "I'm going to land this and make any further documentation tweaks on `main`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1891212159, "label": "`datasette.yaml` plugin support"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2183#issuecomment-1714544153", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2183", "id": 1714544153, "node_id": "IC_kwDOBm6k_c5mMd4Z", "user": {"value": 22429695, "label": "codecov[bot]"}, "created_at": "2023-09-11T20:37:52Z", "updated_at": "2023-09-13T20:58:51Z", "author_association": "NONE", "body": "## [Codecov](https://app.codecov.io/gh/simonw/datasette/pull/2183?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) Report\nPatch coverage: **`95.00%`** and project coverage change: **`-0.04%`** :warning:\n> Comparison is base [(`a4c96d0`)](https://app.codecov.io/gh/simonw/datasette/commit/a4c96d01b27ce7cd06662a024da3547132a7c412?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.69% compared to head [(`659dcbd`)](https://app.codecov.io/gh/simonw/datasette/pull/2183?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) 92.66%.\n\n> :exclamation: Current head 659dcbd differs from pull request most recent head acca338. Consider uploading reports for the commit acca338 to get more accurate results\n\n
Additional details and impacted files\n\n\n```diff\n@@ Coverage Diff @@\n## main #2183 +/- ##\n==========================================\n- Coverage 92.69% 92.66% -0.04% \n==========================================\n Files 40 40 \n Lines 6025 6039 +14 \n==========================================\n+ Hits 5585 5596 +11 \n- Misses 440 443 +3 \n```\n\n\n| [Files Changed](https://app.codecov.io/gh/simonw/datasette/pull/2183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) | Coverage \u0394 | |\n|---|---|---|\n| [datasette/app.py](https://app.codecov.io/gh/simonw/datasette/pull/2183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2FwcC5weQ==) | `94.19% <95.00%> (-0.24%)` | :arrow_down: |\n\n\n
\n\n[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/simonw/datasette/pull/2183?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison). \n:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1891212159, "label": "`datasette.yaml` plugin support"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2183#issuecomment-1716801971", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2183", "id": 1716801971, "node_id": "IC_kwDOBm6k_c5mVFGz", "user": {"value": 15178711, "label": "asg017"}, "created_at": "2023-09-13T01:34:01Z", "updated_at": "2023-09-13T01:34:01Z", "author_association": "CONTRIBUTOR", "body": "@simonw docs are finished, this is ready for review!\r\n\r\nOne thing: I added \"Configuration\" as a top-level item in the documentation site, at the very bottom. Not sure if this is the best, maybe it can be named \"datasette.yaml Configuration\" or something similar?\r\n\r\nMostly because \"Configuration\" by itself can mean many things, but adding \"datasette.yaml\" would make it pretty clear it's about that specific file, and is easier to scan. I'd also be fine with using \"datasette.yaml\" instead of \"datasette.json\", since writing in YAML is much more forgiving (and advanced users will know JSON is also supported)\r\n\r\nAlso, maybe this is a chance to consolidate the docs a bit? I think \"Settings\", \"Configuration\", \"Metadata\", and \"Authentication and permissions\" should possibly be under the same section. Maybe even consolidate the different Plugin pages that exist?\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1891212159, "label": "`datasette.yaml` plugin support"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/594#issuecomment-1714920708", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/594", "id": 1714920708, "node_id": "IC_kwDOCGYnMM5mN50E", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-12T03:51:13Z", "updated_at": "2023-09-12T03:51:13Z", "author_association": "OWNER", "body": "Changing this without breaking backwards compatibility (and forcing a 4.0 release) will be tricky, because `ForeignKey()` is a `namedtuple`:\r\n\r\nhttps://github.com/simonw/sqlite-utils/blob/622c3a5a7dd53a09c029e2af40c2643fe7579340/sqlite_utils/db.py#L148-L150\r\n\r\nI could swap it out for a `dataclass` and add those extra columns, but I need to make sure that code like this still works:\r\n```python\r\nfor table, column, other_table, other_column in table.foreign_keys:\r\n # ...\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1891614971, "label": "Represent compound foreign keys in table.foreign_keys output"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/594#issuecomment-1714919806", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/594", "id": 1714919806, "node_id": "IC_kwDOCGYnMM5mN5l-", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-12T03:49:41Z", "updated_at": "2023-09-12T03:49:41Z", "author_association": "OWNER", "body": "Digging in a bit more:\r\n```pycon\r\n>>> pprint(list(db.query('PRAGMA foreign_key_list(courses)')))\r\n[{'from': 'campus_name',\r\n 'id': 0,\r\n 'match': 'NONE',\r\n 'on_delete': 'NO ACTION',\r\n 'on_update': 'NO ACTION',\r\n 'seq': 0,\r\n 'table': 'departments',\r\n 'to': 'campus_name'},\r\n {'from': 'dept_code',\r\n 'id': 0,\r\n 'match': 'NONE',\r\n 'on_delete': 'NO ACTION',\r\n 'on_update': 'NO ACTION',\r\n 'seq': 1,\r\n 'table': 'departments',\r\n 'to': 'dept_code'}]\r\n```\r\nI think the way you tell it's a compound foreign key is that both of those have the same `id` value - of `0` - but they then have two different `seq` values of `0` and `1`.\r\n\r\nRight now I ignore those columns entirely: https://github.com/simonw/sqlite-utils/blob/622c3a5a7dd53a09c029e2af40c2643fe7579340/sqlite_utils/db.py#L1523-L1540", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1891614971, "label": "Represent compound foreign keys in table.foreign_keys output"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/pull/2183#issuecomment-1714699724", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2183", "id": 1714699724, "node_id": "IC_kwDOBm6k_c5mND3M", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-11T23:01:36Z", "updated_at": "2023-09-11T23:02:30Z", "author_association": "OWNER", "body": "On thinking about this further, I'm fine releasing it as another alpha provided it causes Datasette to error loudly with an explanatory message if you attempt to load `-m metadata.json` at a metadata file that includes `\"plugins\"` configuration.\r\n\r\nSomething like this:\r\n```bash\r\ndatasette -m metadata.json\r\n```\r\nOutputs:\r\n\r\n> Datasette no longer accepts plugin configuration in --metadata. Move your `\"plugins\"` configuration blocks to a separate file - we suggest calling that `datasette.yaml` - and start Datasette with `datasette -c datasette.yaml`.\r\n\r\nFor added usability points, let's have it suggest `datasette.json` if they used `metadata.json` and `datasette.yaml` if they tried to use `metadata.yaml`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1891212159, "label": "`datasette.yaml` plugin support"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/2168#issuecomment-1712897194", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/2168", "id": 1712897194, "node_id": "IC_kwDOBm6k_c5mGLyq", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-09-10T17:54:07Z", "updated_at": "2023-09-10T17:54:07Z", "author_association": "OWNER", "body": "This looks relevant:\r\n\r\nhttps://pluggy.readthedocs.io/en/stable/#wrappers\r\n\r\n> A *hookimpl* can be marked with the `\"wrapper\"` option, which indicates that the function will be called to *wrap* (or surround) all other normal *hookimpl* calls. A *hook wrapper* can thus execute some code ahead and after the execution of all corresponding non-wrappper *hookimpls*.\r\n\r\nThis could be the perfect mechanism for implementing this hook, although I still need to figure out how it interacts with streaming.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1876353656, "label": "Consider a request/response wrapping hook slightly higher level than asgi_wrapper()"}, "performed_via_github_app": null}