{"id": 1174404647, "node_id": "I_kwDOBm6k_c5F__4n", "number": 1669, "title": "Release 0.61 alpha", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-03-20T00:35:35Z", "updated_at": "2022-03-20T01:24:36Z", "closed_at": "2022-03-20T01:24:36Z", "author_association": "OWNER", "pull_request": null, "body": "> I'm going to release this as a 0.61 alpha so I can more easily depend on it from `datasette-hashed-urls`.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1668#issuecomment-1073136896_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1669/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1174306154, "node_id": "I_kwDOBm6k_c5F_n1q", "number": 1668, "title": "Introduce concept of a database `route`, separate from its name", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 20, "created_at": "2022-03-19T16:48:28Z", "updated_at": "2022-03-20T16:43:16Z", "closed_at": "2022-03-20T16:43:16Z", "author_association": "OWNER", "pull_request": null, "body": "Some issues came up in the new `datasette-hashed-urls` plugin relating to the way it renames databases on startup to achieve unique URLs that depend on the database SHA-256 content:\r\n\r\n- https://github.com/simonw/datasette-hashed-urls/issues/10\r\n- https://github.com/simonw/datasette-hashed-urls/issues/9\r\n- https://github.com/simonw/datasette-hashed-urls/issues/8\r\n\r\nAll three of these could be addressed by making the \"path\" concept for a database (the `/foo` bit where it is served) work independently of the database's name, which would be used for default display and also as the alias when configuring cross-database aliases.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1668/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1174302994, "node_id": "I_kwDOBm6k_c5F_nES", "number": 1667, "title": "Make route matched pattern groups more consistent", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 3, "created_at": "2022-03-19T16:32:35Z", "updated_at": "2022-03-19T20:37:42Z", "closed_at": "2022-03-19T20:37:41Z", "author_association": "OWNER", "pull_request": null, "body": "> ... highlights how inconsistent the way the capturing works is. Especially `as_format` which can be `None` or `\"\"` or `.json` or `json` or not used at all in the case of `TableView`.\r\n\r\nhttps://github.com/simonw/datasette/blob/764738dfcb16cd98b0987d443f59d5baa9d3c332/tests/test_routes.py#L12-L36\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1666#issuecomment-1073039670_\r\n\r\nPart of:\r\n- #1660", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1667/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1168995756, "node_id": "I_kwDOBm6k_c5FrXWs", "number": 1657, "title": "Tilde encoding: use ~ instead of - for dash-encoding", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 12, "created_at": "2022-03-14T22:55:17Z", "updated_at": "2022-03-15T18:25:11Z", "closed_at": "2022-03-15T18:01:58Z", "author_association": "OWNER", "pull_request": null, "body": "Refs #1439", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1657/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1169840669, "node_id": "I_kwDOBm6k_c5Fulod", "number": 1658, "title": "Revert main to version that passes tests", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2022-03-15T15:37:02Z", "updated_at": "2022-03-19T04:04:50Z", "closed_at": "2022-03-15T15:42:58Z", "author_association": "OWNER", "pull_request": null, "body": "> I've made a real mess of this. I'm going to revert Datasette`main` back to the last commit that passed the tests and try this again in a branch.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1657#issuecomment-1068125636_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1658/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1170144879, "node_id": "I_kwDOBm6k_c5Fvv5v", "number": 1660, "title": "Refactor and simplify Datasette routing and views", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 8, "created_at": "2022-03-15T19:56:56Z", "updated_at": "2022-03-21T19:19:12Z", "closed_at": "2022-03-21T19:19:01Z", "author_association": "OWNER", "pull_request": null, "body": "While working on:\n- https://github.com/simonw/datasette/issues/1657\n- https://github.com/simonw/datasette/issues/1439\n\nIt became very clear that the least maintainable part of Datasette at the moment is the way routing to the database, table and row views work - in particular the subclassing mechanism with BaseView and DataView, but also the complex variety of ways in which the URL routes capture different named regular expression groups.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1660/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1170355774, "node_id": "I_kwDOBm6k_c5FwjY-", "number": 1661, "title": "Remove Hashed URL mode", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 10, "created_at": "2022-03-15T23:13:56Z", "updated_at": "2022-03-19T00:37:37Z", "closed_at": "2022-03-19T00:37:36Z", "author_association": "OWNER", "pull_request": null, "body": "It's now handled by a plugin instead:\r\n- #647\r\n- https://github.com/simonw/datasette-hashed-urls/issues/3\r\n\r\nhttps://github.com/simonw/datasette-hashed-urls\r\n\r\nSub-tasks:\r\n\r\n- [x] Remove hashed URL mode implementation\r\n- [x] Update documentation\r\n- [x] Ensure `--setting hash_urls 1` shows a useful message", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1661/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1170554975, "node_id": "I_kwDOBm6k_c5FxUBf", "number": 1663, "title": "Document the internals that were used in datasette-hashed-urls", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 2, "created_at": "2022-03-16T05:17:08Z", "updated_at": "2022-03-19T04:04:50Z", "closed_at": "2022-03-17T21:32:38Z", "author_association": "OWNER", "pull_request": null, "body": "The https://github.com/simonw/datasette-hashed-urls used a couple of currently undocumented features:\r\n- `db.hash`\r\n- `Datasette(..., immutables=[...])`", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1663/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1190828163, "node_id": "I_kwDOBm6k_c5G-piD", "number": 1698, "title": "Add a warning about bots and Cloud Run", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-04-03T05:57:17Z", "updated_at": "2022-04-03T06:10:24Z", "closed_at": "2022-04-03T06:10:24Z", "author_association": "OWNER", "pull_request": null, "body": "Recommend the https://github.com/simonw/datasette-block-robots plugin if you are going to run a large database in Cloud Run (one with a lot of rows).", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1698/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1189113609, "node_id": "I_kwDOBm6k_c5G4G8J", "number": 1697, "title": "`Request.fake(..., url_vars={})`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2022-04-01T01:48:40Z", "updated_at": "2022-04-01T02:02:18Z", "closed_at": "2022-04-01T02:02:10Z", "author_association": "OWNER", "pull_request": null, "body": "I just created an alternative `.fake()` method because I wanted to fake the `url_vars` captured in the route as well:\r\n```python\r\nfrom datasette.utils.asgi import Request\r\nclass Request(Request):\r\n\r\n @classmethod\r\n def fake(cls, path_with_query_string, method=\"GET\", scheme=\"http\", url_vars=None):\r\n \"\"\"Useful for constructing Request objects for tests\"\"\"\r\n path, _, query_string = path_with_query_string.partition(\"?\")\r\n scope = {\r\n \"http_version\": \"1.1\",\r\n \"method\": method,\r\n \"path\": path,\r\n \"raw_path\": path_with_query_string.encode(\"latin-1\"),\r\n \"query_string\": query_string.encode(\"latin-1\"),\r\n \"scheme\": scheme,\r\n \"type\": \"http\",\r\n }\r\n if url_vars:\r\n scope[\"url_route\"] = {\r\n \"kwargs\": url_vars\r\n }\r\n return cls(scope, None)\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1697/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1174423568, "node_id": "I_kwDOBm6k_c5GAEgQ", "number": 1670, "title": "Ship Datasette 0.61", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2022-03-20T02:47:54Z", "updated_at": "2022-03-23T18:32:32Z", "closed_at": "2022-03-23T18:32:03Z", "author_association": "OWNER", "pull_request": null, "body": "Let the alpha bake for a while, since #1668 is a big last-minute change.\r\n\r\nAfter shipping, release a new `datasette-hashed-urls` that depends on it, also this:\r\n\r\n- https://github.com/simonw/datasette-hashed-urls/issues/11", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1670/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1174697144, "node_id": "I_kwDOBm6k_c5GBHS4", "number": 1672, "title": "Refactor CSV handling code out of DataView", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2022-03-20T21:47:00Z", "updated_at": "2022-03-20T21:52:39Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> I think the way to get rid of most of the remaining complexity in `DataView` is to refactor how CSV stuff works - pulling it in line with other export factors and extracting the streaming mechanism. Opening a fresh issue for that.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1660#issuecomment-1073355032_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1672/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1174708375, "node_id": "I_kwDOBm6k_c5GBKCX", "number": 1673, "title": "Streaming CSV spends a lot of time in `table_column_details`", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-03-20T22:25:28Z", "updated_at": "2022-03-20T22:34:06Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "At least I think it does. I tried running `py-spy top -p $PID` against a Datasette process that was trying to do:\r\n\r\n datasette covid.db --get '/covid/ny_times_us_counties.csv?_size=10&_stream=on'\r\n\r\nWhile investigating:\r\n- #1355\r\n\r\nAnd spotted this:\r\n```\r\ndatasette covid.db --get /covid/ny_times_us_counties.csv?_size=10&_stream=on' (python v3.10.2)\r\nTotal Samples 5800\r\nGIL: 71.00%, Active: 98.00%, Threads: 4\r\n\r\n %Own %Total OwnTime TotalTime Function (filename:line) \r\n 8.00% 8.00% 4.32s 4.38s sql_operation_in_thread (datasette/database.py:212)\r\n 5.00% 5.00% 3.77s 3.93s table_column_details (datasette/utils/__init__.py:614)\r\n 6.00% 6.00% 3.72s 3.72s _worker (concurrent/futures/thread.py:81)\r\n 7.00% 7.00% 2.98s 2.98s _read_from_self (asyncio/selector_events.py:120)\r\n 5.00% 6.00% 2.35s 2.49s detect_fts (datasette/utils/__init__.py:571)\r\n 4.00% 4.00% 1.34s 1.34s _write_to_self (asyncio/selector_events.py:140)\r\n```\r\nRelevant code: https://github.com/simonw/datasette/blob/798f075ef9b98819fdb564f9f79c78975a0f71e8/datasette/utils/__init__.py#L609-L625\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1673/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1174717287, "node_id": "I_kwDOBm6k_c5GBMNn", "number": 1674, "title": "Tweak design of /.json", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2022-03-20T22:58:01Z", "updated_at": "2022-03-20T22:58:40Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://latest.datasette.io/.json\r\n\r\nCurrently:\r\n```json\r\n{\r\n \"_memory\": {\r\n \"name\": \"_memory\",\r\n \"hash\": null,\r\n \"color\": \"a6c7b9\",\r\n \"path\": \"/_memory\",\r\n \"tables_and_views_truncated\": [],\r\n \"tables_and_views_more\": false,\r\n \"tables_count\": 0,\r\n \"table_rows_sum\": 0,\r\n \"show_table_row_counts\": false,\r\n \"hidden_table_rows_sum\": 0,\r\n \"hidden_tables_count\": 0,\r\n \"views_count\": 0,\r\n \"private\": false\r\n },\r\n \"fixtures\": {\r\n \"name\": \"fixtures\",\r\n \"hash\": \"645005884646eb941c89997fbd1c0dd6be517cb1b493df9816ae497c0c5afbaa\",\r\n \"color\": \"645005\",\r\n \"path\": \"/fixtures\",\r\n \"tables_and_views_truncated\": [\r\n {\r\n \"name\": \"compound_three_primary_keys\",\r\n \"columns\": [\r\n \"pk1\",\r\n \"pk2\",\r\n \"pk3\",\r\n \"content\"\r\n ],\r\n \"primary_keys\": [\r\n \"pk1\",\r\n \"pk2\",\r\n \"pk3\"\r\n ],\r\n \"count\": 1001,\r\n \"hidden\": false,\r\n \"fts_table\": null,\r\n \"num_relationships_for_sorting\": 0,\r\n \"private\": false\r\n },\r\n```\r\nAs-of this issue the `\"path\"` key is confusing, it doesn't match what https://latest.datasette.io/-/databases returns:\r\n\r\n- #1668", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1674/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1175690070, "node_id": "I_kwDOBm6k_c5GE5tW", "number": 1676, "title": "Reconsider ensure_permissions() logic, can it be less confusing?", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 3, "created_at": "2022-03-21T17:14:57Z", "updated_at": "2022-12-02T01:23:40Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> Updated documentation: https://github.com/simonw/datasette/blob/e627510b760198ccedba9e5af47a771e847785c9/docs/internals.rst#await-ensure_permissionsactor-permissions\r\n>\r\n>> This method allows multiple permissions to be checked at onced. It raises a `datasette.Forbidden` exception if any of the checks are denied before one of them is explicitly granted.\r\n>> \r\n>> This is useful when you need to check multiple permissions at once. For example, an actor should be able to view a table if either one of the following checks returns `True` or not a single one of them returns `False`:\r\n>\r\n> That's pretty hard to understand! I'm going to open a separate issue to reconsider if this is a useful enough abstraction given how confusing it is.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1675#issuecomment-1074177827_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1676/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1175694248, "node_id": "I_kwDOBm6k_c5GE6uo", "number": 1677, "title": "Remove `check_permission()` from `BaseView`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2022-03-21T17:18:18Z", "updated_at": "2022-03-21T18:45:04Z", "closed_at": "2022-03-21T18:45:03Z", "author_association": "OWNER", "pull_request": null, "body": "Follow-on from:\r\n- #1675\r\n\r\nRefs:\r\n- #1660", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1677/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1175648453, "node_id": "I_kwDOBm6k_c5GEvjF", "number": 1675, "title": "Extract out `check_permissions()` from `BaseView", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 7, "created_at": "2022-03-21T16:39:46Z", "updated_at": "2022-03-21T17:14:31Z", "closed_at": "2022-03-21T17:13:21Z", "author_association": "OWNER", "pull_request": null, "body": "> I'm going to refactor this stuff out and document it so it can be easily used by plugins:\r\n\r\nhttps://github.com/simonw/datasette/blob/4a4164b81191dec35e423486a208b05a9edc65e4/datasette/views/base.py#L69-L103\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1660#issuecomment-1074136176_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1675/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1175715988, "node_id": "I_kwDOBm6k_c5GFACU", "number": 1678, "title": "Make `check_visibility()` a documented API", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2022-03-21T17:30:34Z", "updated_at": "2022-03-21T19:04:03Z", "closed_at": "2022-03-21T19:01:46Z", "author_association": "OWNER", "pull_request": null, "body": "Spotted this while working on:\r\n- #1677\r\n\r\nhttps://github.com/simonw/datasette/blob/e627510b760198ccedba9e5af47a771e847785c9/datasette/utils/__init__.py#L1005-L1021", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1678/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1175854982, "node_id": "I_kwDOBm6k_c5GFh-G", "number": 1679, "title": "Research: how much overhead does the n=1 time limit have?", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 11, "created_at": "2022-03-21T19:27:46Z", "updated_at": "2022-03-21T21:55:57Z", "closed_at": "2022-03-21T21:55:56Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/simonw/datasette/blob/1a7750eb29fd15dd2eea3b9f6e33028ce441b143/datasette/utils/__init__.py#L181-L200\r\n\r\n```python\r\n@contextmanager\r\ndef sqlite_timelimit(conn, ms):\r\n deadline = time.perf_counter() + (ms / 1000)\r\n # n is the number of SQLite virtual machine instructions that will be\r\n # executed between each check. It's hard to know what to pick here.\r\n # After some experimentation, I've decided to go with 1000 by default and\r\n # 1 for time limits that are less than 50ms\r\n n = 1000\r\n if ms < 50:\r\n n = 1\r\n\r\n def handler():\r\n if time.perf_counter() >= deadline:\r\n return 1\r\n\r\n conn.set_progress_handler(handler, n)\r\n try:\r\n yield\r\n finally:\r\n conn.set_progress_handler(None, n)\r\n```\r\nHow often do I set a time limit of 50 or less? How much slower does it go thanks to this code?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1679/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1175894898, "node_id": "I_kwDOBm6k_c5GFrty", "number": 1680, "title": "Consider simplifying permissions for 1.0", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 0, "created_at": "2022-03-21T20:17:29Z", "updated_at": "2022-03-21T20:17:29Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Permission checks right now can express one of three opinions:\r\n\r\n- `False` means \"so not grant this permisson\"\r\n- `True` means \"grant this permission\"\r\n- `None` means \"I have no opinion\"\r\n\r\nBut... there's also a concept of a \"default\" for a given permission check, which might be `False` or `True`.\r\n\r\nI worry this is too complicated. Could this be simplified before 1.0? In particular the default concept.\r\n\r\nSee also:\r\n- #1676 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1680/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1177101697, "node_id": "I_kwDOBm6k_c5GKSWB", "number": 1681, "title": "Potential bug in numeric handling where_clause for filters", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-03-22T17:43:50Z", "updated_at": "2022-03-22T17:49:09Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> Note that Datasette does already have special logic to convert parameters to integers for numeric comparisons like `>`:\r\n>\r\n> https://github.com/simonw/datasette/blob/c4c9dbd0386e46d2bf199f0ed34e4895c98cb78c/datasette/filters.py#L203-L212\r\n> \r\n> Though... it looks like there's a bug in that? It doesn't account for `float` values - `\"3.5\".isdigit()` return `False` - probably for the best, because `int(3.5)` would break that value anyway.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1671#issuecomment-1075432283_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1681/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1178521513, "node_id": "I_kwDOBm6k_c5GPs-p", "number": 1682, "title": "SQL queries against databases with different routes are broken", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-03-23T18:42:57Z", "updated_at": "2022-03-23T18:48:16Z", "closed_at": "2022-03-23T18:48:16Z", "author_association": "OWNER", "pull_request": null, "body": "500 error on https://datasette-hashed-urls-preview.vercel.app/fixtures-09f8f95?sql=select+*+from+facetable\r\n\r\nHere's the trace:\r\n```\r\n File \"/Users/simon/.local/share/virtualenvs/datasette-hashed-urls-ssI2fO50/lib/python3.10/site-packages/datasette/views/database.py\", line 54, in data\r\n return await QueryView(self.ds).data(\r\n File \"/Users/simon/.local/share/virtualenvs/datasette-hashed-urls-ssI2fO50/lib/python3.10/site-packages/datasette/views/database.py\", line 232, in data\r\n self.ds.get_database(database), sql\r\n File \"/Users/simon/.local/share/virtualenvs/datasette-hashed-urls-ssI2fO50/lib/python3.10/site-packages/datasette/app.py\", line 401, in get_database\r\n return self.databases[name]\r\nKeyError: 'fixtures-aa7318b'\r\n```\r\nIt looks like this is a Datasette bug, which is frustrating because I just shipped Datasette 0.61 five minutes ago!\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette-hashed-urls/issues/13#issuecomment-1076693667_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1682/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1179928510, "node_id": "I_kwDOBm6k_c5GVEe-", "number": 1683, "title": "allow_facet: False should be respected by column cog menu", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-03-24T19:05:06Z", "updated_at": "2022-03-24T19:16:36Z", "closed_at": "2022-03-24T19:16:36Z", "author_association": "OWNER", "pull_request": null, "body": "The column cog menu currently shows \"Facet by this\" even if faceting is disabled for the Datasette instance.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1683/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1179998071, "node_id": "I_kwDOBm6k_c5GVVd3", "number": 1684, "title": "Mechanism for disabling faceting on large tables only", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-03-24T20:06:11Z", "updated_at": "2022-03-24T20:13:19Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Forest turned off faceting on https://labordata.bunkum.us/ because it was causing performance problems on some of the huge tables - but it would be nice if it could still be an option on smaller tables such as https://labordata.bunkum.us/voluntary_recognitions-4421085/voluntary_recognitions\r\n\r\nOne option: a new setting that automatically disables faceting (and facet suggestion) for tables that have either more than X rows or that are so big that the count could not be completed within the time limit.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1684/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1181364043, "node_id": "I_kwDOBm6k_c5Gai9L", "number": 1687, "title": "Make show_json.html or a similar mechanism stable for plugins", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-03-25T23:42:45Z", "updated_at": "2022-03-25T23:42:45Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I used `show_json.html` in the new `datasette-packages` plugin, which means it will break if that template changes:\r\n- https://github.com/simonw/datasette-packages/issues/3\r\n\r\nIt would be useful if it (or something like it) was documented and stable for plugins to use.\r\n\r\nAlso relevant:\r\n- #878", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1687/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1182065616, "node_id": "I_kwDOBm6k_c5GdOPQ", "number": 1689, "title": "datasette.add_message() documentation is incorrect", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-03-26T20:49:42Z", "updated_at": "2022-03-26T21:35:57Z", "closed_at": "2022-03-26T20:51:21Z", "author_association": "OWNER", "pull_request": null, "body": "https://docs.datasette.io/en/0.61.1/internals.html#add-message-request-message-message-type-datasette-info says:\r\n\r\n`.add_message(request, message, message_type=datasette.INFO)`\r\n\r\nBut in the code it's:\r\n\r\nhttps://github.com/simonw/datasette/blob/6b99e4a66ba0ed8fca8ee41ceb7206928b60d5d1/datasette/app.py#L582", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1689/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1182141761, "node_id": "I_kwDOBm6k_c5Gdg1B", "number": 1690, "title": "Idea: `datasette.set_actor_cookie(response, actor)`", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-03-26T22:41:52Z", "updated_at": "2022-03-26T22:43:00Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I just wrote this code in a plugin and it felt like it could benefit from an abstraction: https://github.com/simonw/datasette-auth0/blob/152e6eb21e96e9b73bd9c205f9749a1297d0ef0b/datasette_auth0/__init__.py#L79-L92\r\n\r\n```python\r\n redirect_response = Response.redirect(\"/\")\r\n expires_at = int(time.time()) + (24 * 60 * 60)\r\n redirect_response.set_cookie(\r\n \"ds_actor\",\r\n datasette.sign(\r\n {\r\n \"a\": profile_response.json(),\r\n \"e\": baseconv.base62.encode(expires_at),\r\n },\r\n \"actor\",\r\n ),\r\n )\r\n return redirect_response\r\n```\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1690/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1182143895, "node_id": "I_kwDOBm6k_c5GdhWX", "number": 1691, "title": "Bug in pytest-httpx example", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-03-26T22:45:30Z", "updated_at": "2022-03-26T22:46:09Z", "closed_at": "2022-03-26T22:46:09Z", "author_association": "OWNER", "pull_request": null, "body": "https://docs.datasette.io/en/0.61.1/testing_plugins.html#testing-outbound-http-calls-with-pytest-httpx says:\r\n\r\n```python\r\nasync def test_outbound_http_call(httpx_mock):\r\n httpx_mock.add_response(\r\n url='https://www.example.com/',\r\n data='Hello world',\r\n )\r\n```\r\nThat's wrong - `data=` should be `text=`.\r\n\r\nhttps://github.com/Colin-b/pytest_httpx/blob/v0.20.0/README.md#reply-with-custom-body", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1691/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1185868354, "node_id": "I_kwDOBm6k_c5GrupC", "number": 1695, "title": "Option to un-filter facet not shown for `?col__exact=value`", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-03-30T04:44:02Z", "updated_at": "2022-03-30T04:46:18Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Spotted this on a page with `COUNTY__exact=Lee` in the URL:\r\n\r\n![CleanShot 2022-03-29 at 21 41 46@2x](https://user-images.githubusercontent.com/9599/160752849-a9039343-3770-4655-920b-f19e25687a57.png)\r\n\r\nWith `COUNTY=Lee` you get this instead:\r\n\r\n\"image\"\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1695/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1186696202, "node_id": "I_kwDOBm6k_c5Gu4wK", "number": 1696, "title": "Show foreign key label when filtering", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-03-30T16:18:54Z", "updated_at": "2023-01-29T20:56:20Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "For example here:\r\n\r\n\"image\"\r\n\r\n3 corresponds to \"Human Related: Other\" - it would be neat to display this in this area of the page somehow.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1696/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1194790504, "node_id": "I_kwDOBm6k_c5HNw5o", "number": 1701, "title": "Use + for spaces instead of ~20", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 0, "created_at": "2022-04-06T15:40:48Z", "updated_at": "2022-04-06T15:55:10Z", "closed_at": "2022-04-06T15:55:05Z", "author_association": "OWNER", "pull_request": null, "body": "Tilde encoding introduced in #1657 means that database files with spaces in the name - e.g. the Apple Mail `Envelope Index` database - end up with URLs like this:\r\n\r\n http://127.0.0.1:8001/Envelope~20Index\r\n\r\nI think this would be prettier:\r\n\r\n http://127.0.0.1:9933/Envelope+Index", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1701/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1196327155, "node_id": "I_kwDOBm6k_c5HToDz", "number": 1702, "title": "Be more consistent with column quoting", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-04-07T16:59:20Z", "updated_at": "2022-04-07T16:59:20Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This tutorial made me notice that Datasette is pretty inconsistent with how column quoting works: https://datasette.io/tutorials/learn-sql\r\n\r\nIt has examples of each of `\"table_name\"` and `[table_name]` and `table_name`, and it uses single quoted values too.\r\n\r\nDatasette should generate SQL as consistently as possible to support learners.\r\n\r\nThat tutorial should also provide a tiny bit of extra information about what's going on here.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1702/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1197925865, "node_id": "I_kwDOBm6k_c5HZuXp", "number": 1704, "title": "File PRs against incompatible plugins pinning to datasette<1.0", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 0, "created_at": "2022-04-08T23:15:30Z", "updated_at": "2022-04-08T23:15:30Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "As part of the preparation for the 1.0 release, test all existing known plugins against the alpha.\r\n\r\nFor any that break, submit a PR suggesting they pin to a version <1.0 - and include a link to the documentation on how to upgrade the plugin for 1.0.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1704/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1197926598, "node_id": "I_kwDOBm6k_c5HZujG", "number": 1705, "title": "How to upgrade your plugin for 1.0 documentation", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 1, "created_at": "2022-04-08T23:16:47Z", "updated_at": "2022-12-13T05:29:05Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Among other things, needed by:\r\n- #1704", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1705/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1200649124, "node_id": "I_kwDOBm6k_c5HkHOk", "number": 1708, "title": "Datasette 1.0 alpha upcoming release notes", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 2, "created_at": "2022-04-11T22:57:12Z", "updated_at": "2022-12-13T05:29:06Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I'm going to try writing the release notes first, to see if that helps unblock me.\r\n\r\n# \u26a0\ufe0f Any release notes in this issue are a draft, and should not be treated as the real thing \u26a0\ufe0f ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1708/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1200649502, "node_id": "I_kwDOBm6k_c5HkHUe", "number": 1709, "title": "Redesigned JSON API with ?_extra= parameters", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 1, "created_at": "2022-04-11T22:57:49Z", "updated_at": "2022-12-13T05:29:06Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This will be the single biggest breaking change for the 1.0 release.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1709/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1200649889, "node_id": "I_kwDOBm6k_c5HkHah", "number": 1710, "title": "Guide for plugin authors to upgrade their plugins for 1.0", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-04-11T22:58:25Z", "updated_at": "2022-04-11T23:04:01Z", "closed_at": "2022-04-11T23:03:25Z", "author_association": "OWNER", "pull_request": null, "body": "I'll also encourage testing against both Datasette 0.x and Datasette 1.0 using a GitHub Actions matrix.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1710/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1200650491, "node_id": "I_kwDOBm6k_c5HkHj7", "number": 1711, "title": "Template context powered entirely by the JSON API format", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 1, "created_at": "2022-04-11T22:59:27Z", "updated_at": "2022-12-13T05:29:06Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Datasette 1.0 will have a stable template context. I'm going to achieve this by refactoring the templates to work only with keys returned by the API (or some of its extras) - then the API documentation will double up as template documentation.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1711/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1202227104, "node_id": "I_kwDOBm6k_c5HqIeg", "number": 1712, "title": "Make \"\" easier to read", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2022-04-12T18:17:07Z", "updated_at": "2022-04-12T19:12:22Z", "closed_at": "2022-04-12T18:44:20Z", "author_association": "OWNER", "pull_request": null, "body": "`Binary: 2,427,344 bytes` would be nicer - even better, include a tooltip showing that size translated using this function: https://github.com/simonw/datasette/blob/138e4d9a53e3982137294ba383303c3a848cfca4/datasette/utils/__init__.py#L837-L846\r\n\r\n![CleanShot 2022-04-12 at 11 15 04@2x](https://user-images.githubusercontent.com/9599/163027324-b0b6092e-6e11-438b-8077-789025d0bb37.png)\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1712/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1203943272, "node_id": "I_kwDOBm6k_c5Hwrdo", "number": 1713, "title": "Datasette feature for publishing snapshots of query results", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2022-04-14T01:42:00Z", "updated_at": "2022-07-04T05:16:35Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://twitter.com/simonw/status/1514392335718645760\r\n\r\n> Maybe [@datasetteproj](https://twitter.com/datasetteproj) should grow a feature that lets you cache the results of a query and give that snapshot a stable permalink\r\n>\r\n> A plugin that publishes the JSON output of a query to an S3 bucket would be pretty neat... especially if it could also be configured to re-publish the results on a schedule\r\n\r\nA lot of people said they would find this useful.\r\n\r\nProbably going to build this as a plugin.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1713/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1223234932, "node_id": "I_kwDOBm6k_c5I6RV0", "number": 1733, "title": "Get Datasette compatible with Pyodide", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 9, "created_at": "2022-05-02T19:01:58Z", "updated_at": "2022-05-04T15:14:01Z", "closed_at": "2022-05-02T20:15:27Z", "author_association": "OWNER", "pull_request": null, "body": "I've already got this working as a prototype. Here are the changes I had to make:\r\n\r\n- Replace the two dependencies that don't publish pure Python wheels to PyPI: `click-default-group` and `python-baseconv`\r\n- Get Datasette to work without threading - which it turns out is exclusively used for database connections\r\n- Make the `uvicorn` dependency optional (only needed when Datasette runs in the CLI)\r\n\r\nTODO:\r\n\r\n- [x] Switch to `click-default-group-wheel`\r\n- [x] https://github.com/simonw/datasette/issues/1734\r\n- [x] Work around `uvicorn` import error\r\n- [x] https://github.com/simonw/datasette/issues/1735\r\n- [x] #1737\r\n\r\nGoal is to be able to do the following directly in https://pyodide.org/en/stable/console.html\r\n\r\n```python\r\nimport micropip\r\nawait micropip.install(\"datasette\")\r\nfrom datasette.app import Datasette\r\nds = Datasette()\r\nawait ds.client.get(\"/.json\")\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1733/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1223241647, "node_id": "I_kwDOBm6k_c5I6S-v", "number": 1734, "title": "Remove python-baseconv dependency", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2022-05-02T19:08:37Z", "updated_at": "2022-05-02T23:25:49Z", "closed_at": "2022-05-02T19:39:20Z", "author_association": "OWNER", "pull_request": null, "body": "> I was going to vendor `baseconv.py`, but then I reconsidered - what if there are plugins out there that expect `import baseconv` to work because they have depended on Datasette?\r\n>\r\n> I used https://cs.github.com/ and as far as I can tell there aren't any!\r\n>\r\n> So I'm going to remove that dependency and work out a smarter way to do this - probably by providing a utility function within Datasette itself.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1733#issuecomment-1115258737_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1734/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1223263540, "node_id": "I_kwDOBm6k_c5I6YU0", "number": 1735, "title": "Datasette setting to disable threading (for Pyodide)", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-05-02T19:31:08Z", "updated_at": "2022-05-02T23:25:49Z", "closed_at": "2022-05-02T20:13:52Z", "author_association": "OWNER", "pull_request": null, "body": "> I'm going to add a Datasette setting to disable threading entirely, designed for usage in this particular case.\r\n>\r\n> I thought about adding a new setting, then I noticed this:\r\n>\r\n> datasette mydatabase.db --setting num_sql_threads 10\r\n>\r\n> I'm going to let users set that to `0` to disable threaded execution of SQL queries.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1733#issuecomment-1115278325_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1735/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1223459734, "node_id": "I_kwDOBm6k_c5I7IOW", "number": 1737, "title": "Automated test for Pyodide compatibility", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-05-02T23:24:25Z", "updated_at": "2022-05-02T23:40:50Z", "closed_at": "2022-05-02T23:40:50Z", "author_association": "OWNER", "pull_request": null, "body": "Refs:\r\n- #1733\r\n\r\nNeed something in the test suite such that if Datasette breaks against Pyodide in the future we hear about it.\r\n\r\nI'm thinking this is an opportunity to use [shot-scraper javascript](https://github.com/simonw/shot-scraper#scraping-pages-using-javascript).", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1737/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1223527226, "node_id": "I_kwDOBm6k_c5I7Ys6", "number": 1738, "title": "\"Cannot use _sort and _sort_desc at the same time\"", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8303187, "label": "Datasette 0.62"}, "comments": 2, "created_at": "2022-05-03T01:06:24Z", "updated_at": "2022-08-14T16:13:55Z", "closed_at": "2022-08-14T16:13:55Z", "author_association": "OWNER", "pull_request": null, "body": "Triggered this error while playing with the sort desc checkbox and the apply button that are only visible on this page at mobile screen width:\r\n\r\nhttps://latest.datasette.io/fixtures/compound_three_primary_keys?_sort_desc=pk1\r\n\r\nNavigate to that page (with the browser narrow enough to show the box), un-check the box and click Apply:\r\n\r\n![sort-bug](https://user-images.githubusercontent.com/9599/166390804-cb289b29-63dc-4986-b7f9-81cf2ae04914.gif)\r\n\r\nAlso notable: I managed to get to a page with `?_sort_desk=pk1` in the URL three times by clicking around with that button.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1738/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1223699280, "node_id": "I_kwDOBm6k_c5I8CtQ", "number": 1739, "title": ".db downloads should be served with an ETag", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2022-05-03T05:11:21Z", "updated_at": "2022-05-04T18:21:18Z", "closed_at": "2022-05-03T14:59:51Z", "author_association": "OWNER", "pull_request": null, "body": "I noticed that my Pyodide Datasette prototype is downloading the same database file every single time rather than browser caching it:\r\n\r\n![image](https://user-images.githubusercontent.com/9599/166407074-dee19587-0667-4424-9e88-d3b5b90fd819.png)\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1739/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1212823665, "node_id": "I_kwDOBm6k_c5ISjhx", "number": 1715, "title": "Refactor TableView to use asyncinject", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 13, "created_at": "2022-04-22T21:43:39Z", "updated_at": "2022-12-01T21:15:18Z", "closed_at": "2022-04-28T22:26:56Z", "author_association": "OWNER", "pull_request": null, "body": "I've been working on a dependency injection mechanism in a separate library:\r\n\r\n- https://github.com/simonw/asyncinject\r\n\r\nI think it's ready to try out with Datasette to see if it's a pattern that will work here.\r\n\r\nI'm going to attempt to refactor `TableView` to use it. There are two overall goals here:\r\n\r\n- Use `asyncinject` to add parallel execution of some aspects of the table page - most notably I want to be able to execute the `count(*)` query, the `select ...` query, the various faceting queries and the facet suggestion queries in parallel - and measure if doing so is good for performance.\r\n- Use it to execute different output formats (possibly with some changes to the existing `register_output_renderer()` plugin hook). I want CSV and JSON to use the same mechanism that plugins use.\r\n\r\nStretch goal is to get this working with streaming data too, see:\r\n\r\n- #1101", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1715/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1212838949, "node_id": "I_kwDOBm6k_c5ISnQl", "number": 1716, "title": "Configure git blame to ignore Black commit", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-04-22T21:56:37Z", "updated_at": "2022-04-22T22:02:19Z", "closed_at": "2022-04-22T22:02:19Z", "author_association": "OWNER", "pull_request": null, "body": "GitHub can support this in blame views now too:\r\n\r\nhttps://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1716/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1213683988, "node_id": "I_kwDOBm6k_c5IV1kU", "number": 1718, "title": "Code examples in the documentation should be formatted with Black", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 12, "created_at": "2022-04-24T15:22:50Z", "updated_at": "2022-04-24T16:24:14Z", "closed_at": "2022-04-24T16:18:03Z", "author_association": "OWNER", "pull_request": null, "body": "For example on this page: https://docs.datasette.io/en/stable/writing_plugins.html#packaging-a-plugin\r\n\r\nI wonder if there's an easy way for me to enforce this for Sphinx documentation?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1718/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1214859703, "node_id": "I_kwDOBm6k_c5IaUm3", "number": 1719, "title": "Refactor `RowView` and remove `RowTableShared`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2022-04-25T18:06:24Z", "updated_at": "2022-12-01T21:15:19Z", "closed_at": "2022-04-25T18:33:44Z", "author_association": "OWNER", "pull_request": null, "body": "> The `RowTableShared` class is making this a whole lot more complicated.\r\n> \r\n> I'm going to split the `RowView` view out into an entirely separate `views/row.py` module.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1715#issuecomment-1108875068_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1719/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1215174094, "node_id": "I_kwDOBm6k_c5IbhXO", "number": 1720, "title": "Design plugin hook for extras", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 14, "created_at": "2022-04-26T00:08:10Z", "updated_at": "2022-12-01T21:15:19Z", "closed_at": "2022-04-26T20:20:27Z", "author_association": "OWNER", "pull_request": null, "body": "Refs:\r\n- #262\r\n- #1709\r\n\r\nI realized that this is a really natural plugin hook - and if I design it as a hook I can implement Datasette's core extras as default plugins.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1720/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1216436131, "node_id": "I_kwDOBm6k_c5IgVej", "number": 1721, "title": "Implement plugin hooks: `register_table_extras`, `register_row_extras`, `register_query_extras`", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 0, "created_at": "2022-04-26T20:21:49Z", "updated_at": "2022-12-13T05:29:07Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Designed in:\r\n- #1720\r\n\r\nPart of:\r\n- #262\r\n- #1709", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1721/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1216479167, "node_id": "I_kwDOBm6k_c5Igf-_", "number": 1722, "title": "`db.primary_keys()` and `db.table_columns()` don't show up in traces", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-04-26T21:08:36Z", "updated_at": "2022-04-26T21:08:36Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Noticed this while working on:\r\n- #1715\r\n\r\nThis code here isn't showing up in traces: https://github.com/simonw/datasette/blob/579f59dcec43a91dd7d404e00b87a00afd8515f2/datasette/views/table.py#L218-L220\r\n\r\nBecause those functions don't use the regular trace-instrumented `db.execute()` code path - they work directly against a connection instead: https://github.com/simonw/datasette/blob/579f59dcec43a91dd7d404e00b87a00afd8515f2/datasette/utils/__init__.py#L610-L626\r\n\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1722/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1216508080, "node_id": "I_kwDOBm6k_c5IgnCw", "number": 1723, "title": "Research running SQL in table view in parallel using `asyncio.gather()`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2022-04-26T21:42:48Z", "updated_at": "2022-04-27T18:53:44Z", "closed_at": "2022-04-26T22:19:09Z", "author_association": "OWNER", "pull_request": null, "body": "Spun off from:\r\n- #1715", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1723/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1216619276, "node_id": "I_kwDOBm6k_c5IhCMM", "number": 1724, "title": "?_trace=1 doesn't work on Global Power Plants demo", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2022-04-27T00:15:02Z", "updated_at": "2022-04-27T06:15:14Z", "closed_at": "2022-04-27T00:18:30Z", "author_association": "OWNER", "pull_request": null, "body": "https://global-power-plants.datasettes.com/global-power-plants/global-power-plants?_trace=1 is not showing the trace JSON at the bottom of the page.\r\n\r\nConfirmed that `trace_debug` is `true` on https://global-power-plants.datasettes.com/-/settings\r\n\r\nPossibly related:\r\n\r\n- https://github.com/simonw/datasette-total-page-time/issues/1", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1724/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1216622905, "node_id": "I_kwDOBm6k_c5IhDE5", "number": 1725, "title": "Performance question - what is happening in this gap?", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-04-27T00:21:11Z", "updated_at": "2022-04-27T00:21:11Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Trace from https://latest-with-plugins.datasette.io/github/commits?_facet=repo&_trace=1&_facet=committer\r\n\r\n![CleanShot 2022-04-26 at 17 20 06@2x](https://user-images.githubusercontent.com/9599/165413811-db2cd599-2acc-46ce-b9c2-f9bc45b879e9.png)\r\n\r\nWhat's going on in that gap? Can I improve the tracing output to show some non-SQL queries to figure that out?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1725/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1217014076, "node_id": "I_kwDOBm6k_c5Iiik8", "number": 1726, "title": "Security page in the documentation", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-04-27T08:43:30Z", "updated_at": "2022-04-27T08:43:30Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "A page talking about how to run Datasette securely, and security concerns to take into account.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1726/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1217759117, "node_id": "I_kwDOBm6k_c5IlYeN", "number": 1727, "title": "Research: demonstrate if parallel SQL queries are worthwhile", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 32, "created_at": "2022-04-27T18:54:21Z", "updated_at": "2022-09-26T14:48:31Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I added parallel SQL query execution here:\r\n- https://github.com/simonw/datasette/issues/1723\r\n\r\nMy hunch is that this will take advantage of multiple cores, since Python's `sqlite3` module releases the GIL once a query is passed to SQLite.\r\n\r\nI'd really like to prove this is the case though. Just not sure how to do it!\r\n\r\nLarger question: is this performance optimization actually improving performance at all? Under what circumstances is it worthwhile?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1727/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1219385669, "node_id": "I_kwDOBm6k_c5IrllF", "number": 1729, "title": "Implement ?_extra and new API design for TableView", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 12, "created_at": "2022-04-28T22:28:14Z", "updated_at": "2022-12-13T05:29:07Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Part of:\r\n- #262\r\n- #1518", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1729/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1219398983, "node_id": "I_kwDOBm6k_c5Iro1H", "number": 1730, "title": "SQL tracing should much more closely track the SQL query execution", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-04-28T22:41:04Z", "updated_at": "2022-04-28T22:41:10Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "In #1727 I realized that the SQL tracing was measuring a whole bunch of stuff outside of the SQL query itself.\r\n\r\nI started experimenting with this fix for that but it didn't work - I got back an empty JSON array of traces for some reason:\r\n\r\n```diff\r\ndiff --git a/datasette/database.py b/datasette/database.py\r\nindex ba594a8..d7f9172 100644\r\n--- a/datasette/database.py\r\n+++ b/datasette/database.py\r\n@@ -7,7 +7,7 @@ import sys\r\n import threading\r\n import uuid\r\n \r\n-from .tracer import trace\r\n+from .tracer import trace, trace_child_tasks\r\n from .utils import (\r\n detect_fts,\r\n detect_primary_keys,\r\n@@ -207,30 +207,31 @@ class Database:\r\n time_limit_ms = custom_time_limit\r\n \r\n with sqlite_timelimit(conn, time_limit_ms):\r\n- try:\r\n- cursor = conn.cursor()\r\n- cursor.execute(sql, params if params is not None else {})\r\n- max_returned_rows = self.ds.max_returned_rows\r\n- if max_returned_rows == page_size:\r\n- max_returned_rows += 1\r\n- if max_returned_rows and truncate:\r\n- rows = cursor.fetchmany(max_returned_rows + 1)\r\n- truncated = len(rows) > max_returned_rows\r\n- rows = rows[:max_returned_rows]\r\n- else:\r\n- rows = cursor.fetchall()\r\n- truncated = False\r\n- except (sqlite3.OperationalError, sqlite3.DatabaseError) as e:\r\n- if e.args == (\"interrupted\",):\r\n- raise QueryInterrupted(e, sql, params)\r\n- if log_sql_errors:\r\n- sys.stderr.write(\r\n- \"ERROR: conn={}, sql = {}, params = {}: {}\\n\".format(\r\n- conn, repr(sql), params, e\r\n+ with trace(\"sql\", database=self.name, sql=sql.strip(), params=params):\r\n+ try:\r\n+ cursor = conn.cursor()\r\n+ cursor.execute(sql, params if params is not None else {})\r\n+ max_returned_rows = self.ds.max_returned_rows\r\n+ if max_returned_rows == page_size:\r\n+ max_returned_rows += 1\r\n+ if max_returned_rows and truncate:\r\n+ rows = cursor.fetchmany(max_returned_rows + 1)\r\n+ truncated = len(rows) > max_returned_rows\r\n+ rows = rows[:max_returned_rows]\r\n+ else:\r\n+ rows = cursor.fetchall()\r\n+ truncated = False\r\n+ except (sqlite3.OperationalError, sqlite3.DatabaseError) as e:\r\n+ if e.args == (\"interrupted\",):\r\n+ raise QueryInterrupted(e, sql, params)\r\n+ if log_sql_errors:\r\n+ sys.stderr.write(\r\n+ \"ERROR: conn={}, sql = {}, params = {}: {}\\n\".format(\r\n+ conn, repr(sql), params, e\r\n+ )\r\n )\r\n- )\r\n- sys.stderr.flush()\r\n- raise\r\n+ sys.stderr.flush()\r\n+ raise\r\n \r\n if truncate:\r\n return Results(rows, truncated, cursor.description)\r\n@@ -238,9 +239,8 @@ class Database:\r\n else:\r\n return Results(rows, False, cursor.description)\r\n \r\n- with trace(\"sql\", database=self.name, sql=sql.strip(), params=params):\r\n- results = await self.execute_fn(sql_operation_in_thread)\r\n- return results\r\n+ with trace_child_tasks():\r\n+ return await self.execute_fn(sql_operation_in_thread)\r\n \r\n @property\r\n def size(self):\r\n```\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1727#issuecomment-1111602802_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1730/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1239008850, "node_id": "I_kwDOBm6k_c5J2cZS", "number": 1744, "title": "`--nolock` feature for opening locked databases", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 7, "created_at": "2022-05-17T18:25:16Z", "updated_at": "2022-05-17T19:46:38Z", "closed_at": "2022-05-17T19:40:30Z", "author_association": "OWNER", "pull_request": null, "body": "The getting started docs currently suggest you try this to browse your Chrome history:\r\n\r\n datasette ~/Library/Application\\ Support/Google/Chrome/Default/History\r\n\r\nBut if Chrome is running you will likely get this error:\r\n\r\n sqlite3.OperationalError: database is locked\r\n\r\nTurns out there's a workaround for this which I just spotted [on the SQLite forum](https://sqlite.org/forum/forumpost/86a67f6995):\r\n\r\n> You can do this using a [URI filename](https://sqlite.org/uri.html):\r\n> ```\r\n> sqlite3 'file:places.sqlite?mode=ro&nolock=1'\r\n> ```\r\n> That opens the file `places.sqlite` in read-only mode with locking disabled. This isn't safe, in that changes to the database made by other corrections are likely to cause this connection to return incorrect results or crash. Read-only mode should at least mean that you don't corrupt the database in the process.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1744/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1239080102, "node_id": "I_kwDOBm6k_c5J2tym", "number": 1745, "title": "Documentation on running cog", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-05-17T19:41:06Z", "updated_at": "2022-05-17T19:45:51Z", "closed_at": "2022-05-17T19:43:45Z", "author_association": "OWNER", "pull_request": null, "body": "Noticed that `cog -r docs/*.rst` isn't documented in https://docs.datasette.io/en/latest/contributing.html#editing-and-building-the-documentation", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1745/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1237586379, "node_id": "I_kwDOBm6k_c5JxBHL", "number": 1742, "title": "?_trace=1 fails with datasette-geojson for some reason", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-05-16T19:06:05Z", "updated_at": "2022-05-16T19:42:13Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "view-source:https://calands.datasettes.com/calands/CPAD_2020a_SuperUnits.geojson?_sort=id&id__exact=4&_labels=on&_trace=1 is showing me a blank page.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1742/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1237871948, "node_id": "I_kwDOBm6k_c5JyG1M", "number": 1743, "title": "`datasette.utils.to_css_class()` should be a documented internal", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-05-16T23:57:26Z", "updated_at": "2022-05-16T23:57:26Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Because I'm using it in this plugin:\r\n- https://github.com/simonw/datasette-upload-dbs/issues/1", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1743/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1243498298, "node_id": "I_kwDOBm6k_c5KHkc6", "number": 1746, "title": "Switch documentation theme to Furo", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 21, "created_at": "2022-05-20T18:42:17Z", "updated_at": "2022-05-20T21:28:29Z", "closed_at": "2022-05-20T21:28:29Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/pradyunsg/furo\r\n\r\nI just did this for `shot-scraper` and I really like it: https://shot-scraper.datasette.io/en/latest/\r\n\r\n- https://github.com/simonw/shot-scraper/issues/77", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1746/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1243512344, "node_id": "I_kwDOBm6k_c5KHn4Y", "number": 1747, "title": "Add tutorials to the getting started guide", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-05-20T19:01:52Z", "updated_at": "2022-05-20T19:12:30Z", "closed_at": "2022-05-20T19:05:34Z", "author_association": "OWNER", "pull_request": null, "body": "On https://docs.datasette.io/en/stable/getting_started.html", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1747/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1243517592, "node_id": "I_kwDOBm6k_c5KHpKY", "number": 1748, "title": "Add copy buttons next to code examples in the documentation", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-05-20T19:09:00Z", "updated_at": "2022-05-20T19:15:00Z", "closed_at": "2022-05-20T19:11:32Z", "author_association": "OWNER", "pull_request": null, "body": "Similar to the ones in `datasette-copyable` which are implemented here: https://github.com/executablebooks/sphinx-copybutton/tree/f84c001a0507f8ec46779d0701b079a265564583", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1748/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1251739062, "node_id": "I_kwDOBm6k_c5KnAW2", "number": 1752, "title": "Research if I can drop Janus", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-05-28T22:46:52Z", "updated_at": "2022-05-28T22:46:52Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> It seems to me Janus dependency is not necessary, `async with app.database_write_mutex(): out = await app.transaction(func)` may be enough.\r\n\r\nComment here: https://lobste.rs/s/fki4tj/architecture_notes_datasette#c_a2ihon", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1752/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1266329095, "node_id": "I_kwDOBm6k_c5LeqYH", "number": 1756, "title": "Mechanism for creating databases in WAL mode", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-06-09T15:39:28Z", "updated_at": "2022-06-09T15:39:28Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "The `--create` option currently creates databases if they are missing, but does not enable WAL mode for them.\r\n\r\nIt turns out WAL mode is useful for databases that are accepting writes!\r\n\r\nI think a `--create-wal` option that both creates them AND sets WAL mode on any that are created would be a good idea.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1756/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1306492437, "node_id": "I_kwDOBm6k_c5N334V", "number": 1770, "title": "`handle_exception` plugin hook for custom error handling", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8303187, "label": "Datasette 0.62"}, "comments": 14, "created_at": "2022-07-15T20:52:49Z", "updated_at": "2022-08-14T15:25:51Z", "closed_at": "2022-08-14T15:25:51Z", "author_association": "OWNER", "pull_request": null, "body": "I need this for a couple of plugins, both of which are broken at the moment:\r\n- https://github.com/simonw/datasette-sentry/issues/1\r\n- https://github.com/simonw/datasette-show-errors/issues/2", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1770/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1292370469, "node_id": "I_kwDOBm6k_c5NCAIl", "number": 1765, "title": "Document plugins providing new plugin hook-", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-07-03T17:05:14Z", "updated_at": "2023-08-31T23:08:24Z", "closed_at": "2023-08-31T23:06:31Z", "author_association": "OWNER", "pull_request": null, "body": "I've used this pattern twice now: https://til.simonwillison.net/datasette/register-new-plugin-hooks - in `datasette-graphql` and `datasette-low-disk-space-hook`. I should describe the pattern on https://docs.datasette.io/en/stable/writing_plugins.html", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1765/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1294641696, "node_id": "I_kwDOBm6k_c5NKqog", "number": 1767, "title": "Ability to set a custom favicon", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 9, "created_at": "2022-07-05T18:41:12Z", "updated_at": "2022-07-05T18:56:43Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "If you're running a website on Datasette, like https://www.niche-museums.com/ or https://til.simonwillison.net/ - you should have the ability to easily specify a custom favicon.\r\n\r\nCurrently the `/favicon.ico` view is hard-coded to do this: https://github.com/simonw/datasette/blob/9f1eb0d4eac483b953392157bd9fd6cc4df37de7/datasette/app.py#L179-L188", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1767/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1296222572, "node_id": "I_kwDOBm6k_c5NQsls", "number": 1768, "title": "Upgrade to 3.10.6-slim-bullseye Docker base image", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8303187, "label": "Datasette 0.62"}, "comments": 5, "created_at": "2022-07-06T18:37:49Z", "updated_at": "2022-08-14T15:54:36Z", "closed_at": "2022-08-14T15:54:11Z", "author_association": "OWNER", "pull_request": null, "body": "For the package published to Docker Hub and also the containers used by `datasette package` and `datasette publish cloudrun`.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1768/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1318907685, "node_id": "I_kwDOBm6k_c5OnO8l", "number": 1773, "title": "500 error if sorted by a column not in the ?_col= list", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8303187, "label": "Datasette 0.62"}, "comments": 4, "created_at": "2022-07-27T01:20:27Z", "updated_at": "2022-08-14T16:06:25Z", "closed_at": "2022-08-14T15:44:05Z", "author_association": "OWNER", "pull_request": null, "body": "For example: https://latest.datasette.io/fixtures/sortable?_sort_desc=sortable&_col=sortable_with_nulls\r\n\r\nThat's `?_sort_desc=sortable&_col=sortable_with_nulls`\r\n\r\n\"image\"\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1773/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1339444565, "node_id": "I_kwDOBm6k_c5P1k1V", "number": 1783, "title": "Better guidance as to what to do after you've installed Datasette", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-08-15T20:11:06Z", "updated_at": "2022-08-15T20:14:01Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Feedback [from Discord](https://discord.com/channels/823971286308356157/823971286941302908/1008822978793984060):\r\n\r\n> hello, love the project and came for help and to point out a possible gap in the docs. starting with \"getting started\" and \"installation\" every thing looks great, but then there's a giant leap after you have it installed and running. from the user perspective of \"i have a csv of set of csvs that i want to turn into a table(s), what do i do next?\" --- so something like maybe a page for creating your first project should go after \"installation\".\r\n\r\n- https://docs.datasette.io/en/0.62/getting_started.html\r\n- https://docs.datasette.io/en/0.62/installation.html", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1783/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1340900019, "node_id": "I_kwDOBm6k_c5P7IKz", "number": 1785, "title": "Can't use cog menu to facet by first column in a view", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-08-16T21:27:23Z", "updated_at": "2022-08-16T21:27:23Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://latest.datasette.io/fixtures/paginated_view\r\n\r\n\"image\"\r\n\r\nCompare with:\r\n\r\n\"image\"\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1785/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1338137350, "node_id": "I_kwDOBm6k_c5PwlsG", "number": 1781, "title": "Ensure Datasette Lite is promoted in docs and README", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8303187, "label": "Datasette 0.62"}, "comments": 1, "created_at": "2022-08-14T05:12:35Z", "updated_at": "2022-08-14T15:24:40Z", "closed_at": "2022-08-14T15:24:40Z", "author_association": "OWNER", "pull_request": null, "body": "As of 0.62 https://lite.datasette.io is a supported piece of the overall Datasette ecosystem.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1781/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1338278056, "node_id": "I_kwDOBm6k_c5PxICo", "number": 1782, "title": "Release notes for Datasette 0.62", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8303187, "label": "Datasette 0.62"}, "comments": 2, "created_at": "2022-08-14T15:26:45Z", "updated_at": "2022-08-14T17:40:45Z", "closed_at": "2022-08-14T17:32:54Z", "author_association": "OWNER", "pull_request": null, "body": "I've written a lot of these already for the alphas:\r\n\r\n- https://github.com/simonw/datasette/releases/tag/0.62a0\r\n- https://github.com/simonw/datasette/releases/tag/0.62a1", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1782/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1342430983, "node_id": "I_kwDOBm6k_c5QA98H", "number": 1786, "title": "Adjust height of textarea for no JS case", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-08-18T01:15:15Z", "updated_at": "2022-10-27T21:50:12Z", "closed_at": "2022-08-18T16:06:09Z", "author_association": "OWNER", "pull_request": null, "body": "Datasette Lite: https://lite.datasette.io/?sql=https://gist.githubusercontent.com/simonw/1f8a91123ccefd8844187225b1832d7a/raw/5069075b86aa79358fbab3d4482d1d269077d632/recipes.sql#/data?sql=select+id%2C+name%2C+ingredients%2C+%28%0A++select+json_group_array%28value%29+from+json_each%28ingredients%29%0A++where+value+in+%28select+value+from+json_each%28%3Ap0%29%29%0A%29+as+matching_ingredients%0Afrom+recipes%0Awhere+json_array_length%28matching_ingredients%29+%3E+0%0Aorder+by+json_array_length%28matching_ingredients%29+desc&p0=%5B%22sugar%22%2C+%22cheese%22%5D\r\n\r\n![46F8101E-8CE3-4F61-B200-F865E6B5DBCC](https://user-images.githubusercontent.com/9599/185270723-f55513b0-b561-434d-9d7c-4fe5be9756e0.jpeg)\r\n\r\n\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1786/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1343422749, "node_id": "I_kwDOBm6k_c5QEwEd", "number": 1787, "title": "Move \"datasette --get\" from Getting Started to CLI Reference", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2022-08-18T17:53:39Z", "updated_at": "2022-08-18T21:57:09Z", "closed_at": "2022-08-18T21:56:21Z", "author_association": "OWNER", "pull_request": null, "body": "It really shouldn't be here: https://docs.datasette.io/en/0.62/getting_started.html#datasette-get", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1787/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1343732788, "node_id": "I_kwDOBm6k_c5QF7w0", "number": 1788, "title": "Make it more obvious that Datasette publish can publish multiple databases", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-08-18T22:57:51Z", "updated_at": "2022-08-18T23:06:16Z", "closed_at": "2022-08-18T23:06:16Z", "author_association": "OWNER", "pull_request": null, "body": "Feedback initially for `datasette-publish-fly` but it applies to the others too.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1788/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1345561209, "node_id": "I_kwDOBm6k_c5QM6J5", "number": 1790, "title": "A better HTML title for canned query pages", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-08-21T18:27:46Z", "updated_at": "2022-08-21T18:27:46Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://scotrail.datasette.io/scotrail/assemble_sentence?terms=This+train+is+formed+of%2Cbomb+which\r\n\r\nCurrent title is:\r\n\r\n`scotrail: with phrases as ( select key, value from json_each('["' || replace(:terms, ',', '","') || '"]')),matches as (select phrases.key, phrases.value, ( select File from announcements where announcements.Transcription like '%' || trim(phrases.value) || '%' order by length(announcements.Transcription) limit 1 ) as Filefrom phrases),results as ( select key, announcements.Transcription, announcements.mp3 from announcements join matches on announcements.File = matches.File order by key)select 'Combined sentence:' as mp3, group_concat(Transcription, ' ') as Transcription, -1 as keyfrom results unionselect mp3, Transcription, keyfrom resultsorder by key`\r\n\r\nI think a better title would be:\r\n\r\n`scotrail: assemble_sentence, terms = This train is formed of,bomb which`", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1790/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1353088849, "node_id": "I_kwDOBm6k_c5Qpn9R", "number": 1795, "title": "Consider automatically cleaning up curly quotes in searches", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-08-27T16:35:25Z", "updated_at": "2022-08-27T16:35:25Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "If your phone helpfully adds curly quotes for you then phrase searches against FTS won't work: \u201cRebecca Sugar\u201d\r\n\r\nIn regular (not `?_searchmode=raw` search mode Datasette could clean these up for you to help avoid that mistake.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1795/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1355148385, "node_id": "I_kwDOBm6k_c5Qxexh", "number": 1796, "title": "Research an upgrade to CodeMirror 6", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-08-30T04:27:46Z", "updated_at": "2023-07-03T04:58:21Z", "closed_at": "2023-07-03T04:58:21Z", "author_association": "OWNER", "pull_request": null, "body": "There are still a bunch of bugs in CodeMirror 5 that affect various mobile browsers - see Datasette Discord report here: https://discord.com/channels/823971286308356157/823971286941302908/1013878624992108645\r\n\r\nhttps://user-images.githubusercontent.com/9599/187349269-7b7c0c8c-3894-4810-82f0-de7c1eb940b3.mp4\r\n\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1796/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1373595927, "node_id": "I_kwDOBm6k_c5R32kX", "number": 1809, "title": "`prepare_jinja2_environment()` hook should take `datasette` argument", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 11, "created_at": "2022-09-14T21:15:46Z", "updated_at": "2022-09-17T03:39:05Z", "closed_at": "2022-09-17T03:38:33Z", "author_association": "OWNER", "pull_request": null, "body": "That plugin hook's current signature is:\r\n\r\nhttps://github.com/simonw/datasette/blob/610425460b519e9c16d386cb81aa081c9d730ef0/datasette/hookspecs.py#L28-L30\r\n\r\nAs a result in the first alpha release of `datasette-edit-templates` I had to include this horrific hack: https://github.com/simonw/datasette-edit-templates/blob/087f6a6cabc20020f2b0524f11aa3a7836320848/datasette_edit_templates/__init__.py#L72-L75\r\n\r\n```python\r\n@hookimpl\r\ndef prepare_jinja2_environment(env):\r\n # TODO: This should ideally take datasette, but that's not an argument yet\r\n datasette = inspect.currentframe().f_back.f_back.f_back.f_back.f_locals[\"self\"]\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1809/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1374626873, "node_id": "I_kwDOBm6k_c5R7yQ5", "number": 1810, "title": "Featured table(s) on the homepage", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-09-15T14:30:49Z", "updated_at": "2022-09-15T15:51:25Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Many Datasette instances mainly exist to serve a single table - for example:\r\n\r\n- https://global-power-plants.datasettes.com/global-power-plants/global-power-plants\r\n- https://laion-aesthetic.datasette.io/laion-aesthetic-6pls/images\r\n\r\nIt would be neat if the / homepage of those instances could be configured to highlight that specific table.\r\n\r\nOr maybe more than one?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1810/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1362363685, "node_id": "I_kwDOBm6k_c5RNAUl", "number": 1800, "title": "Remove upper bound dependencies as a default policy", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2022-09-05T18:23:45Z", "updated_at": "2022-09-05T18:39:52Z", "closed_at": "2022-09-05T18:35:41Z", "author_association": "OWNER", "pull_request": null, "body": "https://iscinumpy.dev/post/bound-version-constraints/ has convinced me not to use upper bound dependencies unless I'm certain they are needed.\r\n\r\nRelevant PR:\r\n- https://github.com/simonw/datasette/pull/1799\r\n\r\nAlso:\r\n\r\nhttps://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L45-L46\r\n\r\nhttps://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L48-L49\r\n\r\nhttps://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L51-L55\r\n\r\nhttps://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L57-L59\r\n\r\nhttps://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L75-L78\r\n\r\nhttps://github.com/simonw/datasette/blob/ba35105eee2d3ba620e4f230028a02b2e2571df2/setup.py#L81-L82\r\n\r\n\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1800/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1362402998, "node_id": "I_kwDOBm6k_c5RNJ62", "number": 1802, "title": "Tests reliably failing on Python 3.7", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 15, "created_at": "2022-09-05T19:21:16Z", "updated_at": "2022-09-06T00:40:20Z", "closed_at": "2022-09-06T00:40:20Z", "author_association": "OWNER", "pull_request": null, "body": "\"image\"\r\n\r\nhttps://github.com/simonw/datasette/runs/8194907739?check_suite_focus=true\r\n\r\nI thought this might be an intermittent failure but attempts to re-run the tests have not made it pass.\r\n\r\nEnd of that trace is:\r\n\r\n```\r\n/home/runner/work/datasette/datasette/datasette/app.py:234: in __init__\r\n self._refresh_schemas_lock = asyncio.Lock()\r\n/opt/hostedtoolcache/Python/3.7.13/x64/lib/python3.7/asyncio/locks.py:161: in __init__\r\n self._loop = events.get_event_loop()\r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\n\r\nself = \r\n\r\n def get_event_loop(self):\r\n \"\"\"Get the event loop for the current context.\r\n \r\n Returns an instance of EventLoop or raises an exception.\r\n \"\"\"\r\n if (self._local._loop is None and\r\n not self._local._set_called and\r\n isinstance(threading.current_thread(), threading._MainThread)):\r\n self.set_event_loop(self.new_event_loop())\r\n \r\n if self._local._loop is None:\r\n raise RuntimeError('There is no current event loop in thread %r.'\r\n> % threading.current_thread().name)\r\nE RuntimeError: There is no current event loop in thread 'MainThread'.\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1802/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1363440999, "node_id": "I_kwDOBm6k_c5RRHVn", "number": 1804, "title": "Ability to set a custom facet_size per table", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2022-09-06T15:11:40Z", "updated_at": "2022-09-07T00:21:56Z", "closed_at": "2022-09-06T18:06:53Z", "author_association": "OWNER", "pull_request": null, "body": "Suggestion from Discord: https://discord.com/channels/823971286308356157/823971286941302908/1016725586351247430\r\n\r\n> Is it possible to limit the facet size per database or even per table?\r\n\r\nThis is a really good idea, it could be done in `metadata.yml`.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1804/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1366915240, "node_id": "I_kwDOBm6k_c5ReXio", "number": 1807, "title": "Plugin ecosystem needs to avoid crashes due to no available databases", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-09-08T19:54:34Z", "updated_at": "2022-09-08T20:14:05Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Opening this here to track the issue first reported in:\r\n- https://github.com/simonw/datasette-upload-dbs/issues/5\r\n\r\nPlugins that expect to be able to write to a database need to not crash in situations where no writable database is available.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1807/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1368030952, "node_id": "I_kwDOBm6k_c5Rin7o", "number": 1808, "title": "Database() constructor currently defaults is_mutable to False", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2022-09-09T16:02:41Z", "updated_at": "2022-09-09T16:37:57Z", "closed_at": "2022-09-09T16:19:25Z", "author_association": "OWNER", "pull_request": null, "body": "This is surprising. It caused a bug in `datasette-upload-dbs` because I didn't expect it to do that.\r\n\r\n> I think this is an API design flaw in Datasette itself, but I can fix it here first.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette-upload-dbs/issues/6#issuecomment-1242150394_\r\n\r\nCode in question: https://github.com/simonw/datasette/blob/bf8d84af5422606597be893cedd375020cb2b369/datasette/database.py#L29-L32", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1808/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1378636455, "node_id": "I_kwDOBm6k_c5SLFKn", "number": 1815, "title": "`datasette publish provider .` to publish whole directory, similar to configuration directory mode", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-09-19T23:28:59Z", "updated_at": "2022-09-19T23:29:11Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> I haven't done this with any of my other `datasette publish` tools, but I do think it's a good idea. Being able to publish the entire directory - with templates and plugins and metadata - does seem very useful to me.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette-publish-fly/issues/23#issuecomment-1251673489_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1815/reactions\", \"total_count\": 2, \"+1\": 2, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1378640768, "node_id": "I_kwDOBm6k_c5SLGOA", "number": 1816, "title": "Validate settings.json on startup in configuration directory mode", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-09-19T23:35:18Z", "updated_at": "2022-09-20T01:15:48Z", "closed_at": "2022-09-20T01:15:48Z", "author_association": "OWNER", "pull_request": null, "body": "> It might have been useful for Datasette to show an error when started against a `settings.json` file that contains an invalid setting though.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1814#issuecomment-1251677554_", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1816/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1384273985, "node_id": "I_kwDOBm6k_c5SglhB", "number": 1817, "title": "Expose `sql` and `params` arguments to various plugin hooks", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 7, "created_at": "2022-09-23T20:34:45Z", "updated_at": "2022-09-27T00:27:53Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "On Discord: https://discord.com/channels/823971286308356157/996877076982415491/1022784534363787305\r\n\r\n> Hi! I'm attempting to write a plugin that would provide some statistics on text fields (most common words, etc). I would want this information displayed in the table pages, and (ideally) also updated when users make custom queries from the table pages.\r\n>\r\n> It seems one way to do this would be to use the extra_template_vars hook, and make the appropriate SQL query there. So extra_template_vars would create a variable that is a list of most common words, and this is displayed on the page, possibly above the regular table view.\r\n>\r\n> Is there a way that the plugin code can access the SQL query (or even the data) that was used to produce the table view? I can see that TableView class constructs the SQL query, but I can't seem to find a way to access that information from the objects that are available to extra_template_vars.\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1817/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1384549993, "node_id": "I_kwDOBm6k_c5Sho5p", "number": 1818, "title": "Setting to turn off table row counts entirely", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-09-24T06:39:22Z", "updated_at": "2022-12-11T02:03:09Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "There are situations - such as loading SQLite files remotely using HTTP range headers - where counting all of the rows in a table should be avoided entirely.\r\n\r\n> > Also, this chunked inefficiency means that I have to hack the URL to not load tables of a database as it seems to try to load the whole database when I click on a database.\r\n>\r\n> I bet that's because Datasette tries to show a count of all of the rows in each table when it shows the list on that page, which triggers a full table scan.\r\n>\r\n> Would be great to have a setting that turns that feature off, which could then be exposed as a query string option for Datasette Lite.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette-lite/issues/49#issuecomment-1256880715_\r\n ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1818/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1386734383, "node_id": "I_kwDOBm6k_c5Sp-Mv", "number": 1821, "title": "Release Datasette 0.63a0", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-09-26T21:15:27Z", "updated_at": "2022-09-26T22:06:39Z", "closed_at": "2022-09-26T22:06:39Z", "author_association": "OWNER", "pull_request": null, "body": "> - The [prepare_jinja2_environment(env, datasette)](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-prepare-jinja2-environment) plugin hook now accepts an optional `datasette` argument. Hook implementations can also now return an `async` function which will be awaited automatically. ([#1809](https://github.com/simonw/datasette/issues/1809))\r\n> - `--load-extension` option now supports entrypoints. Thanks, Alex Garcia. ([#1789](https://github.com/simonw/datasette/pull/1789))\r\n> - New tutorial: [Cleaning data with sqlite-utils and Datasette](https://datasette.io/tutorials/clean-data).\r\n> - Facet size can now be set per-table with the new `facet_size` table metadata option. ([#1804](https://github.com/simonw/datasette/issues/1804))\r\n> - `truncate_cells_html` setting now also affects long URLs in columns. ([#1805](https://github.com/simonw/datasette/issues/1805))\r\n> - `Database(is_mutable=)` now defaults to `True`. ([#1808](https://github.com/simonw/datasette/issues/1808))\r\n> - Non-JavaScript textarea now increases height to fit the SQL query. ([#1786](https://github.com/simonw/datasette/issues/1786))\r\n> - More detailed command descriptions on the [CLI reference](https://docs.datasette.io/en/latest/cli-reference.html#cli-reference) page. ([#1787](https://github.com/simonw/datasette/issues/1787))\r\n> - Datasette no longer enforces upper bounds on its depenedencies. ([#1800](https://github.com/simonw/datasette/issues/1800))\r\n> - Facets are now displayed with better line-breaks in long values. Thanks, Daniel Rech. ([#1794](https://github.com/simonw/datasette/pull/1794))\r\n> - The `settings.json` file used in [Configuration directory mode](https://docs.datasette.io/en/latest/settings.html#config-dir) is now validated on startup. ([#1816](https://github.com/simonw/datasette/issues/1816))", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1821/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 1386854246, "node_id": "I_kwDOBm6k_c5Sqbdm", "number": 1822, "title": "Switch to keyword-only arguments for a bunch of internal methods", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 3, "created_at": "2022-09-26T23:20:38Z", "updated_at": "2022-09-27T00:44:04Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This is a good idea, and one that needs to happen before Datasette 1.0:\r\n\r\n> While you are adding features, would you be future-proofing your APIs if you switched over some arguments over to keyword-only arguments or would that be too disruptive?\r\n>\r\n> Thinking out loud:\r\n>\r\n> ```\r\n> async def render_template( \r\n> self, templates, *, context=None, plugin_context=None, request=None, view_name=None \r\n> ): \r\n> ```\r\n_Originally posted by @jefftriplett in https://github.com/simonw/datasette/issues/1817#issuecomment-1256781274_\r\n ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1822/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1406860394, "node_id": "I_kwDOBm6k_c5T2vxq", "number": 1841, "title": "Drop format_bytes for Jinja filesizeformat filter", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2022-10-12T22:06:34Z", "updated_at": "2022-10-12T22:06:34Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Turns out this isn't necessary:\r\n\r\nhttps://github.com/simonw/datasette/blob/5aa359b86907d11b3ee601510775a85a90224da8/datasette/utils/__init__.py#L849-L858\r\n\r\nI can use this instead: https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.filesizeformat", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1841/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1408757705, "node_id": "I_kwDOBm6k_c5T9-_J", "number": 1843, "title": "Intermittent \"Too many open files\" error running tests", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 16, "created_at": "2022-10-14T04:45:01Z", "updated_at": "2022-12-17T22:02:41Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Partial stack trace from one of them:\r\n```\r\n/Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/jinja2/loaders.py:200: in get_source\r\n f = open_if_exists(filename)\r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\r\n\r\nfilename = '/Users/simon/Dropbox/Development/datasette/datasette/templates/error.html', mode = 'rb'\r\n\r\n def open_if_exists(filename: str, mode: str = \"rb\") -> t.Optional[t.IO]:\r\n \"\"\"Returns a file descriptor for the filename if that file exists,\r\n otherwise ``None``.\r\n \"\"\"\r\n if not os.path.isfile(filename):\r\n return None\r\n \r\n> return open(filename, mode)\r\nE OSError: [Errno 24] Too many open files: '/Users/simon/Dropbox/Development/datasette/datasette/templates/error.html'\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1843/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "reopened"} {"id": 1393903845, "node_id": "I_kwDOBm6k_c5TFUjl", "number": 1828, "title": "word-wrap: anywhere resulting in weird display", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2022-10-02T21:25:03Z", "updated_at": "2022-10-02T23:01:17Z", "closed_at": "2022-10-02T23:01:17Z", "author_association": "OWNER", "pull_request": null, "body": "e.g. on https://github-to-sqlite.dogsheep.net/github/commits\r\n\r\n\"image\"\r\n\r\nThis is from a change introduced here: https://github.com/simonw/datasette/commit/bf8d84af5422606597be893cedd375020cb2b369 in #1805\r\n\r\nhttps://github.com/simonw/datasette/blob/bf8d84af5422606597be893cedd375020cb2b369/datasette/static/app.css#L447-L450", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/1828/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"}