schemathesis: [BUG] starlette 0.21.0 uses httpx testclient

Checklist

Describe the bug starlette==0.21.0 updated to use httpx for the testclient instead of requests.

In particular starlette.testclient.TestClient now inherits httpx.Client.

To Reproduce Use Case.call_asgi(...) in a unit test.

Error:

  File "/mnt/win/work/nightcrawler/tests/schema/lookup/test_txt.py", line 22, in test_txt
    response = case.call_asgi(headers={'Authorization': 'Bearer supersecret'})
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/schemathesis/models.py", line 397, in call_asgi
    return self.call(base_url=base_url, session=client, headers=headers, **kwargs)
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/schemathesis/models.py", line 327, in call
    response = session.request(**data)  # type: ignore
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/starlette/testclient.py", line 448, in request
    return super().request(
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/httpx/_client.py", line 803, in request
    request = self.build_request(
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/httpx/_client.py", line 346, in build_request
    headers = self._merge_headers(headers)
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/httpx/_client.py", line 413, in _merge_headers
    merged_headers.update(headers)
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/httpx/_models.py", line 199, in update
    headers = Headers(headers)
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/httpx/_models.py", line 79, in __init__
    self._list = [
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/httpx/_models.py", line 85, in <listcomp>
    for k, v in headers
ValueError: too many values to unpack (expected 2)
Falsifying example: test_txt(
    case=Case(path_parameters={'domain': 'A.ac'}, headers={'Authorization': 'Bearer '}, query={}),
    self=<tests.schema.lookup.test_txt.TestTXTSchema testMethod=test_txt>,
)

Additional context I forced the headers to be a dict instead of a requests.structures.CaseInsensitiveDict and that furthered the state, but it next up failed with:

  File "/mnt/win/work/nightcrawler/tests/schema/lookup/test_txt.py", line 23, in test_txt
    case.validate_response(response)
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/schemathesis/models.py", line 424, in validate_response
    copied_response = copy_response(response)
  File "/mnt/win/work/nightcrawler/.pyenv/lib/python3.10/site-packages/schemathesis/utils.py", line 279, in copy_response
    response.freeze()
AttributeError: 'Response' object has no attribute 'freeze'
Falsifying example: test_txt(
    case=Case(path_parameters={'domain': 'A.ac'}, headers={'Authorization': 'Bearer '}, query={}),
    self=<tests.schema.lookup.test_txt.TestTXTSchema testMethod=test_txt>,
)

This seems to be caused by now getting a httpx.Response back instead of a requests.Response, and these objects are very different.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 19 (9 by maintainers)

Commits related to this issue

Most upvoted comments

Sorry for the delay!

I ran with the approach suggested by @Kludex and it will be available in the next version soon. However, I’d like to overhaul transports properly as it unblocks a few nice things (like a unified interface to requests/WSGI/ASGI responses and adding more transports in the future, etc). I’ll create a separate issue for that

@Stranger6667 if it is going to take a while to address this issue, in the meantime please can the pyproject.toml be corrected to specify its dependency on the appropriate version of starlette?

https://github.com/schemathesis/schemathesis/blob/master/pyproject.toml#L52 at the moment this is specified as starlette = ">=0.13,<1" which is incorrect, since schemathesis is not compatible with starlette>=0.21. It should be starlette = ">=0.13,<0.21"

@Stranger6667 You can ping me on those issues, I can help.

Please do not restrict the range of versions of Starlette. You can replace the Starlette TestClient by this one: https://github.com/Kludex/starlette-testclient; and I’ve also created this tool to help on the bump: https://github.com/Kludex/bump-testclient.

As a consequence FastAPI >= 0.87.0 is also affected since it uses Starlette >= 0.21.0. So thank you in advance for handling httpx. 🙏

Oh, right. Thank you for opening this issue. I’ll take a look this evening

@tmeckel You’re very welcome! 😃

@Stranger6667 Dammit! So obvious!!! This solved the issue. Thanks for helping!

image

Thank you for sharing the code! I believe you need to pass starlette_client.TestClient instance on line 105, instead of the one from starlette

@tmeckel Could you, please, share the test_api function definition + how you load your schema (schemathesis.from_* call)?

This will take some more time as it requires full support for httpx, so all built-in checks, hooks, the runner integration, etc should be updated.