question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ResponseNotRead when attempting to access response data through respx.calls

See original GitHub issue

I’m working on mocking an api client I’ve written using httpx which manipulates the data before returning it, and I can’t seem to get the raw content from the request (before the manipulation). I’ve reconstructed what the client does, with cookies, headers, etc, to demonstrate the issue still happens with httpbin.org.

As you can see, the request.content is read (it’s none, so an empty byte-string is expected), but the response is readable from httpx, but not respx.

Due to the api client construction, I don’t immediately have access to the raw request (i.e. httpx.get(...) or client.get(...)), and I was hoping the mock would store the content in a retrievable format when passing through.

Note: Although not demonstrated here, this also happens with text and json().

Am I doing something wrong or are my expectations misplaced?

Versions:

  • respx (07ca910)
  • httpx (0.7.6)

Demo:

class TestGetContent:
    @respx.mock
    def test_get_content(self, mc_client):
        respx.get("https://httpbin.org/json", pass_through=True)
        base_url = httpx.URL("https://httpbin.org")
        cookies = httpx.Cookies()
        cookies.set(
            name="a_cookie", value="value", domain="httpbin.org",
        )
        headers = httpx.Headers(
            {"User-Agent": "my-python-client/0.0.7.dev0", "X-Auth": "auth_value"}
        )
        timeout = httpx.config.TimeoutConfig(timeout=300)
        c = httpx.Client(base_url=base_url, cookies=cookies, headers=headers, timeout=timeout)
        response = c.get("json")
        print(f"response.text={response.text}\n===")
        print(f"response.json()={response.json()}\n===")
        print(f"response.content={response.content}\n===")
        for req, resp in respx.calls:
            print(f"respx request.content={req.content}\n---")
            print(f"respx response.content={resp.content}\n---")

PyTest Result:

>           print(f"respx response.content={resp.content}\n---")

tests/test_content.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Response [200 OK]>

    @property
    def content(self) -> bytes:
        if not hasattr(self, "_content"):
            if hasattr(self, "_raw_content"):
                raw_content = self._raw_content  # type: ignore
                content = self.decoder.decode(raw_content)
                content += self.decoder.flush()
                self._content = content
            else:
>               raise ResponseNotRead()
E               httpx.exceptions.ResponseNotRead

../../../Library/Caches/pypoetry/virtualenvs/test-py3.7/lib/python3.7/site-packages/httpx/models.py:816: ResponseNotRead
--------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------
response.text={
  "slideshow": {
    "author": "Yours Truly", 
    "date": "date of publication", 
    "slides": [
      {
        "title": "Wake up to WonderWidgets!", 
        "type": "all"
      }, 
      {
        "items": [
          "Why <em>WonderWidgets</em> are great", 
          "Who <em>buys</em> WonderWidgets"
        ], 
        "title": "Overview", 
        "type": "all"
      }
    ], 
    "title": "Sample Slide Show"
  }
}

===
response.json()={'slideshow': {'author': 'Yours Truly', 'date': 'date of publication', 'slides': [{'title': 'Wake up to WonderWidgets!', 'type': 'all'}, {'items': ['Why <em>WonderWidgets</em> are great', 'Who <em>buys</em> WonderWidgets'], 'title': 'Overview', 'type': 'all'}], 'title': 'Sample Slide Show'}}
===
response.content=b'{\n  "slideshow": {\n    "author": "Yours Truly", \n    "date": "date of publication", \n    "slides": [\n      {\n        "title": "Wake up to WonderWidgets!", \n        "type": "all"\n      }, \n      {\n        "items": [\n          "Why <em>WonderWidgets</em> are great", \n          "Who <em>buys</em> WonderWidgets"\n        ], \n        "title": "Overview", \n        "type": "all"\n      }\n    ], \n    "title": "Sample Slide Show"\n  }\n}\n'
===
respx request.content=b''
---

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
StephenBrown2commented, Nov 20, 2019

Yup, looks like it does! Thanks for the quick work on that.

0reactions
lundbergcommented, Nov 20, 2019

I’ve finally found the cause of this issue!

RESPX patches BaseClient._get_response which both sync and async clients use. Problem is that in this stage, the response is still async due to internal dispatch logic in HTTPX.

The PR #23 should solve this, by earlier individual patching in both sync and async clients.

Thanks for raising this issue @StephenBrown2 ! Please try the PR in your use case, before I merge.

Read more comments on GitHub >

github_iconTop Results From Across the Web

User Guide - RESPX
RESPX is a mock router, capturing requests sent by HTTPX , mocking their responses. Inspired by the flexible query API of the Django...
Read more >
How can I mock requests and the response? - python
this solution works great with the GET request. I am trying to generalise it for POST and PUT but cannot understand, how I...
Read more >
respx - PyPI
A utility for mocking out the Python HTTPX library. Usage. For starters, you need to mock HTTPX , by using the RESPX decorator...
Read more >
How to use the respx.get function in respx - Snyk
Use Snyk Code to scan source code in minutes - no build needed - and fix issues ... assert request.called is True assert...
Read more >
Pytest with respx and vcr! The best way to test remote service ...
Testing httpx with respx (pytest). First, I would like to present a simple case to use respx, yet powerful, a utility for mocking...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found