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/1886#issuecomment-1356842576,https://api.github.com/repos/simonw/datasette/issues/1886,1356842576,IC_kwDOBm6k_c5Q38ZQ,18738650,2022-12-18T17:34:20Z,2022-12-18T17:34:20Z,NONE,"A bit late to this, but I have made an app to publish air quality data in Bristol, UK. [air quality data in Bristol, UK.](https://brisaq-wfzqhmj43q-ew.a.run.app/) Next step to see if I can make a streamlit app based on this to produce some nice charts.","{""total_count"": 1, ""+1"": 1, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1447050738, https://github.com/simonw/datasette/pull/1965#issuecomment-1356827218,https://api.github.com/repos/simonw/datasette/issues/1965,1356827218,IC_kwDOBm6k_c5Q34pS,9599,2022-12-18T16:01:36Z,2022-12-18T16:01:36Z,OWNER,Will link to this from my TIL shortly.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1501843596, https://github.com/simonw/datasette/pull/1965#issuecomment-1356827167,https://api.github.com/repos/simonw/datasette/issues/1965,1356827167,IC_kwDOBm6k_c5Q34of,9599,2022-12-18T16:01:22Z,2022-12-18T16:01:22Z,OWNER,"This is great, thank you!","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1501843596, https://github.com/simonw/datasette/issues/1964#issuecomment-1356697705,https://api.github.com/repos/simonw/datasette/issues/1964,1356697705,IC_kwDOBm6k_c5Q3ZBp,9599,2022-12-18T06:37:23Z,2022-12-18T06:37:23Z,OWNER,"I'm certain the two other cog menus (the app menu on the right of the nav bar and the column action menus) have the same problem. Would be great to figure out the right ARIA attributes for these too.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1501778647, https://github.com/simonw/datasette/issues/1771#issuecomment-1356694671,https://api.github.com/repos/simonw/datasette/issues/1771,1356694671,IC_kwDOBm6k_c5Q3YSP,9599,2022-12-18T06:34:20Z,2022-12-18T06:34:20Z,OWNER,Now live on https://latest.datasette.io/fixtures/attraction_characteristic,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1306984363, https://github.com/simonw/datasette/issues/1771#issuecomment-1356680769,https://api.github.com/repos/simonw/datasette/issues/1771,1356680769,IC_kwDOBm6k_c5Q3U5B,9599,2022-12-18T05:56:05Z,2022-12-18T05:56:05Z,OWNER,"This does the trick: ```css div.select-wrapper:focus-within { border: 1px solid black; } ``` ![tab-select-border-fix](https://user-images.githubusercontent.com/9599/208283826-de48212f-a213-40fc-9b37-9d66f0858f21.gif) ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1306984363, https://github.com/simonw/datasette/issues/1771#issuecomment-1356657451,https://api.github.com/repos/simonw/datasette/issues/1771,1356657451,IC_kwDOBm6k_c5Q3PMr,1473102,2022-12-18T04:04:32Z,2022-12-18T04:04:32Z,NONE,"the problem is: ``` .select-wrapper select:focus { outline: none; } ``` I sometimes add this js: ``` window.addEventListener('keydown', function check_tab(e) { if (e.key === 'Tab') { document.documentElement.classList.add('user-is-tabbing') window.removeEventListener('keydown', check_tab) } }) ``` and then in the css, using a `html.user-is-tabbing` selector undo any outlines I removed.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1306984363, https://github.com/simonw/datasette/issues/1771#issuecomment-1356655630,https://api.github.com/repos/simonw/datasette/issues/1771,1356655630,IC_kwDOBm6k_c5Q3OwO,9599,2022-12-18T03:43:12Z,2022-12-18T03:43:12Z,OWNER,"The border is actually on the div that wraps the select box: I tried adding a `border: 1px dotted black` to `select:focus` but it's not quite right - it jumps around a bit like this: ![Tabbing to the selects shows a 1px border but the element expands in size by one pixel, causing a visual jump](https://user-images.githubusercontent.com/9599/208280271-41a07f68-b8b1-4908-a4e2-aac4304d6c09.gif) ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1306984363, https://github.com/simonw/datasette/issues/1771#issuecomment-1356655217,https://api.github.com/repos/simonw/datasette/issues/1771,1356655217,IC_kwDOBm6k_c5Q3Opx,9599,2022-12-18T03:38:16Z,2022-12-18T03:38:16Z,OWNER,"OK I see what you mean: https://latest.datasette.io/fixtures/attraction_characteristic ![Animated GIF of the table page hitting tab a bunch - the cog icon highlights and so does the text input but the two select boxes do not](https://user-images.githubusercontent.com/9599/208280176-1e2de671-fe69-43e8-8d62-bf7aa8f4d36e.gif) ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1306984363, https://github.com/simonw/datasette/issues/1963#issuecomment-1356652057,https://api.github.com/repos/simonw/datasette/issues/1963,1356652057,IC_kwDOBm6k_c5Q3N4Z,9599,2022-12-18T03:23:22Z,2022-12-18T03:23:22Z,OWNER,https://pypi.org/project/datasette/0.63.3/ is released.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1501713288, https://github.com/simonw/datasette/issues/1963#issuecomment-1356651943,https://api.github.com/repos/simonw/datasette/issues/1963,1356651943,IC_kwDOBm6k_c5Q3N2n,9599,2022-12-18T03:23:03Z,2022-12-18T03:23:03Z,OWNER,"Oh that's annoying... every step in publish succeeded except the static docs one: https://github.com/simonw/datasette/actions/runs/3723015082/jobs/6314292722 This means the documentation database used to update the search engine on https://datasette.io/ won't reflect the very latest changelog. I'm OK with that - I'll fix this workflow so that next time I publish a release this will work correctly.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1501713288, https://github.com/simonw/datasette/issues/1955#issuecomment-1356640463,https://api.github.com/repos/simonw/datasette/issues/1955,1356640463,IC_kwDOBm6k_c5Q3LDP,9599,2022-12-18T02:45:18Z,2022-12-18T02:45:18Z,OWNER,"... and with this change, the following now works correctly: ``` % datasette install datasette-gunicorn % datasette gunicorn fixtures.db -p 8855 [2022-12-17 18:44:29 -0800] [7651] [INFO] Starting gunicorn 20.1.0 [2022-12-17 18:44:29 -0800] [7651] [INFO] Listening at: http://127.0.0.1:8855 (7651) [2022-12-17 18:44:29 -0800] [7651] [INFO] Using worker: uvicorn.workers.UvicornWorker [2022-12-17 18:44:29 -0800] [7653] [INFO] Booting worker with pid: 7653 [2022-12-17 18:44:29 -0800] [7653] [INFO] Started server process [7653] [2022-12-17 18:44:29 -0800] [7653] [INFO] Waiting for application startup. [2022-12-17 18:44:29 -0800] [7653] [INFO] Application startup complete. ``` So this issue is now fixed!","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356640266,https://api.github.com/repos/simonw/datasette/issues/1955,1356640266,IC_kwDOBm6k_c5Q3LAK,9599,2022-12-18T02:43:00Z,2022-12-18T02:43:00Z,OWNER,"https://github.com/simonw/datasette/actions/runs/3722908296/jobs/6314093163 shows that new test passing in CI: ``` Generated a certificate for 'localhost', '127.0.0.1', '::1' Configure your server to use the following files: cert=/home/runner/work/datasette/datasette/server.pem key=/home/runner/work/datasette/datasette/server.key Configure your client to use the following files: cert=/home/runner/work/datasette/datasette/client.pem INFO: Started server process [4036] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on https://127.0.0.1:8152/ (Press CTRL+C to quit) % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed INFO: 127.0.0.1:56726 - ""GET /_memory.json HTTP/1.1"" 200 OK 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 213 0 213 0 0 11542 0 --:--:-- --:--:-- --:--:-- 11833 INFO: Shutting down INFO: Waiting for application shutdown. INFO: Application shutdown complete. INFO: Finished server process [4036] {""database"": ""_memory"", ""private"": false, ""path"": ""/_memory"", ""size"": 0, ""tables"": [], ""hidden_count"": 0, ""views"": [], ""queries"": [], ""allow_execute_sql"": true, ""table_columns"": {}, ""query_ms"": 1.4545189999921604}0 ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1221#issuecomment-1356639873,https://api.github.com/repos/simonw/datasette/issues/1221,1356639873,IC_kwDOBm6k_c5Q3K6B,9599,2022-12-18T02:39:04Z,2022-12-18T02:39:04Z,OWNER,I ended up moving this test out of Python and into a `bash` script here: https://github.com/simonw/datasette/commit/d1d369456a7319b9de39175605568cbc9b852478,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",806849424, https://github.com/simonw/datasette/issues/1955#issuecomment-1356633937,https://api.github.com/repos/simonw/datasette/issues/1955,1356633937,IC_kwDOBm6k_c5Q3JdR,9599,2022-12-18T02:28:22Z,2022-12-18T02:28:22Z,OWNER,"This `bash` script does the job: ```bash #!/bin/bash # Generate certificates python -m trustme # This creates server.pem, server.key, client.pem # Start the server in the background datasette --memory \ --ssl-keyfile=server.key \ --ssl-certfile=server.pem \ -p 8152 & # Store the background process ID in a variable server_pid=$! # Wait for the server to start sleep 2 # Make a test request using curl curl -f --cacert client.pem 'https://localhost:8152/_memory.json' # Save curl's exit code (-f option causes it to return one on HTTP errors) curl_exit_code=$? # Shut down the server kill $server_pid sleep 1 # Clean up the certificates rm server.pem server.key client.pem echo $curl_exit_code exit $curl_exit_code ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356630092,https://api.github.com/repos/simonw/datasette/issues/1955,1356630092,IC_kwDOBm6k_c5Q3IhM,9599,2022-12-18T02:20:01Z,2022-12-18T02:20:01Z,OWNER,"Asked ChatGPT: > Write a bash script which starts a server in the background using ""datasette -p 8002"", then uses curl to make a test request against it, then shuts the server down again at the end It gave me: ```bash #!/bin/bash # Start the server in the background datasette -p 8002 & # Store the background process ID in a variable server_pid=$! # Make a test request using curl curl http://localhost:8002 # Shut down the server kill $server_pid ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356629783,https://api.github.com/repos/simonw/datasette/issues/1955,1356629783,IC_kwDOBm6k_c5Q3IcX,9599,2022-12-18T02:18:43Z,2022-12-18T02:18:43Z,OWNER,"Various attempts at a fix which didn't work: ```diff diff --git a/tests/conftest.py b/tests/conftest.py index 69dee68b..899d36fd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,3 @@ -import asyncio import httpx import os import pathlib @@ -6,6 +5,7 @@ import pytest import pytest_asyncio import re import subprocess +import sys import tempfile import time import trustme @@ -27,13 +27,23 @@ UNDOCUMENTED_PERMISSIONS = { _ds_client = None -def wait_until_responds(url, timeout=5.0, client=httpx, **kwargs): +def wait_until_responds(url, timeout=5.0, client=None, **kwargs): + client = client or httpx.Client(**kwargs) start = time.time() while time.time() - start < timeout: try: - client.get(url, **kwargs) + if ""verify"" in kwargs: + print(kwargs[""verify""]) + print( + ""Contents of verify file: {}"".format( + open(kwargs.get(""verify"")).read() + ) + ) + print(""client = {}, kwargs = {}"".format(client, kwargs)) + client.get(url) return - except httpx.ConnectError: + except (httpx.ConnectError, httpx.RemoteProtocolError) as ex: + print(ex) time.sleep(0.1) raise AssertionError(""Timed out waiting for {} to respond"".format(url)) @@ -166,7 +176,7 @@ def check_permission_actions_are_documented(): @pytest.fixture(scope=""session"") def ds_localhost_http_server(): ds_proc = subprocess.Popen( - [""datasette"", ""--memory"", ""-p"", ""8041""], + [sys.executable, ""-m"", ""datasette"", ""--memory"", ""-p"", ""8041""], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # Avoid FileNotFoundError: [Errno 2] No such file or directory: @@ -180,7 +190,7 @@ def ds_localhost_http_server(): ds_proc.terminate() -@pytest.fixture(scope=""session"") +@pytest.fixture def ds_localhost_https_server(tmp_path_factory): cert_directory = tmp_path_factory.mktemp(""certs"") ca = trustme.CA() @@ -194,6 +204,8 @@ def ds_localhost_https_server(tmp_path_factory): ca.cert_pem.write_to_path(path=client_cert) ds_proc = subprocess.Popen( [ + sys.executable, + ""-m"", ""datasette"", ""--memory"", ""-p"", @@ -207,7 +219,11 @@ def ds_localhost_https_server(tmp_path_factory): stderr=subprocess.STDOUT, cwd=tempfile.gettempdir(), ) - wait_until_responds(""http://localhost:8042/"", verify=client_cert) + wait_until_responds( + ""http://localhost:8042/_memory.json"", + verify=client_cert, + headers={""Connection"": ""close""}, + ) # Check it started successfully assert not ds_proc.poll(), ds_proc.stdout.read().decode(""utf-8"") yield ds_proc, client_cert diff --git a/tests/test_cli_serve_server.py b/tests/test_cli_serve_server.py index 1c31e2a3..9320b623 100644 --- a/tests/test_cli_serve_server.py +++ b/tests/test_cli_serve_server.py @@ -16,7 +16,11 @@ def test_serve_localhost_http(ds_localhost_http_server): @pytest.mark.serial def test_serve_localhost_https(ds_localhost_https_server): _, client_cert = ds_localhost_https_server - response = httpx.get(""https://localhost:8042/_memory.json"", verify=client_cert) + response = httpx.get( + ""https://localhost:8042/_memory.json"", + verify=client_cert, + headers={""Connection"": ""close""}, + ) assert { ""database"": ""_memory"", ""path"": ""/_memory"", ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356627931,https://api.github.com/repos/simonw/datasette/issues/1955,1356627931,IC_kwDOBm6k_c5Q3H_b,9599,2022-12-18T02:13:01Z,2022-12-18T02:13:01Z,OWNER,"Rather than continue to bang my head against this, I'm tempted to rewrite this test to happen outside of Python world - in a bash script run by GitHub Actions, for example.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356627331,https://api.github.com/repos/simonw/datasette/issues/1955,1356627331,IC_kwDOBm6k_c5Q3H2D,9599,2022-12-18T02:11:17Z,2022-12-18T02:11:17Z,OWNER,"This issue might be relevant, but I tried the suggested fix in there (`Connection: close` on the incoming requests) and it didn't fix my problem: - https://github.com/encode/httpx/discussions/2056","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356626334,https://api.github.com/repos/simonw/datasette/issues/1955,1356626334,IC_kwDOBm6k_c5Q3Hme,9599,2022-12-18T02:04:01Z,2022-12-18T02:04:07Z,OWNER,"I used the steps to test manually from this comment: https://github.com/simonw/datasette/issues/1221#issuecomment-777901052 In one terminal: ``` cd /tmp python -m trustme datasette --memory --ssl-keyfile=/tmp/server.key --ssl-certfile=/tmp/server.pem -p 8003 ``` Then in another terminal: ``` curl --cacert /tmp/client.pem 'https://localhost:8003/_memory.json' ``` This worked correctly, outputting the expected JSON. So the feature still works, it's just the test that is broken for some reason.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356625642,https://api.github.com/repos/simonw/datasette/issues/1955,1356625642,IC_kwDOBm6k_c5Q3Hbq,9599,2022-12-18T02:00:57Z,2022-12-18T02:00:57Z,OWNER,"I added the TLS support here: - https://github.com/simonw/datasette/issues/1221","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356625556,https://api.github.com/repos/simonw/datasette/issues/1955,1356625556,IC_kwDOBm6k_c5Q3HaU,9599,2022-12-18T02:00:18Z,2022-12-18T02:00:18Z,OWNER,Maybe the reason the ASGI lifespan stuff broke was this line: https://github.com/simonw/datasette/blob/8b73fc6b47dffd8836f5c58aae1e57c1f66a5754/datasette/cli.py#L630-L632,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356620233,https://api.github.com/repos/simonw/datasette/issues/1955,1356620233,IC_kwDOBm6k_c5Q3GHJ,9599,2022-12-18T01:31:10Z,2022-12-18T01:31:10Z,OWNER,"During the polling loop it constantly raises: `httpx.RemoteProtocolError`: Server disconnected without sending a response","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356618913,https://api.github.com/repos/simonw/datasette/issues/1955,1356618913,IC_kwDOBm6k_c5Q3Fyh,9599,2022-12-18T01:29:05Z,2022-12-18T01:29:05Z,OWNER,"Now the only failure is in the `https` test - which fails like this (in CI and on my laptop): ``` message = str(exc) > raise mapped_exc(message) from exc E httpx.RemoteProtocolError: Server disconnected without sending a response. /opt/hostedtoolcache/Python/3.11.1/x64/lib/python3.11/site-packages/httpx/_transports/default.py:77: RemoteProtocolError =========================== short test summary info ============================ ERROR tests/test_cli_serve_server.py::test_serve_localhost_https - httpx.RemoteProtocolError: Server disconnected without sending a response. ================= 30 passed, 1264 deselected, 1 error in 6.15s ================= ``` That's this test: https://github.com/simonw/datasette/blob/63fb750f39cac6f49b451387fdff659ecd9edc5c/tests/test_cli_serve_server.py#L16-L24 And this fixture: https://github.com/simonw/datasette/blob/63fb750f39cac6f49b451387fdff659ecd9edc5c/tests/conftest.py#L178-L215 ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356610089,https://api.github.com/repos/simonw/datasette/issues/1955,1356610089,IC_kwDOBm6k_c5Q3Dop,9599,2022-12-18T01:12:39Z,2022-12-18T01:12:39Z,OWNER,"... and it turns out those tests saved me. Because I forgot to check if `datasette` would actually start a server correctly! ``` % datasette fixtures.db -p 8852 INFO: Started server process [3538] INFO: Waiting for application startup. ERROR: Exception in 'lifespan' protocol Traceback (most recent call last): File ""/Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/uvicorn/lifespan/on.py"", line 86, in main await app(scope, self.receive, self.send) File ""/Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py"", line 78, in __call__ return await self.app(scope, receive, send) File ""/Users/simon/Dropbox/Development/datasette/datasette/utils/asgi.py"", line 437, in __call__ return await self.asgi(scope, receive, send) File ""/Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/asgi_csrf.py"", line 39, in app_wrapped_with_csrf await app(scope, receive, send) File ""/Users/simon/Dropbox/Development/datasette/datasette/app.py"", line 1457, in __call__ path = scope[""path""] KeyError: 'path' ERROR: Application startup failed. Exiting. ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356609095,https://api.github.com/repos/simonw/datasette/issues/1955,1356609095,IC_kwDOBm6k_c5Q3DZH,9599,2022-12-18T01:10:43Z,2022-12-18T01:10:43Z,OWNER,"Improved version of that fixture: ```diff diff --git a/tests/conftest.py b/tests/conftest.py index 44c44f87..69dee68b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,6 +27,17 @@ UNDOCUMENTED_PERMISSIONS = { _ds_client = None +def wait_until_responds(url, timeout=5.0, client=httpx, **kwargs): + start = time.time() + while time.time() - start < timeout: + try: + client.get(url, **kwargs) + return + except httpx.ConnectError: + time.sleep(0.1) + raise AssertionError(""Timed out waiting for {} to respond"".format(url)) + + @pytest_asyncio.fixture async def ds_client(): from datasette.app import Datasette @@ -161,13 +172,7 @@ def ds_localhost_http_server(): # Avoid FileNotFoundError: [Errno 2] No such file or directory: cwd=tempfile.gettempdir(), ) - # Loop until port 8041 serves traffic - while True: - try: - httpx.get(""http://localhost:8041/"") - break - except httpx.ConnectError: - time.sleep(0.1) + wait_until_responds(""http://localhost:8041/"") # Check it started successfully assert not ds_proc.poll(), ds_proc.stdout.read().decode(""utf-8"") yield ds_proc @@ -202,12 +207,7 @@ def ds_localhost_https_server(tmp_path_factory): stderr=subprocess.STDOUT, cwd=tempfile.gettempdir(), ) - while True: - try: - httpx.get(""https://localhost:8042/"", verify=client_cert) - break - except httpx.ConnectError: - time.sleep(0.1) + wait_until_responds(""http://localhost:8042/"", verify=client_cert) # Check it started successfully assert not ds_proc.poll(), ds_proc.stdout.read().decode(""utf-8"") yield ds_proc, client_cert @@ -231,12 +231,7 @@ def ds_unix_domain_socket_server(tmp_path_factory): # Poll until available transport = httpx.HTTPTransport(uds=uds) client = httpx.Client(transport=transport) - while True: - try: - client.get(""http://localhost/_memory.json"") - break - except httpx.ConnectError: - time.sleep(0.1) + wait_until_responds(""http://localhost/_memory.json"", client=client) # Check it started successfully assert not ds_proc.poll(), ds_proc.stdout.read().decode(""utf-8"") yield ds_proc, uds ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356600917,https://api.github.com/repos/simonw/datasette/issues/1955,1356600917,IC_kwDOBm6k_c5Q3BZV,9599,2022-12-18T01:02:26Z,2022-12-18T01:02:26Z,OWNER,"This bit here looks like it could hang! ```python # Loop until port 8041 serves traffic while True: try: httpx.get(""http://localhost:8041/"") break except httpx.ConnectError: time.sleep(0.1) ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356599930,https://api.github.com/repos/simonw/datasette/issues/1955,1356599930,IC_kwDOBm6k_c5Q3BJ6,9599,2022-12-18T01:01:47Z,2022-12-18T01:01:47Z,OWNER,"I think that's this test: https://github.com/simonw/datasette/blob/63fb750f39cac6f49b451387fdff659ecd9edc5c/tests/test_cli_serve_server.py#L6-L13 Using this fixture: https://github.com/simonw/datasette/blob/63fb750f39cac6f49b451387fdff659ecd9edc5c/tests/conftest.py#L155-L175","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356596740,https://api.github.com/repos/simonw/datasette/issues/1955,1356596740,IC_kwDOBm6k_c5Q3AYE,9599,2022-12-18T00:59:47Z,2022-12-18T00:59:47Z,OWNER,"Hitting `Ctrl+C` while using `--full-trace` gave me more clues: ``` % pytest -m serial tests/test_cli_serve_server.py --full-trace ======================================================= test session starts ======================================================== platform darwin -- Python 3.10.3, pytest-7.1.3, pluggy-1.0.0 SQLite: 3.39.4 rootdir: /Users/simon/Dropbox/Development/datasette, configfile: pytest.ini plugins: anyio-3.6.1, xdist-2.5.0, forked-1.4.0, asyncio-0.19.0, timeout-2.1.0, profiling-1.7.0 asyncio: mode=strict collected 3 items tests/test_cli_serve_server.py ^C^C ====================================================== no tests ran in 3.49s ======================================================= Traceback (most recent call last): File ""/Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/httpcore/_exceptions.py"", line 8, in map_exceptions yield File ""/Users/simon/.local/share/virtualenvs/datasette-AWNrQs95/lib/python3.10/site-packages/httpcore/backends/sync.py"", line 86, in connect_tcp sock = socket.create_connection( File ""/Users/simon/.pyenv/versions/3.10.3/lib/python3.10/socket.py"", line 845, in create_connection raise err File ""/Users/simon/.pyenv/versions/3.10.3/lib/python3.10/socket.py"", line 833, in create_connection sock.connect(sa) ConnectionRefusedError: [Errno 61] Connection refused [...] ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622, https://github.com/simonw/datasette/issues/1955#issuecomment-1356595665,https://api.github.com/repos/simonw/datasette/issues/1955,1356595665,IC_kwDOBm6k_c5Q3AHR,9599,2022-12-18T00:58:16Z,2022-12-18T00:58:16Z,OWNER,"`pytest -m serial` on my Mac laptop also freezes: ``` (datasette) datasette % pytest -m serial ======================================================= test session starts ======================================================== platform darwin -- Python 3.10.3, pytest-7.1.3, pluggy-1.0.0 SQLite: 3.39.4 rootdir: /Users/simon/Dropbox/Development/datasette, configfile: pytest.ini plugins: anyio-3.6.1, xdist-2.5.0, forked-1.4.0, asyncio-0.19.0, timeout-2.1.0, profiling-1.7.0 asyncio: mode=strict collected 1295 items / 1264 deselected / 31 selected tests/test_package.py . [ 3%] tests/test_cli_serve_server.py ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1496652622,