We have a cookiejar abstraction, I think setting it to an always-empty jar like you describe is best. :)","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717746043,datasette.client internal requests mechanism, https://github.com/simonw/datasette/issues/1001#issuecomment-705905121,https://api.github.com/repos/simonw/datasette/issues/1001,705905121,MDEyOklzc3VlQ29tbWVudDcwNTkwNTEyMQ==,9599,simonw,2020-10-09T01:00:07Z,2020-10-09T01:00:07Z,OWNER,"The www.djangoproject.com site returns an empty page: ``` ~ % curl -vv -XOPTIONS https://www.djangoproject.com/ * Trying 151.101.42.217:443... * Connected to www.djangoproject.com (151.101.42.217) port 443 (#0) * ALPN, offering http/1.1 * TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * Server certificate: osff2.map.fastly.net * Server certificate: GlobalSign CloudSSL CA - SHA256 - G3 * Server certificate: GlobalSign Root CA > OPTIONS / HTTP/1.1 > Host: www.djangoproject.com > User-Agent: curl/7.70.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Connection: keep-alive < Content-Length: 0 < Server: nginx < Content-Type: text/html; charset=utf-8 < Allow: GET, HEAD, OPTIONS < Content-Language: en < X-Frame-Options: SAMEORIGIN < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Strict-Transport-Security: max-age=31536000; includeSubDomains; preload < Access-Control-Allow-Origin: https://code.djangoproject.com < Accept-Ranges: bytes < Date: Fri, 09 Oct 2020 00:59:42 GMT < Via: 1.1 varnish < X-Served-By: cache-sjc10047-SJC < X-Cache: MISS < X-Cache-Hits: 0 < X-Timer: S1602205182.833493,VS0,VE305 < Vary: Accept-Language, Accept-Encoding < * Connection #0 to host www.djangoproject.com left intact ~ % ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717768441,OPTIONS requests return a 500 error, https://github.com/simonw/datasette/pull/1000#issuecomment-705937696,https://api.github.com/repos/simonw/datasette/issues/1000,705937696,MDEyOklzc3VlQ29tbWVudDcwNTkzNzY5Ng==,9599,simonw,2020-10-09T02:52:53Z,2020-10-09T02:52:53Z,OWNER,"These failures are giving me a severe ""how did this ever work in the first place?"" vibe: ``` FAILED tests/test_html.py::test_base_url_config[/fixtures/compound_three_primary_keys-https://example.com/] FAILED tests/test_html.py::test_base_url_config[/fixtures/compound_three_primary_keys/a,a,a-https://example.com/] FAILED tests/test_html.py::test_base_url_config[/fixtures/paginated_view-https://example.com/] FAILED tests/test_html.py::test_base_url_config[/fixtures/facetable-https://example.com/] ``` I have a fix for them, no idea why they weren't already failing though.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717746043,datasette.client internal requests mechanism, https://github.com/simonw/datasette/issues/1006#issuecomment-706270877,https://api.github.com/repos/simonw/datasette/issues/1006,706270877,MDEyOklzc3VlQ29tbWVudDcwNjI3MDg3Nw==,9599,simonw,2020-10-09T16:12:09Z,2020-10-09T16:12:09Z,OWNER,This can become a section on https://docs.datasette.io/en/stable/internals.html,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",718264811,Documentation for datasette.client, https://github.com/simonw/datasette/pull/1000#issuecomment-705940507,https://api.github.com/repos/simonw/datasette/issues/1000,705940507,MDEyOklzc3VlQ29tbWVudDcwNTk0MDUwNw==,9599,simonw,2020-10-09T03:04:15Z,2020-10-09T03:04:15Z,OWNER,"This is really weird: new set of test failures that I wasn't seeing before, and those tests aren't failing on my laptop: ``` =========================== short test summary info ============================ FAILED tests/test_api.py::test_table_with_slashes_in_name - assert 404 == 200 FAILED tests/test_api.py::test_row_strange_table_name - assert 404 == 200 FAILED tests/test_html.py::test_row_strange_table_name_with_url_hash - assert... FAILED tests/test_html.py::test_css_classes_on_body[/fixtures/table%2Fwith%2Fslashes.csv-expected_classes5] FAILED tests/test_html.py::test_templates_considered[/fixtures/table%2Fwith%2Fslashes.csv-table-fixtures-tablewithslashescsv-fa7563.html, *table.html] ================== 5 failed, 738 passed in 194.73s (0:03:14) =================== ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717746043,datasette.client internal requests mechanism, https://github.com/simonw/datasette/issues/1001#issuecomment-705904566,https://api.github.com/repos/simonw/datasette/issues/1001,705904566,MDEyOklzc3VlQ29tbWVudDcwNTkwNDU2Ng==,9599,simonw,2020-10-09T00:58:08Z,2020-10-09T00:58:08Z,OWNER,"To get a traceback: ``` datasette . -p 8009 --pdb ``` And then: ``` curl -XOPTIONS http://127.0.0.1:8009 ``` This causes the server to open a debugging prompt: ``` INFO: 127.0.0.1:59514 - ""OPTIONS / HTTP/1.1"" 500 Internal Server Error > /Users/simon/Dropbox/Development/datasette/datasette/views/base.py(115)dispatch_request() -> return await handler(request, *args, **kwargs) (Pdb) list 110 def database_color(self, database): 111 return ""ff0000"" 112 113 async def dispatch_request(self, request, *args, **kwargs): 114 handler = getattr(self, request.method.lower(), None) 115 -> return await handler(request, *args, **kwargs) 116 117 async def render(self, templates, request, context=None): 118 context = context or {} 119 template = self.ds.jinja_env.select_template(templates) 120 template_context = { (Pdb) ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717768441,OPTIONS requests return a 500 error, https://github.com/simonw/datasette/issues/1001#issuecomment-705904759,https://api.github.com/repos/simonw/datasette/issues/1001,705904759,MDEyOklzc3VlQ29tbWVudDcwNTkwNDc1OQ==,9599,simonw,2020-10-09T00:58:47Z,2020-10-09T00:58:47Z,OWNER,"What should an OPTIONS request return, anyway?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717768441,OPTIONS requests return a 500 error, https://github.com/simonw/datasette/pull/1000#issuecomment-705921006,https://api.github.com/repos/simonw/datasette/issues/1000,705921006,MDEyOklzc3VlQ29tbWVudDcwNTkyMTAwNg==,9599,simonw,2020-10-09T01:55:01Z,2020-10-09T01:55:01Z,OWNER,"With the single client that is reused for all tests: ``` % time pytest tests/test_api.py ... 6.73s user 9.91s system 81% cpu 20.365 total ``` After switching back to this class: ```python class DatasetteClient: def __init__(self, ds): self.app = ds.app() def _fix(self, path): if path.startswith(""/""): path = ""http://localhost{}"".format(path) return path async def get(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.get(self._fix(path), **kwargs) async def options(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.options(self._fix(path), **kwargs) async def head(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.head(self._fix(path), **kwargs) async def post(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.post(self._fix(path), **kwargs) async def put(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.put(self._fix(path), **kwargs) async def patch(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.patch(self._fix(path), **kwargs) async def delete(self, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.delete(self._fix(path), **kwargs) async def request(self, method, path, **kwargs): async with httpx.AsyncClient(app=self.app) as client: return await client.request(method, self._fix(path), **kwargs) ``` The time taken is: ``` % time pytest tests/test_api.py ... 7.26s user 10.02s system 82% cpu 21.014 total ``` That's close enough that I don't feel I need to investigate this further.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",717746043,datasette.client internal requests mechanism, https://github.com/simonw/datasette/issues/1003#issuecomment-706272322,https://api.github.com/repos/simonw/datasette/issues/1003,706272322,MDEyOklzc3VlQ29tbWVudDcwNjI3MjMyMg==,9599,simonw,2020-10-09T16:14:56Z,2020-10-09T16:14:56Z,OWNER,Yes I think that makes sense. I added `json` to the template context in Dogsheep Beta just a few days ago because I needed that: https://github.com/dogsheep/dogsheep-beta/blob/bed9df2b3ef68189e2e445427721a28f4e9b4887/dogsheep_beta/__init__.py#L176,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",718238967,from_json jinja2 filter, https://github.com/simonw/datasette/issues/1001#issuecomment-705904917,https://api.github.com/repos/simonw/datasette/issues/1001,705904917,MDEyOklzc3VlQ29tbWVudDcwNTkwNDkxNw==,9599,simonw,2020-10-09T00:59:25Z,2020-10-09T00:59:25Z,OWNER,"``` ~ % curl -XOPTIONS https://www.google.com/