id,node_id,number,title,user,state,locked,assignee,milestone,comments,created_at,updated_at,closed_at,author_association,pull_request,body,repo,type,active_lock_reason,performed_via_github_app,reactions,draft,state_reason
1646068413,I_kwDOBm6k_c5iHQK9,2048,Test failures encountered while packaging for GNU Guix,8332263,open,0,,,0,2023-03-29T15:36:54Z,2023-03-29T15:36:54Z,,NONE,,"Hello,

While reviewing a packaged submitted to Guix to add `datasette`, the test suite produces the following errors:
```
=================================== FAILURES ===================================
_________________________ test_row_strange_table_name __________________________
[gw21] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffef099be0>

    def test_row_strange_table_name(app_client):
        response = app_client.get(
            ""/fixtures/table~2Fwith~2Fslashes~2Ecsv/3.json?_shape=objects""
        )
>       assert response.status == 200
E       assert 400 == 200
E        +  where 400 = <datasette.utils.testing.TestResponse object at 0x7fffef236a30>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:701: AssertionError
----------------------------- Captured stderr call -----------------------------
ERROR: conn=<sqlite3.Connection object at 0x7fffeedfe5d0>, sql = 'select rowid, * from [table%7E2Fwith%7E2Fslashes%7E2Ecsv] where ""rowid""=:p0', params = {'p0': '3'}: no such table: table%7E2Fwith%7E2Fslashes%7E2Ecsv
_______________ test_database_page_for_database_with_dot_in_name _______________
[gw15] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_with_dot = <datasette.utils.testing.TestClient object at 0x7fffef3416a0>

    def test_database_page_for_database_with_dot_in_name(app_client_with_dot):
        response = app_client_with_dot.get(""/fixtures~2Edot.json"")
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffef089fa0>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:633: AssertionError
___________________ test_tilde_encoded_database_names[fo%o] ____________________
[gw6] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

db_name = 'fo%o'

    @pytest.mark.asyncio
    @pytest.mark.parametrize(""db_name"", (""foo"", r""fo%o"", ""f~/c.d""))
    async def test_tilde_encoded_database_names(db_name):
        ds = Datasette()
        ds.add_memory_database(db_name)
        response = await ds.client.get(""/.json"")
        assert db_name in response.json().keys()
        path = response.json()[db_name][""path""]
        # And the JSON for that database
        response2 = await ds.client.get(path + "".json"")
>       assert response2.status_code == 200
E       assert 302 == 200
E        +  where 302 = <Response [302 Found]>.status_code

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:983: AssertionError
__________________ test_tilde_encoded_database_names[f~/c.d] ___________________
[gw7] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

db_name = 'f~/c.d'

    @pytest.mark.asyncio
    @pytest.mark.parametrize(""db_name"", (""foo"", r""fo%o"", ""f~/c.d""))
    async def test_tilde_encoded_database_names(db_name):
        ds = Datasette()
        ds.add_memory_database(db_name)
        response = await ds.client.get(""/.json"")
        assert db_name in response.json().keys()
        path = response.json()[db_name][""path""]
        # And the JSON for that database
        response2 = await ds.client.get(path + "".json"")
>       assert response2.status_code == 200
E       assert 302 == 200
E        +  where 302 = <Response [302 Found]>.status_code

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:983: AssertionError
______________ test_database_with_space_in_name[/searchable.json] ______________
[gw21] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_two_attached_databases = <datasette.utils.testing.TestClient object at 0x7fffef11d730>
path = '/searchable.json'

    @pytest.mark.parametrize(
        ""path"",
        (
            ""/"",
            "".json"",
            ""/searchable"",
            ""/searchable.json"",
            ""/searchable_view"",
            ""/searchable_view.json"",
        ),
    )
    def test_database_with_space_in_name(app_client_two_attached_databases, path):
>       response = app_client_two_attached_databases.get(
            ""/extra~20database"" + path, follow_redirects=True
        )

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:920: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:223: in __call__
    return call_result.result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:438: in result
    return self.__get_result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:390: in __get_result
    raise self._exception
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:292: in main_wrap
    result = await self.awaitable(*args, **kwargs)
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:66: in get
    return await self._request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:156: in _request
    httpx_response = await self.ds.client.request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/app.py:1602: in request
    return await client.request(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1527: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1614: in send
    response = await self._send_handling_auth(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1642: in _send_handling_auth
    response = await self._send_handling_redirects(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpx.AsyncClient object at 0x7fffef11d940>
request = <Request('GET', 'http://localhost/extra%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E20database/searchable%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E2Ejson')>
follow_redirects = True
history = [<Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, ...]

    async def _send_handling_redirects(
        self,
        request: Request,
        follow_redirects: bool,
        history: typing.List[Response],
    ) -> Response:
        while True:
            if len(history) > self.max_redirects:
>               raise TooManyRedirects(
                    ""Exceeded maximum allowed redirects."", request=request
                )
E               httpx.TooManyRedirects: Exceeded maximum allowed redirects.

/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1672: TooManyRedirects
___________________ test_database_with_space_in_name[.json] ____________________
[gw19] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_two_attached_databases = <datasette.utils.testing.TestClient object at 0x7fffef085a90>
path = '.json'

    @pytest.mark.parametrize(
        ""path"",
        (
            ""/"",
            "".json"",
            ""/searchable"",
            ""/searchable.json"",
            ""/searchable_view"",
            ""/searchable_view.json"",
        ),
    )
    def test_database_with_space_in_name(app_client_two_attached_databases, path):
>       response = app_client_two_attached_databases.get(
            ""/extra~20database"" + path, follow_redirects=True
        )

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:920: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:223: in __call__
    return call_result.result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:438: in result
    return self.__get_result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:390: in __get_result
    raise self._exception
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:292: in main_wrap
    result = await self.awaitable(*args, **kwargs)
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:66: in get
    return await self._request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:156: in _request
    httpx_response = await self.ds.client.request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/app.py:1602: in request
    return await client.request(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1527: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1614: in send
    response = await self._send_handling_auth(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1642: in _send_handling_auth
    response = await self._send_handling_redirects(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpx.AsyncClient object at 0x7fffecd99ca0>
request = <Request('GET', 'http://localhost/extra%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E20database%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E2Ejson')>
follow_redirects = True
history = [<Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, ...]

    async def _send_handling_redirects(
        self,
        request: Request,
        follow_redirects: bool,
        history: typing.List[Response],
    ) -> Response:
        while True:
            if len(history) > self.max_redirects:
>               raise TooManyRedirects(
                    ""Exceeded maximum allowed redirects."", request=request
                )
E               httpx.TooManyRedirects: Exceeded maximum allowed redirects.

/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1672: TooManyRedirects
______________ test_database_with_space_in_name[/searchable_view] ______________
[gw22] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_two_attached_databases = <datasette.utils.testing.TestClient object at 0x7fffeeab4c70>
path = '/searchable_view'

    @pytest.mark.parametrize(
        ""path"",
        (
            ""/"",
            "".json"",
            ""/searchable"",
            ""/searchable.json"",
            ""/searchable_view"",
            ""/searchable_view.json"",
        ),
    )
    def test_database_with_space_in_name(app_client_two_attached_databases, path):
>       response = app_client_two_attached_databases.get(
            ""/extra~20database"" + path, follow_redirects=True
        )

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:920: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:223: in __call__
    return call_result.result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:438: in result
    return self.__get_result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:390: in __get_result
    raise self._exception
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:292: in main_wrap
    result = await self.awaitable(*args, **kwargs)
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:66: in get
    return await self._request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:156: in _request
    httpx_response = await self.ds.client.request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/app.py:1602: in request
    return await client.request(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1527: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1614: in send
    response = await self._send_handling_auth(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1642: in _send_handling_auth
    response = await self._send_handling_redirects(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpx.AsyncClient object at 0x7fffec5b3580>
request = <Request('GET', 'http://localhost/extra%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E20database/searchable_view')>
follow_redirects = True
history = [<Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, ...]

    async def _send_handling_redirects(
        self,
        request: Request,
        follow_redirects: bool,
        history: typing.List[Response],
    ) -> Response:
        while True:
            if len(history) > self.max_redirects:
>               raise TooManyRedirects(
                    ""Exceeded maximum allowed redirects."", request=request
                )
E               httpx.TooManyRedirects: Exceeded maximum allowed redirects.

/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1672: TooManyRedirects
_____________________ test_database_with_space_in_name[/] ______________________
[gw18] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_two_attached_databases = <datasette.utils.testing.TestClient object at 0x7fffef085be0>
path = '/'

    @pytest.mark.parametrize(
        ""path"",
        (
            ""/"",
            "".json"",
            ""/searchable"",
            ""/searchable.json"",
            ""/searchable_view"",
            ""/searchable_view.json"",
        ),
    )
    def test_database_with_space_in_name(app_client_two_attached_databases, path):
>       response = app_client_two_attached_databases.get(
            ""/extra~20database"" + path, follow_redirects=True
        )

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:920: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:223: in __call__
    return call_result.result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:438: in result
    return self.__get_result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:390: in __get_result
    raise self._exception
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:292: in main_wrap
    result = await self.awaitable(*args, **kwargs)
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:66: in get
    return await self._request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:156: in _request
    httpx_response = await self.ds.client.request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/app.py:1602: in request
    return await client.request(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1527: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1614: in send
    response = await self._send_handling_auth(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1642: in _send_handling_auth
    response = await self._send_handling_redirects(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpx.AsyncClient object at 0x7fffec5f1370>
request = <Request('GET', 'http://localhost/extra%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E20database/')>
follow_redirects = True
history = [<Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, ...]

    async def _send_handling_redirects(
        self,
        request: Request,
        follow_redirects: bool,
        history: typing.List[Response],
    ) -> Response:
        while True:
            if len(history) > self.max_redirects:
>               raise TooManyRedirects(
                    ""Exceeded maximum allowed redirects."", request=request
                )
E               httpx.TooManyRedirects: Exceeded maximum allowed redirects.

/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1672: TooManyRedirects
________________ test_database_with_space_in_name[/searchable] _________________
[gw20] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_two_attached_databases = <datasette.utils.testing.TestClient object at 0x7fffef099f10>
path = '/searchable'

    @pytest.mark.parametrize(
        ""path"",
        (
            ""/"",
            "".json"",
            ""/searchable"",
            ""/searchable.json"",
            ""/searchable_view"",
            ""/searchable_view.json"",
        ),
    )
    def test_database_with_space_in_name(app_client_two_attached_databases, path):
>       response = app_client_two_attached_databases.get(
            ""/extra~20database"" + path, follow_redirects=True
        )

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:920: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:223: in __call__
    return call_result.result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:438: in result
    return self.__get_result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:390: in __get_result
    raise self._exception
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:292: in main_wrap
    result = await self.awaitable(*args, **kwargs)
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:66: in get
    return await self._request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:156: in _request
    httpx_response = await self.ds.client.request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/app.py:1602: in request
    return await client.request(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1527: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1614: in send
    response = await self._send_handling_auth(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1642: in _send_handling_auth
    response = await self._send_handling_redirects(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpx.AsyncClient object at 0x7fffecd8c790>
request = <Request('GET', 'http://localhost/extra%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E20database/searchable')>
follow_redirects = True
history = [<Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, ...]

    async def _send_handling_redirects(
        self,
        request: Request,
        follow_redirects: bool,
        history: typing.List[Response],
    ) -> Response:
        while True:
            if len(history) > self.max_redirects:
>               raise TooManyRedirects(
                    ""Exceeded maximum allowed redirects."", request=request
                )
E               httpx.TooManyRedirects: Exceeded maximum allowed redirects.

/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1672: TooManyRedirects
___________ test_database_with_space_in_name[/searchable_view.json] ____________
[gw23] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client_two_attached_databases = <datasette.utils.testing.TestClient object at 0x7fffef341520>
path = '/searchable_view.json'

    @pytest.mark.parametrize(
        ""path"",
        (
            ""/"",
            "".json"",
            ""/searchable"",
            ""/searchable.json"",
            ""/searchable_view"",
            ""/searchable_view.json"",
        ),
    )
    def test_database_with_space_in_name(app_client_two_attached_databases, path):
>       response = app_client_two_attached_databases.get(
            ""/extra~20database"" + path, follow_redirects=True
        )

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_api.py:920: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:223: in __call__
    return call_result.result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:438: in result
    return self.__get_result()
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/concurrent/futures/_base.py:390: in __get_result
    raise self._exception
/gnu/store/mcclmphjgbrgpa0v037a4nlq336482g8-python-asgiref-3.4.1/lib/python3.9/site-packages/asgiref/sync.py:292: in main_wrap
    result = await self.awaitable(*args, **kwargs)
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:66: in get
    return await self._request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:156: in _request
    httpx_response = await self.ds.client.request(
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/app.py:1602: in request
    return await client.request(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1527: in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1614: in send
    response = await self._send_handling_auth(
/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1642: in _send_handling_auth
    response = await self._send_handling_redirects(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <httpx.AsyncClient object at 0x7fffef085460>
request = <Request('GET', 'http://localhost/extra%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E20database/searchable_view%7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E2Ejson')>
follow_redirects = True
history = [<Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, <Response [302 Found]>, ...]

    async def _send_handling_redirects(
        self,
        request: Request,
        follow_redirects: bool,
        history: typing.List[Response],
    ) -> Response:
        while True:
            if len(history) > self.max_redirects:
>               raise TooManyRedirects(
                    ""Exceeded maximum allowed redirects."", request=request
                )
E               httpx.TooManyRedirects: Exceeded maximum allowed redirects.

/gnu/store/bj5lb299rfb4cbbq5kczq9imdk9a7y64-python-httpx-0.23.0/lib/python3.9/site-packages/httpx/_client.py:1672: TooManyRedirects
________________ test_weird_database_names[database (1).sqlite] ________________
[gw7] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

tmpdir = local('/tmp/guix-build-datasette-0.64.2.drv-0/pytest-of-nixbld/pytest-0/popen-gw7/test_weird_database_names_data0')
filename = 'database (1).sqlite'

    @pytest.mark.parametrize(
        ""filename"", [""test-database (1).sqlite"", ""database (1).sqlite""]
    )
    def test_weird_database_names(tmpdir, filename):
        # https://github.com/simonw/datasette/issues/1181
        runner = CliRunner()
        db_path = str(tmpdir / filename)
        sqlite3.connect(db_path).execute(""vacuum"")
        result1 = runner.invoke(cli, [db_path, ""--get"", ""/""])
        assert result1.exit_code == 0, result1.output
        filename_no_stem = filename.rsplit(""."", 1)[0]
        expected_link = '<a href=""/{}"">{}</a>'.format(
            tilde_encode(filename_no_stem), filename_no_stem
        )
        assert expected_link in result1.output
        # Now try hitting that database page
        result2 = runner.invoke(
            cli, [db_path, ""--get"", ""/{}"".format(tilde_encode(filename_no_stem))]
        )
>       assert result2.exit_code == 0, result2.output
E       AssertionError: 
E         
E       assert 1 == 0
E        +  where 1 = <Result SystemExit(1)>.exit_code

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_cli.py:321: AssertionError
_____________ test_weird_database_names[test-database (1).sqlite] ______________
[gw6] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

tmpdir = local('/tmp/guix-build-datasette-0.64.2.drv-0/pytest-of-nixbld/pytest-0/popen-gw6/test_weird_database_names_test0')
filename = 'test-database (1).sqlite'

    @pytest.mark.parametrize(
        ""filename"", [""test-database (1).sqlite"", ""database (1).sqlite""]
    )
    def test_weird_database_names(tmpdir, filename):
        # https://github.com/simonw/datasette/issues/1181
        runner = CliRunner()
        db_path = str(tmpdir / filename)
        sqlite3.connect(db_path).execute(""vacuum"")
        result1 = runner.invoke(cli, [db_path, ""--get"", ""/""])
        assert result1.exit_code == 0, result1.output
        filename_no_stem = filename.rsplit(""."", 1)[0]
        expected_link = '<a href=""/{}"">{}</a>'.format(
            tilde_encode(filename_no_stem), filename_no_stem
        )
        assert expected_link in result1.output
        # Now try hitting that database page
        result2 = runner.invoke(
            cli, [db_path, ""--get"", ""/{}"".format(tilde_encode(filename_no_stem))]
        )
>       assert result2.exit_code == 0, result2.output
E       AssertionError: 
E         
E       assert 1 == 0
E        +  where 1 = <Result SystemExit(1)>.exit_code

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_cli.py:321: AssertionError
_ test_row_html_compound_primary_key[/fixtures/compound_primary_key/a~2Fb,~2Ec~2Dd-expected1] _
[gw11] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffec2d37f0>
path = '/fixtures/compound_primary_key/a~2Fb,~2Ec~2Dd'
expected = [['<td class=""col-pk1 type-str"">a/b</td>', '<td class=""col-pk2 type-str"">.c-d</td>', '<td class=""col-content type-str"">c</td>']]

    @pytest.mark.parametrize(
        ""path,expected"",
        (
            (
                ""/fixtures/compound_primary_key/a,b"",
                [
                    [
                        '<td class=""col-pk1 type-str"">a</td>',
                        '<td class=""col-pk2 type-str"">b</td>',
                        '<td class=""col-content type-str"">c</td>',
                    ]
                ],
            ),
            (
                ""/fixtures/compound_primary_key/a~2Fb,~2Ec~2Dd"",
                [
                    [
                        '<td class=""col-pk1 type-str"">a/b</td>',
                        '<td class=""col-pk2 type-str"">.c-d</td>',
                        '<td class=""col-content type-str"">c</td>',
                    ]
                ],
            ),
        ),
    )
    def test_row_html_compound_primary_key(app_client, path, expected):
        response = app_client.get(path)
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffd47c23a0>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_html.py:370: AssertionError
_ test_css_classes_on_body[/fixtures/table~2Fwith~2Fslashes~2Ecsv-expected_classes5] _
[gw3] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffd4743fa0>
path = '/fixtures/table~2Fwith~2Fslashes~2Ecsv'
expected_classes = ['table', 'db-fixtures', 'table-tablewithslashescsv-fa7563']

    @pytest.mark.parametrize(
        ""path,expected_classes"",
        [
            (""/"", [""index""]),
            (""/fixtures"", [""db"", ""db-fixtures""]),
            (""/fixtures?sql=select+1"", [""query"", ""db-fixtures""]),
            (
                ""/fixtures/simple_primary_key"",
                [""table"", ""db-fixtures"", ""table-simple_primary_key""],
            ),
            (
                ""/fixtures/neighborhood_search"",
                [""query"", ""db-fixtures"", ""query-neighborhood_search""],
            ),
            (
                ""/fixtures/table~2Fwith~2Fslashes~2Ecsv"",
                [""table"", ""db-fixtures"", ""table-tablewithslashescsv-fa7563""],
            ),
            (
                ""/fixtures/simple_primary_key/1"",
                [""row"", ""db-fixtures"", ""table-simple_primary_key""],
            ),
        ],
    )
    def test_css_classes_on_body(app_client, path, expected_classes):
        response = app_client.get(path)
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffd4628dc0>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_html.py:238: AssertionError
_ test_templates_considered[/fixtures/table~2Fwith~2Fslashes~2Ecsv-table-fixtures-tablewithslashescsv-fa7563.html, *table.html] _
[gw3] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffd4743fa0>
path = '/fixtures/table~2Fwith~2Fslashes~2Ecsv'
expected_considered = 'table-fixtures-tablewithslashescsv-fa7563.html, *table.html'

    @pytest.mark.parametrize(
        ""path,expected_considered"",
        [
            (""/"", ""*index.html""),
            (""/fixtures"", ""database-fixtures.html, *database.html""),
            (
                ""/fixtures/simple_primary_key"",
                ""table-fixtures-simple_primary_key.html, *table.html"",
            ),
            (
                ""/fixtures/table~2Fwith~2Fslashes~2Ecsv"",
                ""table-fixtures-tablewithslashescsv-fa7563.html, *table.html"",
            ),
            (
                ""/fixtures/simple_primary_key/1"",
                ""row-fixtures-simple_primary_key.html, *row.html"",
            ),
        ],
    )
    def test_templates_considered(app_client, path, expected_considered):
        response = app_client.get(path)
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffd44f2d60>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_html.py:264: AssertionError
_ test_alternate_url_json[/fixtures/table~2Fwith~2Fslashes~2Ecsv-http://localhost/fixtures/table~2Fwith~2Fslashes~2Ecsv.json] _
[gw21] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffecd9fac0>
path = '/fixtures/table~2Fwith~2Fslashes~2Ecsv'
expected = 'http://localhost/fixtures/table~2Fwith~2Fslashes~2Ecsv.json'

    @pytest.mark.parametrize(
        ""path,expected"",
        (
            # Instance index page
            (""/"", ""http://localhost/.json""),
            # Table page
            (""/fixtures/facetable"", ""http://localhost/fixtures/facetable.json""),
            (
                ""/fixtures/table~2Fwith~2Fslashes~2Ecsv"",
                ""http://localhost/fixtures/table~2Fwith~2Fslashes~2Ecsv.json"",
            ),
            # Row page
            (
                ""/fixtures/no_primary_key/1"",
                ""http://localhost/fixtures/no_primary_key/1.json"",
            ),
            # Database index page
            (
                ""/fixtures"",
                ""http://localhost/fixtures.json"",
            ),
            # Custom query page
            (
                ""/fixtures?sql=select+*+from+facetable"",
                ""http://localhost/fixtures.json?sql=select+*+from+facetable"",
            ),
            # Canned query page
            (
                ""/fixtures/neighborhood_search?text=town"",
                ""http://localhost/fixtures/neighborhood_search.json?text=town"",
            ),
            # /-/ pages
            (
                ""/-/plugins"",
                ""http://localhost/-/plugins.json"",
            ),
        ),
    )
    def test_alternate_url_json(app_client, path, expected):
        response = app_client.get(path)
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffd4650b80>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_html.py:948: AssertionError
_ test_edit_sql_link_on_canned_queries[/fixtures/~F0~9D~90~9C~F0~9D~90~A2~F0~9D~90~AD~F0~9D~90~A2~F0~9D~90~9E~F0~9D~90~AC-/fixtures?sql=select+id%2C+name+from+facet_cities+order+by+id+limit+1%3B] _
[gw18] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffec5952e0>
path = '/fixtures/~F0~9D~90~9C~F0~9D~90~A2~F0~9D~90~AD~F0~9D~90~A2~F0~9D~90~9E~F0~9D~90~AC'
expected = '/fixtures?sql=select+id%2C+name+from+facet_cities+order+by+id+limit+1%3B'

    @pytest.mark.parametrize(
        ""path,expected"",
        [
            (
                ""/fixtures/neighborhood_search"",
                ""/fixtures?sql=%0Aselect+_neighborhood%2C+facet_cities.name%2C+state%0Afrom+facetable%0A++++join+facet_cities%0A++++++++on+facetable._city_id+%3D+facet_cities.id%0Awhere+_neighborhood+like+%27%25%27+%7C%7C+%3Atext+%7C%7C+%27%25%27%0Aorder+by+_neighborhood%3B%0A&amp;text="",
            ),
            (
                ""/fixtures/neighborhood_search?text=ber"",
                ""/fixtures?sql=%0Aselect+_neighborhood%2C+facet_cities.name%2C+state%0Afrom+facetable%0A++++join+facet_cities%0A++++++++on+facetable._city_id+%3D+facet_cities.id%0Awhere+_neighborhood+like+%27%25%27+%7C%7C+%3Atext+%7C%7C+%27%25%27%0Aorder+by+_neighborhood%3B%0A&amp;text=ber"",
            ),
            (""/fixtures/pragma_cache_size"", None),
            (
                # /fixtures/𝐜𝐢𝐭𝐢𝐞𝐬
                ""/fixtures/~F0~9D~90~9C~F0~9D~90~A2~F0~9D~90~AD~F0~9D~90~A2~F0~9D~90~9E~F0~9D~90~AC"",
                ""/fixtures?sql=select+id%2C+name+from+facet_cities+order+by+id+limit+1%3B"",
            ),
            (""/fixtures/magic_parameters"", None),
        ],
    )
    def test_edit_sql_link_on_canned_queries(app_client, path, expected):
        response = app_client.get(path)
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffec4a6f70>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_html.py:841: AssertionError
_______________________ test_table_with_slashes_in_name ________________________
[gw9] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffec0860a0>

    def test_table_with_slashes_in_name(app_client):
        response = app_client.get(
            ""/fixtures/table~2Fwith~2Fslashes~2Ecsv.json?_shape=objects""
        )
>       assert response.status == 200
E       assert 302 == 200
E        +  where 302 = <datasette.utils.testing.TestResponse object at 0x7fffec086fa0>.status

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_table_api.py:141: AssertionError
__________________ test_custom_query_with_unicode_characters ___________________
[gw8] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffec1cda90>

    def test_custom_query_with_unicode_characters(app_client):
        # /fixtures/𝐜𝐢𝐭𝐢𝐞𝐬.json
        response = app_client.get(
            ""/fixtures/~F0~9D~90~9C~F0~9D~90~A2~F0~9D~90~AD~F0~9D~90~A2~F0~9D~90~9E~F0~9D~90~AC.json?_shape=array""
        )
>       assert [{""id"": 1, ""name"": ""San Francisco""}] == response.json

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_table_api.py:1042: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/tmp/guix-build-datasette-0.64.2.drv-0/source/datasette/utils/testing.py:40: in json
    return json.loads(self.text)
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/json/__init__.py:346: in loads
    return _default_decoder.decode(s)
/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/json/decoder.py:337: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <json.decoder.JSONDecoder object at 0x7ffff7479760>, s = '', idx = 0

    def raw_decode(self, s, idx=0):
        """"""Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """"""
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError(""Expecting value"", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

/gnu/store/65i3nhcwmz0p8rqbg48gaavyky4g4hwk-python-3.9.9/lib/python3.9/json/decoder.py:355: JSONDecodeError
_ test_searchable[/fixtures/searchable.json?_search=te*+AND+do*&_searchmode=raw-expected_rows3] _
[gw13] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

app_client = <datasette.utils.testing.TestClient object at 0x7fffd470bf10>
path = '/fixtures/searchable.json?_search=te*+AND+do*&_searchmode=raw'
expected_rows = [[1, 'barry cat', 'terry dog', 'panther'], [2, 'terry dog', 'sara weasel', 'puma']]

    @pytest.mark.parametrize(
        ""path,expected_rows"",
        [
            (
                ""/fixtures/searchable.json?_search=dog"",
                [
                    [1, ""barry cat"", ""terry dog"", ""panther""],
                    [2, ""terry dog"", ""sara weasel"", ""puma""],
                ],
            ),
            (
                # Special keyword shouldn't break FTS query
                ""/fixtures/searchable.json?_search=AND"",
                [],
            ),
            (
                # Without _searchmode=raw this should return no results
                ""/fixtures/searchable.json?_search=te*+AND+do*"",
                [],
            ),
            (
                # _searchmode=raw
                ""/fixtures/searchable.json?_search=te*+AND+do*&_searchmode=raw"",
                [
                    [1, ""barry cat"", ""terry dog"", ""panther""],
                    [2, ""terry dog"", ""sara weasel"", ""puma""],
                ],
            ),
            (
                # _searchmode=raw combined with _search_COLUMN
                ""/fixtures/searchable.json?_search_text2=te*&_searchmode=raw"",
                [
                    [1, ""barry cat"", ""terry dog"", ""panther""],
                ],
            ),
            (
                ""/fixtures/searchable.json?_search=weasel"",
                [[2, ""terry dog"", ""sara weasel"", ""puma""]],
            ),
            (
                ""/fixtures/searchable.json?_search_text2=dog"",
                [[1, ""barry cat"", ""terry dog"", ""panther""]],
            ),
            (
                ""/fixtures/searchable.json?_search_name%20with%20.%20and%20spaces=panther"",
                [[1, ""barry cat"", ""terry dog"", ""panther""]],
            ),
        ],
    )
    def test_searchable(app_client, path, expected_rows):
        response = app_client.get(path)
>       assert expected_rows == response.json[""rows""]
E       AssertionError: assert [[1, 'barry cat', 'terry dog', 'panther'],\n [2, 'terry dog', 'sara weasel', 'puma']] == []
E         Left contains 2 more items, first extra item: [1, 'barry cat', 'terry dog', 'panther']
E         Full diff:
E           [
E         -  ,
E         +  [1,
E         +   'barry cat',
E         +   'terry dog',
E         +   'panther'],
E         +  [2,
E         +   'terry dog',
E         +   'sara weasel',
E         +   'puma'],
E           ]

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_table_api.py:402: AssertionError
_____ test_searchmode[table_metadata1-_search=te*+AND+do*-expected_rows1] ______
[gw20] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

table_metadata = {'searchmode': 'raw'}, querystring = '_search=te*+AND+do*'
expected_rows = [[1, 'barry cat', 'terry dog', 'panther'], [2, 'terry dog', 'sara weasel', 'puma']]

    @pytest.mark.parametrize(
        ""table_metadata,querystring,expected_rows"",
        [
            (
                {},
                ""_search=te*+AND+do*"",
                [],
            ),
            (
                {""searchmode"": ""raw""},
                ""_search=te*+AND+do*"",
                _SEARCHMODE_RAW_RESULTS,
            ),
            (
                {},
                ""_search=te*+AND+do*&_searchmode=raw"",
                _SEARCHMODE_RAW_RESULTS,
            ),
            # Can be over-ridden with _searchmode=escaped
            (
                {""searchmode"": ""raw""},
                ""_search=te*+AND+do*&_searchmode=escaped"",
                [],
            ),
        ],
    )
    def test_searchmode(table_metadata, querystring, expected_rows):
        with make_app_client(
            metadata={""databases"": {""fixtures"": {""tables"": {""searchable"": table_metadata}}}}
        ) as client:
            response = client.get(""/fixtures/searchable.json?"" + querystring)
>           assert expected_rows == response.json[""rows""]
E           AssertionError: assert [[1, 'barry cat', 'terry dog', 'panther'],\n [2, 'terry dog', 'sara weasel', 'puma']] == []
E             Left contains 2 more items, first extra item: [1, 'barry cat', 'terry dog', 'panther']
E             Full diff:
E               [
E             -  ,
E             +  [1,
E             +   'barry cat',
E             +   'terry dog',
E             +   'panther'],
E             +  [2,
E             +   'terry dog',
E             +   'sara weasel',
E             +   'puma'],
E               ]

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_table_api.py:442: AssertionError
_ test_searchmode[table_metadata2-_search=te*+AND+do*&_searchmode=raw-expected_rows2] _
[gw20] linux -- Python 3.9.9 /gnu/store/slsh0qjv5j68xda2bb6h8gsxwyi1j25a-python-wrapper-3.9.9/bin/python

table_metadata = {}, querystring = '_search=te*+AND+do*&_searchmode=raw'
expected_rows = [[1, 'barry cat', 'terry dog', 'panther'], [2, 'terry dog', 'sara weasel', 'puma']]

    @pytest.mark.parametrize(
        ""table_metadata,querystring,expected_rows"",
        [
            (
                {},
                ""_search=te*+AND+do*"",
                [],
            ),
            (
                {""searchmode"": ""raw""},
                ""_search=te*+AND+do*"",
                _SEARCHMODE_RAW_RESULTS,
            ),
            (
                {},
                ""_search=te*+AND+do*&_searchmode=raw"",
                _SEARCHMODE_RAW_RESULTS,
            ),
            # Can be over-ridden with _searchmode=escaped
            (
                {""searchmode"": ""raw""},
                ""_search=te*+AND+do*&_searchmode=escaped"",
                [],
            ),
        ],
    )
    def test_searchmode(table_metadata, querystring, expected_rows):
        with make_app_client(
            metadata={""databases"": {""fixtures"": {""tables"": {""searchable"": table_metadata}}}}
        ) as client:
            response = client.get(""/fixtures/searchable.json?"" + querystring)
>           assert expected_rows == response.json[""rows""]
E           AssertionError: assert [[1, 'barry cat', 'terry dog', 'panther'],\n [2, 'terry dog', 'sara weasel', 'puma']] == []
E             Left contains 2 more items, first extra item: [1, 'barry cat', 'terry dog', 'panther']
E             Full diff:
E               [
E             -  ,
E             +  [1,
E             +   'barry cat',
E             +   'terry dog',
E             +   'panther'],
E             +  [2,
E             +   'terry dog',
E             +   'sara weasel',
E             +   'puma'],
E               ]

/tmp/guix-build-datasette-0.64.2.drv-0/source/tests/test_table_api.py:442: AssertionError
=========================== short test summary info ============================
FAILED tests/test_api.py::test_row_strange_table_name - assert 400 == 200
FAILED tests/test_api.py::test_database_page_for_database_with_dot_in_name - ...
FAILED tests/test_api.py::test_tilde_encoded_database_names[fo%o] - assert 30...
FAILED tests/test_api.py::test_tilde_encoded_database_names[f~/c.d] - assert ...
FAILED tests/test_api.py::test_database_with_space_in_name[/searchable.json]
FAILED tests/test_api.py::test_database_with_space_in_name[.json] - httpx.Too...
FAILED tests/test_api.py::test_database_with_space_in_name[/searchable_view]
FAILED tests/test_api.py::test_database_with_space_in_name[/] - httpx.TooMany...
FAILED tests/test_api.py::test_database_with_space_in_name[/searchable] - htt...
FAILED tests/test_api.py::test_database_with_space_in_name[/searchable_view.json]
FAILED tests/test_cli.py::test_weird_database_names[database (1).sqlite] - As...
FAILED tests/test_cli.py::test_weird_database_names[test-database (1).sqlite]
FAILED tests/test_html.py::test_row_html_compound_primary_key[/fixtures/compound_primary_key/a~2Fb,~2Ec~2Dd-expected1]
FAILED tests/test_html.py::test_css_classes_on_body[/fixtures/table~2Fwith~2Fslashes~2Ecsv-expected_classes5]
FAILED tests/test_html.py::test_templates_considered[/fixtures/table~2Fwith~2Fslashes~2Ecsv-table-fixtures-tablewithslashescsv-fa7563.html, *table.html]
FAILED tests/test_html.py::test_alternate_url_json[/fixtures/table~2Fwith~2Fslashes~2Ecsv-http://localhost/fixtures/table~2Fwith~2Fslashes~2Ecsv.json]
FAILED tests/test_html.py::test_edit_sql_link_on_canned_queries[/fixtures/~F0~9D~90~9C~F0~9D~90~A2~F0~9D~90~AD~F0~9D~90~A2~F0~9D~90~9E~F0~9D~90~AC-/fixtures?sql=select+id%2C+name+from+facet_cities+order+by+id+limit+1%3B]
FAILED tests/test_table_api.py::test_table_with_slashes_in_name - assert 302 ...
FAILED tests/test_table_api.py::test_custom_query_with_unicode_characters - j...
FAILED tests/test_table_api.py::test_searchable[/fixtures/searchable.json?_search=te*+AND+do*&_searchmode=raw-expected_rows3]
FAILED tests/test_table_api.py::test_searchmode[table_metadata1-_search=te*+AND+do*-expected_rows1]
FAILED tests/test_table_api.py::test_searchmode[table_metadata2-_search=te*+AND+do*&_searchmode=raw-expected_rows2]
=========== 22 failed, 1049 passed, 3 skipped in 1522.28s (0:25:22) ============
error: in phase 'check': uncaught exception:
%exception #<&invoke-error program: ""/gnu/store/ziqwkzz6znb5d3c245xn0cq5ra2ly0w3-python-pytest-7.1.3/bin/pytest"" arguments: (""-vv"" ""-n"" ""24"" ""-m"" ""not serial"") exit-status: 1 term-signal: #f stop-signal: #f> 
phase `check' failed after 1523.3 seconds
```
The tests run in a private namespace without internet connectivity, and the Python dependencies are at:
```
python-aiofiles@0.6.0 python-asgi-csrf@0.9 python-asgiref@3.4.1
+ python-beautifulsoup4@4.11.1 python-black@22.3.0 python-click-default-group@1.2.2 python-click@8.1.3
+ python-cogapp@3.3.0 python-httpx@0.23.0 python-hupper@1.10.3 python-itsdangerous@2.0.1
+ python-janus@1.0.0 python-jinja2@3.1.1 python-mergedeep@1.3.4 python-pint@0.20.1 python-pluggy@1.0.0
+ python-pytest-asyncio@0.17.2 python-pytest-runner@5.2 python-pytest-timeout@2.0.2
+ python-pytest-xdist@2.5.0 python-pytest@7.1.3 python-pyyaml@6.0 python-setuptools@64.0.3
+ python-trustme@0.9.0 python-uvicorn@0.17.6
```
With Python 3.9.9.

Thank you!",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/2048/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,
1645098678,PR_kwDOBm6k_c5NIQri,2047,Bump black from 22.12.0 to 23.3.0,49699333,closed,0,,,0,2023-03-29T06:09:06Z,2023-03-29T06:12:21Z,2023-03-29T06:12:05Z,CONTRIBUTOR,simonw/datasette/pulls/2047,"Bumps [black](https://github.com/psf/black) from 22.12.0 to 23.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href=""https://github.com/psf/black/releases"">black's releases</a>.</em></p>
<blockquote>
<h2>23.3.0</h2>
<h3>Highlights</h3>
<p>This release fixes a longstanding confusing behavior in Black's GitHub action, where the
version of the action did not determine the version of Black being run (issue <a href=""https://redirect.github.com/psf/black/issues/3382"">#3382</a>). In
addition, there is a small bug fix around imports and a number of improvements to the
preview style.</p>
<p>Please try out the
<a href=""https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html#preview-style"">preview style</a>
with <code>black --preview</code> and tell us your feedback. All changes in the preview style are
expected to become part of Black's stable style in January 2024.</p>
<h3>Stable style</h3>
<ul>
<li>Import lines with <code># fmt: skip</code> and <code># fmt: off</code> no longer have an extra blank line
added when they are right after another import line (<a href=""https://redirect.github.com/psf/black/issues/3610"">#3610</a>)</li>
</ul>
<h3>Preview style</h3>
<ul>
<li>Add trailing commas to collection literals even if there's a comment after the last
entry (<a href=""https://redirect.github.com/psf/black/issues/3393"">#3393</a>)</li>
<li><code>async def</code>, <code>async for</code>, and <code>async with</code> statements are now formatted consistently
compared to their non-async version. (<a href=""https://redirect.github.com/psf/black/issues/3609"">#3609</a>)</li>
<li><code>with</code> statements that contain two context managers will be consistently wrapped in
parentheses (<a href=""https://redirect.github.com/psf/black/issues/3589"">#3589</a>)</li>
<li>Let string splitters respect <a href=""https://www.unicode.org/reports/tr11/"">East Asian Width</a>
(<a href=""https://redirect.github.com/psf/black/issues/3445"">#3445</a>)</li>
<li>Now long string literals can be split after East Asian commas and periods (<code>、</code> U+3001
IDEOGRAPHIC COMMA, <code>。</code> U+3002 IDEOGRAPHIC FULL STOP, &amp; <code>,</code> U+FF0C FULLWIDTH COMMA)
besides before spaces (<a href=""https://redirect.github.com/psf/black/issues/3445"">#3445</a>)</li>
<li>For stubs, enforce one blank line after a nested class with a body other than just
<code>...</code> (<a href=""https://redirect.github.com/psf/black/issues/3564"">#3564</a>)</li>
<li>Improve handling of multiline strings by changing line split behavior (<a href=""https://redirect.github.com/psf/black/issues/1879"">#1879</a>)</li>
</ul>
<h3>Parser</h3>
<ul>
<li>Added support for formatting files with invalid type comments (<a href=""https://redirect.github.com/psf/black/issues/3594"">#3594</a>)</li>
</ul>
<h3>Integrations</h3>
<ul>
<li>Update GitHub Action to use the version of Black equivalent to action's version if
version input is not specified (<a href=""https://redirect.github.com/psf/black/issues/3543"">#3543</a>)</li>
<li>Fix missing Python binary path in autoload script for vim (<a href=""https://redirect.github.com/psf/black/issues/3508"">#3508</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document that only the most recent release is supported for security issues;
vulnerabilities should be reported through Tidelift (<a href=""https://redirect.github.com/psf/black/issues/3612"">#3612</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href=""https://github.com/psf/black/blob/main/CHANGES.md"">black's changelog</a>.</em></p>
<blockquote>
<h2>23.3.0</h2>
<h3>Highlights</h3>
<p>This release fixes a longstanding confusing behavior in Black's GitHub action, where the
version of the action did not determine the version of Black being run (issue <a href=""https://redirect.github.com/psf/black/issues/3382"">#3382</a>). In
addition, there is a small bug fix around imports and a number of improvements to the
preview style.</p>
<p>Please try out the
<a href=""https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html#preview-style"">preview style</a>
with <code>black --preview</code> and tell us your feedback. All changes in the preview style are
expected to become part of Black's stable style in January 2024.</p>
<h3>Stable style</h3>
<ul>
<li>Import lines with <code># fmt: skip</code> and <code># fmt: off</code> no longer have an extra blank line
added when they are right after another import line (<a href=""https://redirect.github.com/psf/black/issues/3610"">#3610</a>)</li>
</ul>
<h3>Preview style</h3>
<ul>
<li>Add trailing commas to collection literals even if there's a comment after the last
entry (<a href=""https://redirect.github.com/psf/black/issues/3393"">#3393</a>)</li>
<li><code>async def</code>, <code>async for</code>, and <code>async with</code> statements are now formatted consistently
compared to their non-async version. (<a href=""https://redirect.github.com/psf/black/issues/3609"">#3609</a>)</li>
<li><code>with</code> statements that contain two context managers will be consistently wrapped in
parentheses (<a href=""https://redirect.github.com/psf/black/issues/3589"">#3589</a>)</li>
<li>Let string splitters respect <a href=""https://www.unicode.org/reports/tr11/"">East Asian Width</a>
(<a href=""https://redirect.github.com/psf/black/issues/3445"">#3445</a>)</li>
<li>Now long string literals can be split after East Asian commas and periods (<code>、</code> U+3001
IDEOGRAPHIC COMMA, <code>。</code> U+3002 IDEOGRAPHIC FULL STOP, &amp; <code>,</code> U+FF0C FULLWIDTH COMMA)
besides before spaces (<a href=""https://redirect.github.com/psf/black/issues/3445"">#3445</a>)</li>
<li>For stubs, enforce one blank line after a nested class with a body other than just
<code>...</code> (<a href=""https://redirect.github.com/psf/black/issues/3564"">#3564</a>)</li>
<li>Improve handling of multiline strings by changing line split behavior (<a href=""https://redirect.github.com/psf/black/issues/1879"">#1879</a>)</li>
</ul>
<h3>Parser</h3>
<ul>
<li>Added support for formatting files with invalid type comments (<a href=""https://redirect.github.com/psf/black/issues/3594"">#3594</a>)</li>
</ul>
<h3>Integrations</h3>
<ul>
<li>Update GitHub Action to use the version of Black equivalent to action's version if
version input is not specified (<a href=""https://redirect.github.com/psf/black/issues/3543"">#3543</a>)</li>
<li>Fix missing Python binary path in autoload script for vim (<a href=""https://redirect.github.com/psf/black/issues/3508"">#3508</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document that only the most recent release is supported for security issues;
vulnerabilities should be reported through Tidelift (<a href=""https://redirect.github.com/psf/black/issues/3612"">#3612</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href=""https://github.com/psf/black/commit/bf7a16254ec96b084a6caf3d435ec18f0f245cc7""><code>bf7a162</code></a> Fixup the changelog (<a href=""https://redirect.github.com/psf/black/issues/3628"">#3628</a>)</li>
<li><a href=""https://github.com/psf/black/commit/9b2b048692f0bd642f38230b4e61c778a4653f91""><code>9b2b048</code></a> Prepare release 23.3.0 (<a href=""https://redirect.github.com/psf/black/issues/3625"">#3625</a>)</li>
<li><a href=""https://github.com/psf/black/commit/bf5abdb0b6cf6644628977230736a0a6478c1bff""><code>bf5abdb</code></a> Specify Python exec path with minor version if available (<a href=""https://redirect.github.com/psf/black/issues/3508"">#3508</a>)</li>
<li><a href=""https://github.com/psf/black/commit/b542f589a5c4041f54847591104cd51684849f2e""><code>b542f58</code></a> Use GH action version when version argument not specified (<a href=""https://redirect.github.com/psf/black/issues/3543"">#3543</a>)</li>
<li><a href=""https://github.com/psf/black/commit/f3b1a3b9d2fc6de8f0845399cb80d8bdfd6400fd""><code>f3b1a3b</code></a> Bump furo from 2022.12.7 to 2023.3.23 in /docs (<a href=""https://redirect.github.com/psf/black/issues/3624"">#3624</a>)</li>
<li><a href=""https://github.com/psf/black/commit/ef6e079901d53a42dfae4ab10b081ce7a73a47b5""><code>ef6e079</code></a> Let string splitters respect <code>East_Asian_Width</code> property (<a href=""https://redirect.github.com/psf/black/issues/3445"">#3445</a>)</li>
<li><a href=""https://github.com/psf/black/commit/5c064a986c388e2be1e448c3e4b28e5f5ba7ce5a""><code>5c064a9</code></a> Bump sphinx from 5.3.0 to 6.1.3 in /docs (<a href=""https://redirect.github.com/psf/black/issues/3499"">#3499</a>)</li>
<li><a href=""https://github.com/psf/black/commit/3a9d6f0a5f9013b97676f3d24246bd34d93fce4c""><code>3a9d6f0</code></a> Bump myst-parser from 0.18.1 to 1.0.0 in /docs (<a href=""https://redirect.github.com/psf/black/issues/3601"">#3601</a>)</li>
<li><a href=""https://github.com/psf/black/commit/53c23e62df9b182edf9e7ccf726acdcf8c25846f""><code>53c23e6</code></a> Support files with type comment syntax errors (<a href=""https://redirect.github.com/psf/black/issues/3594"">#3594</a>)</li>
<li><a href=""https://github.com/psf/black/commit/dba3c2695c59fdb11825dbdf8f3b0ab6e0b368b2""><code>dba3c26</code></a> Fix bug introduced in <a href=""https://redirect.github.com/psf/black/issues/3564"">#3564</a>. (<a href=""https://redirect.github.com/psf/black/issues/3615"">#3615</a>)</li>
<li>Additional commits viewable in <a href=""https://github.com/psf/black/compare/22.12.0...23.3.0"">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=black&package-manager=pip&previous-version=22.12.0&new-version=23.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

<!-- readthedocs-preview datasette start -->
----
:books: Documentation preview :books:: https://datasette--2047.org.readthedocs.build/en/2047/

<!-- readthedocs-preview datasette end -->",107914493,pull,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/2047/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",0,