{"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-592621235", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 592621235, "node_id": "MDEyOklzc3VlQ29tbWVudDU5MjYyMTIzNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-02-28T17:24:06Z", "updated_at": "2020-05-27T21:12:21Z", "author_association": "OWNER", "body": "Rather than pass a request object (hence promoting that object into part of the documented, stable API) I think I'll pass the ASGI scope - that's already a stable, documented standard.\r\n\r\nUPDATE: changed my mind since `request` is used by other plugins too, see #706.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/744#issuecomment-634395343", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/744", "id": 634395343, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDM5NTM0Mw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T02:49:26Z", "updated_at": "2020-05-27T02:49:26Z", "author_association": "OWNER", "body": "OK, here's a new branch you can try. Install it like this:\r\n\r\n pip install https://github.com/simonw/datasette/archive/shutil-backport.zip\r\n\r\nIf it works for you I'll merge that branch into master.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 608058890, "label": "link_or_copy_directory() error - Invalid cross-device link"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/744#issuecomment-634850676", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/744", "id": 634850676, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg1MDY3Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T18:18:01Z", "updated_at": "2020-05-27T18:18:01Z", "author_association": "OWNER", "body": "Thanks for helping test this @aborruso!", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 608058890, "label": "link_or_copy_directory() error - Invalid cross-device link"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634852196", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634852196, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg1MjE5Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T18:20:46Z", "updated_at": "2020-05-27T18:20:46Z", "author_association": "OWNER", "body": "Here's the code that calls the renderers - this needs to be expanded to check for those extra optional arguments:\r\n\r\nhttps://github.com/simonw/datasette/blob/2d099ad9c657d2cab59de91cdb8bfed2da236ef6/datasette/views/base.py#L387-L398", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634853296", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634853296, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg1MzI5Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T18:22:46Z", "updated_at": "2020-05-27T18:22:46Z", "author_association": "OWNER", "body": "While I'm doing this, another feature I would like is the ability for renderers to opt-in / opt-out of being displayed as options on the page.\r\n\r\nhttps://www.niche-museums.com/browse/museums for example shows a `atom` link because the `datasette-atom` plugin is installed... but clicking it will give you a 400 error because the correct columns are not present:\r\n\r\n\"browse__museums__102_rows\"\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634856748", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634856748, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg1Njc0OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T18:28:32Z", "updated_at": "2020-05-27T18:28:32Z", "author_association": "OWNER", "body": "Here's the code that passes a list of renderers to the template:\r\n\r\nhttps://github.com/simonw/datasette/blob/2d099ad9c657d2cab59de91cdb8bfed2da236ef6/datasette/views/base.py#L411-L423\r\n\r\nA renderer is currently defined as a two-key dictionary:\r\n```python\r\n@hookimpl\r\ndef register_output_renderer(datasette):\r\n return {\r\n 'extension': 'test',\r\n 'callback': render_test\r\n }\r\n```\r\nI can add a third key, `\"should_suggest\"` which is a function that returns `True` or `False` for a given query. If that key is missing it is assumed to return `True`.\r\n\r\nOne catch: what arguments should be passed to the `should_suggest(...)` function?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634857975", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634857975, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg1Nzk3NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T18:30:29Z", "updated_at": "2020-05-27T18:30:29Z", "author_association": "OWNER", "body": "I'll use #770 for the `should_suggest` mechanism - this issue is for the extra arguments passed to the rendering callback.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634865620", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634865620, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg2NTYyMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T18:44:06Z", "updated_at": "2020-05-27T18:44:06Z", "author_association": "OWNER", "body": "The existing render callback takes the following arguments:\r\n\r\n> `args` - dictionary\r\n> The GET parameters of the request\r\n> \r\n> `data` - dictionary\r\n> The data to be rendered\r\n> \r\n> `view_name` - string\r\n> The name of the view where the renderer is being called. (`index`, `database`, `table`, and `row` are the most important ones.)\r\n\r\nThe `data` argument is a bit of a problem, because it tightly couples plugins to a currently undocumented datastructure within Datasette. Here's how `datasette-atom` picks that apart for example: https://github.com/simonw/datasette-atom/blob/095941c23c81b70c4787cdeef873c556b573b5fa/datasette_atom/__init__.py#L15-L66 - it does things like access `data[\"query\"][\"sql\"]` to figure out the SQL query that was used.\r\n\r\nI'm going to change the design of part of this ticket. I won't break the old `data` value just yet, but I'll mark it to be deprecated by Datasette 1.0.\r\n\r\nI think the only plugins using it right now are my `datasette-atom` and `datasette-ics` and @russss's [datasette-geo](https://github.com/russss/datasette-geo/blob/0d24c9fd782eeae8d136ee791143ee8cbf49ebdf/datasette_plugin_geo/__init__.py#L94-L101) so hopefully changing this won't cause any wider damage.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634879734", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634879734, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg3OTczNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:10:17Z", "updated_at": "2020-05-27T19:12:36Z", "author_association": "OWNER", "body": "The `should_suggest` callback will take the same arguments: https://github.com/simonw/datasette/issues/770#issuecomment-634880090", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/770#issuecomment-634880474", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/770", "id": 634880474, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg4MDQ3NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:11:39Z", "updated_at": "2020-05-27T19:11:39Z", "author_association": "OWNER", "body": "I'm going to rename `callback` to `render` but continue supporting `callback` until Datasette 1.0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625930207, "label": "register_output_renderer can_render mechanism"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634881287", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634881287, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg4MTI4Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:13:09Z", "updated_at": "2020-05-27T19:13:09Z", "author_association": "OWNER", "body": "I think I need a utility function for \"call this function with this dictionary of arguments, but only pass the arguments which are inspected by the function\".", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634882112", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634882112, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg4MjExMg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:14:55Z", "updated_at": "2020-05-27T19:14:55Z", "author_association": "OWNER", "body": "https://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object\r\n\r\n> New in version 3.3.\r\n> \r\n> The Signature object represents the call signature of a callable object and its return annotation. To retrieve a Signature object, use the [`signature()`](https://docs.python.org/3/library/inspect.html#inspect.signature \"inspect.signature\") function.\r\n> \r\n> `inspect.``signature`(*callable*, ***, *follow_wrapped=True*)\r\n> \r\n> Return a [`Signature`](https://docs.python.org/3/library/inspect.html#inspect.Signature \"inspect.Signature\") object for the given `callable`:\r\n> \r\n> ```\r\n> >>> from inspect import signature\r\n> >>> def foo(a, *, b:int, **kwargs):\r\n> ... pass\r\n> \r\n> >>> sig = signature(foo)\r\n> \r\n> >>> str(sig)\r\n> '(a, *, b:int, **kwargs)'\r\n> \r\n> >>> str(sig.parameters['b'])\r\n> 'b:int'\r\n> \r\n> >>> sig.parameters['b'].annotation\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": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634882770", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634882770, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg4Mjc3MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:16:19Z", "updated_at": "2020-05-27T19:16:19Z", "author_association": "OWNER", "body": "```\r\nIn [1]: import inspect \r\n\r\nIn [2]: def foo(view, sql, inspect): \r\n ...: pass \r\n ...: \r\n\r\nIn [3]: inspect.signature(foo) \r\nOut[3]: \r\n\r\nIn [4]: inspect.signature(foo).parameters \r\nOut[4]: \r\nmappingproxy({'view': ,\r\n 'sql': ,\r\n 'inspect': })\r\n\r\nIn [5]: inspect.signature(foo).parameters.keys() \r\nOut[5]: odict_keys(['view', 'sql', 'inspect'])\r\n\r\nIn [6]: set(inspect.signature(foo).parameters.keys()) \r\nOut[6]: {'inspect', 'sql', 'view'}\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634888582", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634888582, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg4ODU4Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:23:23Z", "updated_at": "2020-05-27T19:23:23Z", "author_association": "OWNER", "body": "Here's the function I just wrote for this:\r\n```python\r\ndef call_with_supported_arguments(fn, **kwargs):\r\n parameters = inspect.signature(fn).parameters.keys()\r\n call_with = []\r\n for parameter in parameters:\r\n if parameter not in kwargs:\r\n raise TypeError(\"{} requires parameters {}\".format(fn, tuple(parameters)))\r\n call_with.append(kwargs[parameter])\r\n return fn(*call_with)\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634893744", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634893744, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDg5Mzc0NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:32:08Z", "updated_at": "2020-05-27T19:32:08Z", "author_association": "OWNER", "body": "Need to figure out how best to unit test this plugin hook.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/771#issuecomment-634900776", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/771", "id": 634900776, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDkwMDc3Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T19:44:25Z", "updated_at": "2020-05-27T19:44:25Z", "author_association": "OWNER", "body": "This seems to work:\r\n```diff\r\ndiff --git a/tests/test_plugins.py b/tests/test_plugins.py\r\nindex 8b6a6b4..e9a40aa 100644\r\n--- a/tests/test_plugins.py\r\n+++ b/tests/test_plugins.py\r\n@@ -7,7 +7,7 @@ from .fixtures import (\r\n TestClient as _TestClient,\r\n ) # noqa\r\n from datasette.app import Datasette\r\n-from datasette.plugins import get_plugins, DEFAULT_PLUGINS\r\n+from datasette.plugins import get_plugins, DEFAULT_PLUGINS, pm\r\n from datasette.utils import sqlite3\r\n import base64\r\n import json\r\n@@ -20,6 +20,21 @@ import pytest\r\n import urllib\r\n \r\n \r\n+def test_plugin_hooks_have_tests():\r\n+ \"Every plugin hook should be referenced in this test module\"\r\n+ hooks = [name for name in dir(pm.hook) if not name.startswith(\"_\")]\r\n+ tests_in_this_module = [t for t in globals().keys() if t.startswith('test_')]\r\n+ untested = []\r\n+ for hook in hooks:\r\n+ ok = False\r\n+ for test in tests_in_this_module:\r\n+ if hook in test:\r\n+ ok = True\r\n+ if not ok:\r\n+ untested.append(hook)\r\n+ assert not untested, 'These plugin hooks are missing tests: {}'.format(untested)\r\n+\r\n+\r\n def test_plugins_dir_plugin_prepare_connection(app_client):\r\n response = app_client.get(\r\n \"/fixtures.json?sql=select+convert_units(100%2C+'m'%2C+'ft')\"\r\n```\r\nBased on how the documentation unit tests work.\r\n\r\nCurrently fails with:\r\n\r\n AssertionError: These plugin hooks are missing tests:\r\n ['prepare_jinja2_environment', 'publish_subcommand', 'register_facet_classes', 'register_output_renderer']\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625980317, "label": "Unit test that checks that all plugin hooks have corresponding unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/771#issuecomment-634909347", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/771", "id": 634909347, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDkwOTM0Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T20:01:52Z", "updated_at": "2020-05-27T20:01:52Z", "author_association": "OWNER", "body": "I'll do the work for this in the pull request #772.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625980317, "label": "Unit test that checks that all plugin hooks have corresponding unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/771#issuecomment-634909818", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/771", "id": 634909818, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDkwOTgxOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T20:02:52Z", "updated_at": "2020-05-27T20:02:52Z", "author_association": "OWNER", "body": "Actually I'll land this using `@pytest.mark.xfail`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625980317, "label": "Unit test that checks that all plugin hooks have corresponding unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/771#issuecomment-634915104", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/771", "id": 634915104, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDkxNTEwNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T20:14:32Z", "updated_at": "2020-05-27T20:14:32Z", "author_association": "OWNER", "body": "```\r\n$ pytest -k test_plugin_hooks_have_tests -vv\r\n====================================== test session starts ======================================\r\nplatform darwin -- Python 3.7.7, pytest-5.2.4, py-1.8.1, pluggy-0.13.1 -- /Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/bin/python\r\ncachedir: .pytest_cache\r\nrootdir: /Users/simon/Dropbox/Development/datasette, inifile: pytest.ini\r\nplugins: asyncio-0.10.0\r\ncollected 486 items / 475 deselected / 11 selected \r\n\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[asgi_wrapper] XPASS [ 9%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[extra_body_script] XPASS [ 18%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[extra_css_urls] XPASS [ 27%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[extra_js_urls] XPASS [ 36%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[extra_template_vars] XPASS [ 45%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[prepare_connection] XPASS [ 54%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[prepare_jinja2_environment] XFAIL [ 63%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[publish_subcommand] XFAIL [ 72%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[register_facet_classes] XFAIL [ 81%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[register_output_renderer] XFAIL [ 90%]\r\ntests/test_plugins.py::test_plugin_hooks_have_tests[render_cell] XPASS [100%]\r\n\r\n========================= 475 deselected, 4 xfailed, 7 xpassed in 1.70s =========================", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625980317, "label": "Unit test that checks that all plugin hooks have corresponding unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/771#issuecomment-634916313", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/771", "id": 634916313, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDkxNjMxMw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T20:17:13Z", "updated_at": "2020-05-27T20:17:13Z", "author_association": "OWNER", "body": "Closed in da87e963bff24e47878a5bc2025c8bfc63d4bc93", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625980317, "label": "Unit test that checks that all plugin hooks have corresponding unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634921101", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634921101, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDkyMTEwMQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T20:27:36Z", "updated_at": "2020-05-27T20:27:36Z", "author_association": "OWNER", "body": "Actually passing the `request` object would be OK if I document it see https://github.com/simonw/datasette/issues/706", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/773#issuecomment-634940522", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/773", "id": 634940522, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk0MDUyMg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:07:48Z", "updated_at": "2020-05-27T21:07:48Z", "author_association": "OWNER", "body": "Remove this `xfail` decorator once they are all tested: https://github.com/simonw/datasette/blob/da87e963bff24e47878a5bc2025c8bfc63d4bc93/tests/test_plugins.py#L23-L28", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 626001501, "label": "All plugin hooks should have unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634943336", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634943336, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk0MzMzNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:13:04Z", "updated_at": "2020-05-27T21:13:04Z", "author_association": "OWNER", "body": "Since I'm passing `request` I won't pass `scope` - if people want that they can access `request.scope`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634944832", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634944832, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk0NDgzMg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:15:50Z", "updated_at": "2020-05-27T21:16:28Z", "author_association": "OWNER", "body": "It bothers me that `query_name` here means the configured name of the canned query, but `view_name` means the name of the Datasette view class, NOT the name of an associated SQL view. That's in `table`.\r\n\r\nCan I come up with clearer names for these?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634946197", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634946197, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk0NjE5Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:18:30Z", "updated_at": "2020-05-27T21:18:30Z", "author_association": "OWNER", "body": "I'm going to break backwards compatibility directly here, without waiting for Datasette 1.0.\r\n\r\nThe reason is that https://github.com/russss/datasette-geo hasn't been updated in 13 months so is already broken against current Datasette, and the other two plugins using this hook are owned by me so I can upgrade them myself.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634946319", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634946319, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk0NjMxOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:18:50Z", "updated_at": "2020-05-27T21:18:50Z", "author_association": "OWNER", "body": "(I used GitHub code search to find code using this plugin hook: https://github.com/search?q=register_output_renderer&type=Code )", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/758#issuecomment-634950200", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/758", "id": 634950200, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk1MDIwMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:26:37Z", "updated_at": "2020-05-27T21:26:37Z", "author_association": "OWNER", "body": "https://latest.datasette.io/.json currently returns:\r\n\r\n```\r\n{\r\n \"fixtures\": {\r\n \"name\": \"fixtures\",\r\n \"hash\": \"87b3f2c55dfb81ff1452dd306c2623fa5550b90982cfa32bad404c4d8bbedde2\",\r\n \"color\": \"87b3f2\",\r\n \"path\": \"/fixtures\",\r\n \"tables_and_views_truncated\": [\r\n```\r\n\r\nI published `fixtures.db` here like this:\r\n\r\n datasette publish cloudrun fixtures.db --service datasette-hash-urls --extra-options '--config hash_urls:1'\r\n\r\nhttps://datasette-hash-urls-j7hipcg4aq-uw.a.run.app/.json\r\n```\r\n{\r\n \"fixtures\": {\r\n \"name\": \"fixtures\",\r\n \"hash\": \"bda7daa889c23f9a8f06e46d7d280dd423c76275e9593c4c1cad7c53b19032fe\",\r\n \"color\": \"bda7da\",\r\n \"path\": \"/fixtures-bda7daa\",\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 612382643, "label": "Question: Access to immutable database-path"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/758#issuecomment-634951605", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/758", "id": 634951605, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk1MTYwNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:29:19Z", "updated_at": "2020-05-27T21:29:19Z", "author_association": "OWNER", "body": "But... https://datasette-hash-urls-j7hipcg4aq-uw.a.run.app/fixtures-bda7daa.json doesn't expose that hash:\r\n```\r\n{\r\n \"database\": \"fixtures\",\r\n \"size\": 258048,\r\n \"tables\": [\r\n {\r\n \"name\": \"123_starts_with_digits\",\r\n```\r\nLikewise https://datasette-hash-urls-j7hipcg4aq-uw.a.run.app/fixtures-bda7daa/complex_foreign_keys.json\r\n```\r\n{\r\n \"database\": \"fixtures\",\r\n \"table\": \"complex_foreign_keys\",\r\n \"is_view\": false,\r\n \"human_description_en\": \"\",\r\n \"rows\": [\r\n [\r\n \"1\",\r\n \"1\",\r\n \"2\",\r\n \"1\"\r\n ]\r\n ],\r\n```\r\nAnd https://datasette-hash-urls-j7hipcg4aq-uw.a.run.app/fixtures-bda7daa/complex_foreign_keys/1.json\r\n```\r\n{\r\n \"database\": \"fixtures\",\r\n \"table\": \"complex_foreign_keys\",\r\n \"rows\": [\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 612382643, "label": "Question: Access to immutable database-path"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634964294", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634964294, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk2NDI5NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:57:10Z", "updated_at": "2020-05-27T21:57:10Z", "author_association": "OWNER", "body": "Right now a rendering callback returns the following:\r\n```\r\nbody - string or bytes, optional\r\n The response body, default empty\r\ncontent_type - string, optional\r\n The Content-Type header, default text/plain\r\nstatus_code - integer, optional\r\n The HTTP status code, default 200 \r\n```\r\nI'm going to add an optional `headers` dictionary key, too.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634964457", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634964457, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk2NDQ1Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:57:35Z", "updated_at": "2020-05-27T21:57:35Z", "author_association": "OWNER", "body": "(I wonder if this would be enough to allow really smart plugins to implement ETag/conditional get)", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/706#issuecomment-634965148", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/706", "id": 634965148, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk2NTE0OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T21:59:07Z", "updated_at": "2020-05-27T21:59:07Z", "author_association": "OWNER", "body": "This is the full current implementation of the request object:\r\nhttps://github.com/simonw/datasette/blob/9424687e9e94401438896116898a071702b09d40/datasette/utils/asgi.py#L15-L95", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 585633142, "label": "Documentation for the \"request\" object"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/706#issuecomment-634973596", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/706", "id": 634973596, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk3MzU5Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T22:19:02Z", "updated_at": "2020-05-27T22:19:02Z", "author_association": "OWNER", "body": "New documentation can be seen here: https://github.com/simonw/datasette/blob/6d7cb02f00010d3cb4b4bac0460d41277652b80e/docs/internals.rst#request-object\r\n\r\nIt's inspired me to reconsider the name of the `.raw_args` property, which isn't particularly clear.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 585633142, "label": "Documentation for the \"request\" object"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/706#issuecomment-634974088", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/706", "id": 634974088, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk3NDA4OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T22:20:20Z", "updated_at": "2020-05-27T22:20:20Z", "author_association": "OWNER", "body": "It looks like I inherited `.raw_args` from Sanic - I use it in a few places: https://github.com/search?q=user%3Asimonw+raw_args&type=Code", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 585633142, "label": "Documentation for the \"request\" object"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/706#issuecomment-634974819", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/706", "id": 634974819, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk3NDgxOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T22:22:20Z", "updated_at": "2020-05-27T22:22:20Z", "author_association": "OWNER", "body": "What would a better name be?\r\n\r\n- `.simple_args`\r\n- `.kv_args`\r\n- `.pair_args`\r\n- `.dict_args`\r\n- `.args_dict`\r\n\r\nI dislike the last two the least.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 585633142, "label": "Documentation for the \"request\" object"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/706#issuecomment-634975252", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/706", "id": 634975252, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk3NTI1Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T22:23:26Z", "updated_at": "2020-05-27T22:30:05Z", "author_association": "OWNER", "body": "I'm going to leave `.raw_args` in for the moment but deliberately not document it. I'll hope to phase it out entirely at a later date.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 585633142, "label": "Documentation for the \"request\" object"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/581#issuecomment-634978388", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/581", "id": 634978388, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk3ODM4OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T22:32:03Z", "updated_at": "2020-05-27T22:32:03Z", "author_association": "OWNER", "body": "Request object is now documented: https://datasette.readthedocs.io/en/latest/internals.html#request-object", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 502993509, "label": "Redesign register_output_renderer callback"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/770#issuecomment-634980179", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/770", "id": 634980179, "node_id": "MDEyOklzc3VlQ29tbWVudDYzNDk4MDE3OQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-05-27T22:37:19Z", "updated_at": "2020-05-27T22:37:19Z", "author_association": "OWNER", "body": "Can I come up with a better name than `should_suggest`?\r\n\r\nIt's a check that sees if the current query is supported by the renderer plugin. Some options:\r\n\r\n- `can_render`\r\n- `supports_query`\r\n- `is_supported`\r\n\r\nI like `can_render`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 625930207, "label": "register_output_renderer can_render mechanism"}, "performed_via_github_app": null}