vcrpy icon indicating copy to clipboard operation
vcrpy copied to clipboard

Httpx stub cause tests to breaks trying to access httpx.Response elapsed time property

Open isaquealves opened this issue 3 years ago • 2 comments

When building an httpx response at vcr.stubs.httpx_stubs._from_serialized_response, the elapsed property was not covered. This cause tests to break as the elapsed property is dynamic calculated and depends on the patched method close.

Example:

# script.py
import httpx

def get_elapsed_microsecs():
    response = httpx.get('https://api.github.com/events')
    return round(response.elapsed.total_seconds() * 1000, 2)
# test_script.py
import pytest
import vcr

@vcr.use_cassete("cassete.yml")
@pytest.mark.asyncio
def test_get_elapsed_microsecs():
  ''' Breaks raising ".elapsed may ony be accessed after the response has been read or closed" '''
    microsecs = get_elapsed_microsecs()
    assert microsecs >= 0.02


isaquealves avatar Aug 12 '21 11:08 isaquealves

I suggest we close this one in view of #784

parkerhancock avatar Dec 08 '23 19:12 parkerhancock

Unfortunately, even the latest release v6.0.1 of vcrpy does not seem to resolve this issue. From my experiments it looks like httpx.Response.elapsed still cannot be accessed in tests.

As was mentioned in the original message by @isaquealves from almost 3 years ago, the problem is that the httpx.Response.elapsed property is only being set by the httpx.Response.close method which is being mocked while creating a response from serialized data in vcr.stubs.httpx_stubs._from_serialized_response function. And since there is no additional patching done by vcrpy, this property remains unavailable.

A naive fix might look similar to this:

diff --git a/vcr/stubs/httpx_stubs.py b/vcr/stubs/httpx_stubs.py
index 759cb72..b9fd59f 100644
--- a/vcr/stubs/httpx_stubs.py
+++ b/vcr/stubs/httpx_stubs.py
@@ -1,4 +1,5 @@
 import asyncio
+from datetime import timedelta
 import functools
 import inspect
 import logging
@@ -100,6 +101,7 @@ def _from_serialized_response(request, serialized_response, history=None):
         history=history or [],
         extensions=extensions,
     )
+    response.elapsed = timedelta(seconds=1)

     return response

Perhaps until a proper approach is found, this might be an acceptable work-around.

pbasista avatar Apr 17 '24 10:04 pbasista