{"html_url": "https://github.com/simonw/datasette/issues/1#issuecomment-338523957", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1", "id": 338523957, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUyMzk1Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T01:09:05Z", "updated_at": "2017-10-24T02:42:12Z", "author_association": "OWNER", "body": "I also need to solve for weird primary keys. If it\u2019s a single integer or a single char field that\u2019s easy. But what if it is a compound key with more than one chat field? What delimiter can I use that will definitely be safe?\r\n\r\nLet\u2019s say I use hyphen. Now I need to find a durable encoding for any hyphens that might exist in the key fields themselves.\r\n\r\nHow about I use URLencoding for every non-alpha-numeric character? That will turn hyphens into (I think) %2D. It should also solve for unicode characters, but it means the vast majority of keys (integers) will display neatly, including a compound key of eg 5678-345\r\n\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267513424, "label": "Addressable pages for every row in a table"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1#issuecomment-338524454", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1", "id": 338524454, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUyNDQ1NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T01:15:24Z", "updated_at": "2017-10-23T01:15:24Z", "author_association": "OWNER", "body": "Table rendering logic needs to detect the primary key field and turn it into a hyperlink. If there is a compound primary key it should add an extra column at the start of the table which displays the compound key as a link", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267513424, "label": "Addressable pages for every row in a table"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1#issuecomment-338857568", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1", "id": 338857568, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg1NzU2OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T02:57:12Z", "updated_at": "2017-10-24T02:57:12Z", "author_association": "OWNER", "body": "I can find the primary keys using:\r\n\r\n PRAGMA table_info(myTable)\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267513424, "label": "Addressable pages for every row in a table"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1#issuecomment-338861511", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1", "id": 338861511, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg2MTUxMQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T03:24:17Z", "updated_at": "2017-10-24T03:24:17Z", "author_association": "OWNER", "body": "Some tables won't have primary keys, in which case I won't generate pages for individual records.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267513424, "label": "Addressable pages for every row in a table"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1#issuecomment-338872286", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1", "id": 338872286, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg3MjI4Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T04:46:06Z", "updated_at": "2017-10-24T04:46:06Z", "author_association": "OWNER", "body": "I'm going to use `,` as the separator between elements of a compound primary key. If those elements themselves include a comma I will use `%2C` in its place.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267513424, "label": "Addressable pages for every row in a table"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1#issuecomment-338882207", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1", "id": 338882207, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg4MjIwNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T05:56:04Z", "updated_at": "2017-10-24T05:56:04Z", "author_association": "OWNER", "body": "Next step: generate links to these.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267513424, "label": "Addressable pages for every row in a table"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/3#issuecomment-338526148", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/3", "id": 338526148, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUyNjE0OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T01:35:17Z", "updated_at": "2017-10-23T01:35:17Z", "author_association": "OWNER", "body": "https://github.com/ahupp/python-magic/blob/master/README.md", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515678, "label": "Make individual column valuables addressable, with smart content types"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338530389", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338530389, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUzMDM4OQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T02:15:41Z", "updated_at": "2017-10-23T02:15:41Z", "author_association": "OWNER", "body": "This means I need a good solution for these compile time options while running in development mode \r\n ", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338530480", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338530480, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUzMDQ4MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T02:16:33Z", "updated_at": "2017-10-23T02:16:33Z", "author_association": "OWNER", "body": " How about when the service starts up it checks for a compile.json file and, if it is missing, creates it using the same code we run at compile time normally ", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338531827", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338531827, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUzMTgyNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T02:28:31Z", "updated_at": "2017-10-23T02:29:05Z", "author_association": "OWNER", "body": "Many of the applications I want to implement with this would benefit from having permanent real URLs.\r\n\r\nSo let\u2019s have both. The sha1 urls will serve far future cache headers (and an etag derived from their path). The non sha1 URLs will serve 302 uncached redirects to the sha1 locations.\r\n\r\nWe will have a setting that lets people opt out of this behavior.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338789734", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338789734, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODc4OTczNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T20:40:25Z", "updated_at": "2017-10-23T21:10:19Z", "author_association": "OWNER", "body": "URL design:\r\n\r\n /database/table.json - redirects to /database-6753f4a/table.json\r\n\r\nSo we always redirect to the version with the truncated hash in the URL.\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338797522", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338797522, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODc5NzUyMg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T21:09:33Z", "updated_at": "2017-10-23T21:09:33Z", "author_association": "OWNER", "body": "https://stackoverflow.com/a/18134919/6083 is a good answer about how many characters of the hash are needed to be unique. I say we default to 7 characters, like git does - but allow extras to be configured.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338799438", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338799438, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODc5OTQzOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T21:17:25Z", "updated_at": "2017-10-23T21:17:25Z", "author_association": "OWNER", "body": "Can I take advantage of HTTP/2 so even if you get redirected I start serving you the correct resource straight away?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338804173", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338804173, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODgwNDE3Mw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T21:36:37Z", "updated_at": "2017-10-23T21:36:37Z", "author_association": "OWNER", "body": "Looks like the easiest way to implement HTTP/2 server push today is to run behind Cloudflare and use this:\r\n\r\n Link: ; rel=preload; as=script\r\n\r\nhttps://blog.cloudflare.com/announcing-support-for-http-2-server-push-2/\r\n\r\nHere's the W3C draft: https://w3c.github.io/preload/\r\n\r\nFrom https://w3c.github.io/preload/#as-attribute it looks like I should use `as=fetch` if the content is intended for consumption by fetch() or XMLHTTPRequest.\r\n\r\nUnclear if I should throw `as=fetch crossorigin` in there. Need to experiment on that.\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/4#issuecomment-338806718", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/4", "id": 338806718, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODgwNjcxOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T21:47:53Z", "updated_at": "2017-10-23T21:47:53Z", "author_association": "OWNER", "body": "Here's what the homepage of cloudflare.com does (with newlines added within the link header for clarity):\r\n\r\n $ curl -i 'https://www.cloudflare.com/' \r\n HTTP/1.1 200 OK\r\n Date: Mon, 23 Oct 2017 21:45:58 GMT\r\n Content-Type: text/html; charset=utf-8\r\n Transfer-Encoding: chunked\r\n Connection: keep-alive\r\n link:\r\n ; rel=preload; as=style,\r\n ; rel=preload; as=style,\r\n ; rel=preload,\r\n ; rel=preload,\r\n ; rel=preload; as=video,\r\n ; rel=preload; as=video,\r\n ; rel=preload; as=video,\r\n ; rel=preload; as=video,\r\n ; rel=preload; as=video,\r\n ; rel=preload; as=image\r\n\r\nThe original header looked like this:\r\n\r\n link: ; rel=preload; as=style, ; rel=preload; as=style, ; rel=preload, ; rel=preload, ; rel=preload; as=video, ; rel=preload; as=video, ; rel=preload; as=video, ; rel=preload; as=video, ; rel=preload; as=video, ; rel=preload; as=image\r\n\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267515836, "label": "Make URLs immutable"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/5#issuecomment-338524857", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/5", "id": 338524857, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUyNDg1Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T01:20:30Z", "updated_at": "2017-10-23T01:20:30Z", "author_association": "OWNER", "body": "https://stackoverflow.com/a/14468878/6083\r\n\r\nLooks like I should order by compound primary key and implement cursor-based pagination.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267516066, "label": "Implement sensible query pagination"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/5#issuecomment-339027711", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/5", "id": 339027711, "node_id": "MDEyOklzc3VlQ29tbWVudDMzOTAyNzcxMQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T15:21:30Z", "updated_at": "2017-10-24T15:21:30Z", "author_association": "OWNER", "body": "I have code to detect primary keys on tables... but what should I do for tables that lack primary keys? How should I even sort them?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267516066, "label": "Implement sensible query pagination"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/5#issuecomment-339028979", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/5", "id": 339028979, "node_id": "MDEyOklzc3VlQ29tbWVudDMzOTAyODk3OQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T15:25:08Z", "updated_at": "2017-10-24T15:25:08Z", "author_association": "OWNER", "body": "Looks like I can use the SQLite specific \u201crowid\u201d in that case. It isn\u2019t guaranteed to stay consistent across a VACUUM but that\u2019s ok because we are immutable anyway.\r\n\r\n https://www.sqlite.org/lang_createtable.html#rowid", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267516066, "label": "Implement sensible query pagination"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/7#issuecomment-338853083", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/7", "id": 338853083, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg1MzA4Mw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T02:27:25Z", "updated_at": "2017-10-24T02:27:25Z", "author_association": "OWNER", "body": "Fixed in 9d219140694551453bfa528e0624919eb065f9d6", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267516650, "label": "Framework where by every page is JSON plus a template"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/8#issuecomment-338697223", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/8", "id": 338697223, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODY5NzIyMw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T15:28:11Z", "updated_at": "2017-10-23T15:28:11Z", "author_association": "OWNER", "body": "Now returning this:\r\n\r\n {\r\n \"error\": \"attempt to write a readonly database\",\r\n \"ok\": false\r\n }\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267517314, "label": "Attempting an INSERT or UPDATE should return a sane error message"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/9#issuecomment-338863155", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/9", "id": 338863155, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg2MzE1NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T03:36:58Z", "updated_at": "2017-10-24T03:36:58Z", "author_association": "OWNER", "body": "I\u2019m going to use py.test and start with all tests in a single tests.py module", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267517348, "label": "Initial test suite"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/9#issuecomment-338882110", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/9", "id": 338882110, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODg4MjExMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-24T05:55:33Z", "updated_at": "2017-10-24T05:55:33Z", "author_association": "OWNER", "body": "Well, I've started it at least.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267517348, "label": "Initial test suite"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/10#issuecomment-341938424", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/10", "id": 341938424, "node_id": "MDEyOklzc3VlQ29tbWVudDM0MTkzODQyNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-04T23:48:57Z", "updated_at": "2017-11-04T23:48:57Z", "author_association": "OWNER", "body": "Done: https://github.com/simonw/stateless-datasets/commit/edaa10587e60946e0c1935333f6b79553db33798", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267517381, "label": "Set up Travis"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/11#issuecomment-338530704", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/11", "id": 338530704, "node_id": "MDEyOklzc3VlQ29tbWVudDMzODUzMDcwNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-10-23T02:18:36Z", "updated_at": "2017-10-23T02:18:36Z", "author_association": "OWNER", "body": "Needed by https://github.com/simonw/stateless-datasets/issues/4#issuecomment-338530389", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267522549, "label": "Code that generates compile-time properties about the database "}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/12#issuecomment-348245757", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/12", "id": 348245757, "node_id": "MDEyOklzc3VlQ29tbWVudDM0ODI0NTc1Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-30T16:39:45Z", "updated_at": "2017-11-30T16:39:45Z", "author_association": "OWNER", "body": "It is now possible to over-ride templates on a per-database / per-row or per-\r\ntable basis.\r\n\r\nWhen you access e.g. `/mydatabase/mytable` Datasette will look for the following:\r\n\r\n - table-mydatabase-mytable.html\r\n - table.html\r\n\r\nIf you provided a `--template-dir` argument to datasette serve it will look in\r\nthat directory first.\r\n\r\nThe lookup rules are as follows:\r\n\r\n Index page (/):\r\n index.html\r\n\r\n Database page (/mydatabase):\r\n database-mydatabase.html\r\n database.html\r\n\r\n Table page (/mydatabase/mytable):\r\n table-mydatabase-mytable.html\r\n table.html\r\n\r\n Row page (/mydatabase/mytable/id):\r\n row-mydatabase-mytable.html\r\n row.html\r\n\r\nIf a table name has spaces or other unexpected characters in it, the template\r\nfilename will follow the same rules as our custom `
` CSS classes\r\nintroduced in 8ab3a16 - for example, a table called \"Food Trucks\"\r\nwill attempt to load the following templates:\r\n\r\n table-mydatabase-Food-Trucks-399138.html\r\n table.html\r\n\r\nIt is possible to extend the default templates using Jinja template\r\ninheritance. If you want to customize EVERY row template with some additional\r\ncontent you can do so by creating a `row.html` template like this:\r\n\r\n {% extends \"default:row.html\" %}\r\n\r\n {% block content %}\r\nThis line renders the original block:
\r\n {{ super() }}\r\n {% endblock %}\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267523511, "label": "Make it so you can override templates"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/13#issuecomment-344462608", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/13", "id": 344462608, "node_id": "MDEyOklzc3VlQ29tbWVudDM0NDQ2MjYwOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-15T02:04:51Z", "updated_at": "2017-11-15T02:04:51Z", "author_association": "OWNER", "body": "Fixed in https://github.com/simonw/datasette/commit/8252daa4c14d73b4b69e3f2db4576bb39d73c070 - thanks, @tomdyson!", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267542338, "label": "Add a syntax highlighting SQL editor"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-343675165", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 343675165, "node_id": "MDEyOklzc3VlQ29tbWVudDM0MzY3NTE2NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-11T16:07:10Z", "updated_at": "2017-11-11T16:07:10Z", "author_association": "OWNER", "body": "The plugin system can also allow alternative providers for the `publish` command - e.g. maybe hook up hyper.sh as an option for publishing containers.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-344438724", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 344438724, "node_id": "MDEyOklzc3VlQ29tbWVudDM0NDQzODcyNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-14T23:47:54Z", "updated_at": "2017-11-14T23:47:54Z", "author_association": "OWNER", "body": "Plugins should be able to interact with the build step. This would give plugins an opportunity to modify the SQL databases and help prepare them for serving - for example, a full-text search plugin might create additional FTS tables, or a mapping plugin might pre-calculate a bunch of geohashes for tables that have latitude/longitude values. Plugins could really take advantage of the immutable nature of the dataset here.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-345067498", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 345067498, "node_id": "MDEyOklzc3VlQ29tbWVudDM0NTA2NzQ5OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-16T21:25:32Z", "updated_at": "2017-11-16T21:26:22Z", "author_association": "OWNER", "body": "For visualizations, Google Maps should be made available as a plugin. The default visualizations can use Leaflet and Open Street Map, but there's no reason to not make Google Maps available as a plugin, especially if the plugin can provide a mechanism for configuring the necessary API key.\r\n\r\nI'm particularly excited in the Google Maps heatmap visualization https://developers.google.com/maps/documentation/javascript/heatmaplayer as seen on http://mochimachine.org/wasteland/", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-345893877", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 345893877, "node_id": "MDEyOklzc3VlQ29tbWVudDM0NTg5Mzg3Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-21T02:11:27Z", "updated_at": "2017-11-21T02:11:27Z", "author_association": "OWNER", "body": "http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins Is pretty good ", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-346406009", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 346406009, "node_id": "MDEyOklzc3VlQ29tbWVudDM0NjQwNjAwOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2017-11-22T16:39:08Z", "updated_at": "2017-11-22T16:39:08Z", "author_association": "OWNER", "body": "Oh thanks, that definitely looks like an interesting option.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381442233", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381442233, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ0MjIzMw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-15T22:13:06Z", "updated_at": "2018-04-15T22:13:06Z", "author_association": "OWNER", "body": "I started a thread on Twitter asking people for good examples of Python projects with a strong plugin ecosystem: https://twitter.com/simonw/status/985377670388105216\r\n\r\nThe most impressive example that came back was pytest - which now has nearly 400 plugins: https://plugincompat.herokuapp.com/\r\n\r\nThe pytest plugin infrastructure is available as an independent package called pluggy - which appears to offer everything I need for Datasette. I'm going to give that a go and see how well it works: https://pluggy.readthedocs.io/en/latest/", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381442494", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381442494, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ0MjQ5NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-15T22:17:59Z", "updated_at": "2018-04-15T22:17:59Z", "author_association": "OWNER", "body": "Datasette 1.0 will be the release of Datasette that attempts to provide a stable plugin API: https://github.com/simonw/datasette/milestone/7\r\n\r\nThere's a lot of work to be done before then, but as a starting point I'm going to support two very simple extension mechanisms:\r\n\r\n* Template system plugins - where the hook gets passed the Jinja environment and can freely register new template tags and filters\r\n* SQLite connection plugins - where the hook gets passed a new SQLite connection and can register custom SQLite functions\r\n\r\nThe template system hook will go near here:\r\n\r\nhttps://github.com/simonw/datasette/blob/efbb4e83374a2c795e436c72fa79f70da72309b8/datasette/app.py#L1225-L1228\r\n\r\nThe SQLite connection hook will go near here:\r\n\r\nhttps://github.com/simonw/datasette/blob/efbb4e83374a2c795e436c72fa79f70da72309b8/datasette/app.py#L1094-L1098\r\n\r\nThese two feel simple enough that I'm not worried that I might design an API that I later regret.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381443728", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381443728, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ0MzcyOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-15T22:39:00Z", "updated_at": "2018-04-15T22:39:00Z", "author_association": "OWNER", "body": "Tox is a good example of a project that uses pluggy in the way I want to use it (function hooks rather than classes): https://github.com/tox-dev/tox/blob/master/tox/hookspecs.py", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381446392", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381446392, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ0NjM5Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-15T23:22:40Z", "updated_at": "2018-04-16T05:25:57Z", "author_association": "OWNER", "body": "OK, from that prototype in f2720b0c6b7172ebe8820 it looks like pluggy provides a solid path forward.\r\n\r\nNext steps:\r\n\r\n- [x] Build a demo plugin that uses setuptools entrypoints to register with the `datasette` plugin manager via pluggy\r\n- [x] Figure out a mechanism for registering plugins without first needing to publish them to PyPI. Can I load plugins from a special `plugins/` directory similar to the `--template-dir=templates/` option already supported by Datasette? #211", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381446511", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381446511, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ0NjUxMQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-15T23:25:04Z", "updated_at": "2018-04-15T23:25:04Z", "author_association": "OWNER", "body": "Here's a demo of the `convert_units()` SQL function I prototyped in f2720b0c6b7172ebe88\r\n\r\n![2018-04-15 at 4 23 pm](https://user-images.githubusercontent.com/9599/38784633-8c43821e-40c9-11e8-97dd-697755a0f858.png)\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381446906", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381446906, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ0NjkwNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-15T23:31:58Z", "updated_at": "2018-04-15T23:34:10Z", "author_association": "OWNER", "body": "Once I've got the plugins mechanism stable and people start releasing plugins it would be useful to have a dedicated Trove classifier on PyPI for Datasette plugins - `Framework :: Datasette` for example.\r\n\r\nThis would help me build a Datasette equivalent of the http://plugincompat.herokuapp.com/ site, which works by scanning PyPI for items with the ``Framework :: Pytest`` classifier:\r\n\r\nhttps://github.com/pytest-dev/plugincompat/blob/8bdf1a6fb82807091ece0c68c196103ee8270194/update_index.py#L52-L53\r\n\r\nIt looks like the mechanism for requesting new PyPI classifiers is to file a ticket against warehouse, like these ones: https://github.com/pypa/warehouse/issues/3570 and https://github.com/pypa/warehouse/issues/2881", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381450394", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381450394, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ1MDM5NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-16T00:27:23Z", "updated_at": "2018-04-16T00:27:23Z", "author_association": "OWNER", "body": "I created https://github.com/simonw/datasette-plugin-demos which is now published to PyPI and can be installed with `pip install datasette-plugin-demos` - I've confirmed that if you DO install it my Datasette `plugins` branch picks up the plugins, and `select random_integer(1, 4)` works as it should.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 267707940, "label": "Datasette Plugins"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/14#issuecomment-381450591", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/14", "id": 381450591, "node_id": "MDEyOklzc3VlQ29tbWVudDM4MTQ1MDU5MQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2018-04-16T00:30:22Z", "updated_at": "2018-04-16T00:34:42Z", "author_association": "OWNER", "body": "Slight code design problem... when I tried installing my branch in a fresh virtual environment I got this error, because `setup.py` now depends on `pluggy` (from importing `__version__`):\r\n\r\n```\r\n File \"/private/var/folders/jj/fngnv0810tn2lt_kd3911pdc0000gp/T/pip-req-build-dftqdezt/setup.py\", line 2, in