html_url,issue_url,id,node_id,user,created_at,updated_at,author_association,body,reactions,issue,performed_via_github_app
https://github.com/simonw/datasette/issues/1809#issuecomment-1249990033,https://api.github.com/repos/simonw/datasette/issues/1809,1249990033,IC_kwDOBm6k_c5KgVWR,9599,2022-09-17T03:39:05Z,2022-09-17T03:39:05Z,OWNER,New docs section on the need to call `await ds.invoke_startup()`: https://github.com/simonw/datasette/blob/ddc999ad1296e8c69cffede3e367dda059b8adad/docs/testing_plugins.rst#setting-up-a-datasette-test-instance,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1249987643,https://api.github.com/repos/simonw/datasette/issues/1809,1249987643,IC_kwDOBm6k_c5KgUw7,9599,2022-09-17T03:19:24Z,2022-09-17T03:19:24Z,OWNER,"In looking at the documentation on [writing tests](https://docs.datasette.io/en/latest/testing_plugins.html), there are a lot of examples like this:
```python
def test_that_opens_the_debugger_or_errors():
ds = Datasette([db_path], pdb=True)
response = await ds.client.get(""/"")
```
I really don't like having to tell people to add `await ds.invoke_startup()` to every test that might look like this.
Since it's safe to call that function multiple times, I'm going to have `ds.client.get()` and friends call it for you too - so if you forget in a plugin test it won't matter.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1249986079,https://api.github.com/repos/simonw/datasette/issues/1809,1249986079,IC_kwDOBm6k_c5KgUYf,9599,2022-09-17T03:07:24Z,2022-09-17T03:07:24Z,OWNER,"Datasette's own tests started to break because calls to the `TestClient` were performed without awaiting that method. I fixed that by adding this to `_request()` inside that class:
```python
async def _request(
self,
path,
follow_redirects=True,
redirect_count=0,
method=""GET"",
cookies=None,
headers=None,
post_body=None,
content_type=None,
if_none_match=None,
):
if not self.ds._startup_invoked:
await self.ds.invoke_startup()
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1249985971,https://api.github.com/repos/simonw/datasette/issues/1809,1249985971,IC_kwDOBm6k_c5KgUWz,9599,2022-09-17T03:06:32Z,2022-09-17T03:06:32Z,OWNER,"This is likely going to cause some tests in plugins to break, but I'm OK with that - I'll fix them as I find them once this release is out.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1249985741,https://api.github.com/repos/simonw/datasette/issues/1809,1249985741,IC_kwDOBm6k_c5KgUTN,9599,2022-09-17T03:04:51Z,2022-09-17T03:04:51Z,OWNER,I'm going to throw an error in `ds.render_template()` if you haven't previously called `await ds.invoke_startup()`.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1247317941,https://api.github.com/repos/simonw/datasette/issues/1809,1247317941,IC_kwDOBm6k_c5KWI-1,9599,2022-09-14T21:24:43Z,2022-09-14T21:24:43Z,OWNER,"It looks like Datasette Lite does NOT invoke that method, which is likely a bug: https://github.com/simonw/datasette-lite/blob/e7ccaf621b3cdf613ebaf544304d387f2af32edf/webworker.js#L103-L110","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1247316715,https://api.github.com/repos/simonw/datasette/issues/1809,1247316715,IC_kwDOBm6k_c5KWIrr,9599,2022-09-14T21:23:10Z,2022-09-14T21:23:10Z,OWNER,It might be good to have Datasette LOUDLY fail if you attempt to use it without calling `await ds.invoke_startup()`.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1247316097,https://api.github.com/repos/simonw/datasette/issues/1809,1247316097,IC_kwDOBm6k_c5KWIiB,9599,2022-09-14T21:22:24Z,2022-09-14T21:22:24Z,OWNER,"It looks like this is the only place that calls `invoke_startup()`: https://github.com/simonw/datasette/blob/1d64c9a8dac45b9a3452acf8e76dfadea2b0bc49/datasette/cli.py#L590-L591
`datasette-publish-vercel` is the one deployment mechanism that skips running Uvicorn, and it calls that method separately here: https://github.com/simonw/datasette-publish-vercel/blob/1559d979b4e3b1f2f83c51c3c0c10192ff9a6d0c/datasette_publish_vercel/__init__.py#L42-L52
```python
ds = Datasette(
[],
{database_files},
static_mounts=static_mounts,
metadata=metadata{extras},
secret=secret,
cors=True,
settings={settings}{crossdb}
)
asyncio.run(ds.invoke_startup())
app = ds.app()
```
So preparing the Jinja environment inside that function would work fine.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1247314352,https://api.github.com/repos/simonw/datasette/issues/1809,1247314352,IC_kwDOBm6k_c5KWIGw,9599,2022-09-14T21:20:12Z,2022-09-14T21:20:12Z,OWNER,"The reason to support `await_me_maybe` is in case a hook wants to execute a SQL query as part of configuring the Jinja template loader.
That's exactly what `datasette-edit-templates` needs to do, though it's currently achieving that in a `startup()` hook instead: https://github.com/simonw/datasette-edit-templates/blob/087f6a6cabc20020f2b0524f11aa3a7836320848/datasette_edit_templates/__init__.py#L32-L48
```python
@hookimpl
def startup(datasette):
datasette._edit_templates = {}
async def inner():
db = get_database(datasette)
# Does the table exist?
if not await db.table_exists(TABLE):
for sql in CREATE_TABLE:
await db.execute_write(sql, block=True)
else:
# Load all templates from that table
rows = await db.execute(""select template, body FROM {}"".format(TABLE))
for name, content in rows:
datasette._edit_templates[name] = content
return inner
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1247313134,https://api.github.com/repos/simonw/datasette/issues/1809,1247313134,IC_kwDOBm6k_c5KWHzu,9599,2022-09-14T21:18:46Z,2022-09-14T21:18:46Z,OWNER,"`await_me_maybe` might be tricky though, because the only place that hook is executed is here:
https://github.com/simonw/datasette/blob/8430c3bc7dd22b173c1a8c6cd7180e3b31240cd1/datasette/app.py#L348
Which is inside the `Datasette.__init__` method.
To implement an `await` on that would need to move it somewhere else - probably here: https://github.com/simonw/datasette/blob/8430c3bc7dd22b173c1a8c6cd7180e3b31240cd1/datasette/app.py#L391-L393
But I'm not 100% confident that is always executed at the right time to ensure the Jinja environment is properly configured? I think it is, but would need to make sure.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,
https://github.com/simonw/datasette/issues/1809#issuecomment-1247311275,https://api.github.com/repos/simonw/datasette/issues/1809,1247311275,IC_kwDOBm6k_c5KWHWr,9599,2022-09-14T21:16:32Z,2022-09-14T21:16:32Z,OWNER,It should also implement the `await_me_maybe` pattern so you can return an `async` function from it.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1373595927,