mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-09 01:03:24 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b7e6c0ab8 | ||
|
|
bd7c6ed03f | ||
|
|
1e414826e7 | ||
|
|
1e1c093b3c | ||
|
|
bb8f563135 | ||
|
|
ca3200d96e | ||
|
|
04b5978adc | ||
|
|
01f1f9fdc1 | ||
|
|
a82e8628c2 | ||
|
|
7d68f0577a |
@@ -608,6 +608,8 @@ new API in version 1.0.x
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
- 1.7.2 [#186] Get effective_url in tornado (thanks @mvschaik), [#187]
|
||||||
|
Set request_time on Response object in tornado (thanks @abhinav).
|
||||||
- 1.7.1 [#183] Patch ``fetch_impl`` instead of the entire HTTPClient
|
- 1.7.1 [#183] Patch ``fetch_impl`` instead of the entire HTTPClient
|
||||||
class for Tornado (thanks @abhinav).
|
class for Tornado (thanks @abhinav).
|
||||||
- 1.7.0 [#177] Properly support coroutine/generator decoration. [#178]
|
- 1.7.0 [#177] Properly support coroutine/generator decoration. [#178]
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -51,7 +51,7 @@ except Exception:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='vcrpy',
|
name='vcrpy',
|
||||||
version='1.7.1',
|
version='1.7.2',
|
||||||
description=(
|
description=(
|
||||||
"Automatically mock your HTTP interactions to simplify and "
|
"Automatically mock your HTTP interactions to simplify and "
|
||||||
"speed up testing"
|
"speed up testing"
|
||||||
|
|||||||
@@ -56,6 +56,17 @@ def test_response_headers(scheme, tmpdir):
|
|||||||
resp, _ = httplib2.Http().request(url)
|
resp, _ = httplib2.Http().request(url)
|
||||||
assert set(headers) == set(resp.items())
|
assert set(headers) == set(resp.items())
|
||||||
|
|
||||||
|
def test_effective_url(scheme, tmpdir):
|
||||||
|
'''Ensure that the effective_url is captured'''
|
||||||
|
url = scheme + '://httpbin.org/redirect-to?url=/html'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cass:
|
||||||
|
resp, _ = httplib2.Http().request(url)
|
||||||
|
effective_url = resp['content-location']
|
||||||
|
assert effective_url == scheme + '://httpbin.org/html'
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cass:
|
||||||
|
resp, _ = httplib2.Http().request(url)
|
||||||
|
assert effective_url == resp['content-location']
|
||||||
|
|
||||||
def test_multiple_requests(scheme, tmpdir):
|
def test_multiple_requests(scheme, tmpdir):
|
||||||
'''Ensure that we can cache multiple requests'''
|
'''Ensure that we can cache multiple requests'''
|
||||||
|
|||||||
@@ -44,6 +44,15 @@ def test_body(tmpdir, scheme):
|
|||||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||||
assert content == requests.get(url).content
|
assert content == requests.get(url).content
|
||||||
|
|
||||||
|
def test_effective_url(scheme, tmpdir):
|
||||||
|
'''Ensure that the effective_url is captured'''
|
||||||
|
url = scheme + '://httpbin.org/redirect-to?url=/html'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('url.yaml'))):
|
||||||
|
effective_url = requests.get(url).url
|
||||||
|
assert effective_url == scheme + '://httpbin.org/html'
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('url.yaml'))):
|
||||||
|
assert effective_url == requests.get(url).url
|
||||||
|
|
||||||
def test_auth(tmpdir, scheme):
|
def test_auth(tmpdir, scheme):
|
||||||
'''Ensure that we can handle basic auth'''
|
'''Ensure that we can handle basic auth'''
|
||||||
|
|||||||
@@ -81,6 +81,17 @@ def test_body(get_client, tmpdir, scheme):
|
|||||||
assert content == (yield get(get_client(), url)).body
|
assert content == (yield get(get_client(), url)).body
|
||||||
assert 1 == cass.play_count
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_effective_url(get_client, scheme, tmpdir):
|
||||||
|
'''Ensure that the effective_url is captured'''
|
||||||
|
url = scheme + '://httpbin.org/redirect-to?url=/html'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('url.yaml'))):
|
||||||
|
effective_url = (yield get(get_client(), url)).effective_url
|
||||||
|
assert effective_url == scheme + '://httpbin.org/html'
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('url.yaml'))) as cass:
|
||||||
|
assert effective_url == (yield get(get_client(), url)).effective_url
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
@pytest.mark.gen_test
|
@pytest.mark.gen_test
|
||||||
def test_auth(get_client, tmpdir, scheme):
|
def test_auth(get_client, tmpdir, scheme):
|
||||||
@@ -326,3 +337,19 @@ def test_existing_instances_get_patched(get_client, tmpdir):
|
|||||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))) as cass:
|
with vcr.use_cassette(str(tmpdir.join('data.yaml'))) as cass:
|
||||||
yield get(client, 'http://httpbin.org/get')
|
yield get(client, 'http://httpbin.org/get')
|
||||||
assert cass.play_count == 1
|
assert cass.play_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_request_time_is_set(get_client, tmpdir):
|
||||||
|
'''Ensures that the request_time on HTTPResponses is set.'''
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('data.yaml'))):
|
||||||
|
client = get_client()
|
||||||
|
response = yield get(client, 'http://httpbin.org/get')
|
||||||
|
assert response.request_time is not None
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('data.yaml'))) as cass:
|
||||||
|
client = get_client()
|
||||||
|
response = yield get(client, 'http://httpbin.org/get')
|
||||||
|
assert response.request_time is not None
|
||||||
|
assert cass.play_count == 1
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ def test_response_headers(scheme, tmpdir):
|
|||||||
open2 = urlopen(url).info().items()
|
open2 = urlopen(url).info().items()
|
||||||
assert sorted(open1) == sorted(open2)
|
assert sorted(open1) == sorted(open2)
|
||||||
|
|
||||||
|
def test_effective_url(scheme, tmpdir):
|
||||||
|
'''Ensure that the effective_url is captured'''
|
||||||
|
url = scheme + '://httpbin.org/redirect-to?url=/html'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cass:
|
||||||
|
effective_url = urlopen(url).geturl()
|
||||||
|
assert effective_url == scheme + '://httpbin.org/html'
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cass:
|
||||||
|
assert effective_url == urlopen(url).geturl()
|
||||||
|
|
||||||
def test_multiple_requests(scheme, tmpdir):
|
def test_multiple_requests(scheme, tmpdir):
|
||||||
'''Ensure that we can cache multiple requests'''
|
'''Ensure that we can cache multiple requests'''
|
||||||
|
|||||||
@@ -20,10 +20,18 @@ class CassetteContextDecorator(object):
|
|||||||
"""Context manager/decorator that handles installing the cassette and
|
"""Context manager/decorator that handles installing the cassette and
|
||||||
removing cassettes.
|
removing cassettes.
|
||||||
|
|
||||||
This class defers the creation of a new cassette instance until the point at
|
This class defers the creation of a new cassette instance until
|
||||||
which it is installed by context manager or decorator. The fact that a new
|
the point at which it is installed by context manager or
|
||||||
cassette is used with each application prevents the state of any cassette
|
decorator. The fact that a new cassette is used with each
|
||||||
from interfering with another.
|
application prevents the state of any cassette from interfering
|
||||||
|
with another.
|
||||||
|
|
||||||
|
Instances of this class are NOT reentrant as context managers.
|
||||||
|
However, functions that are decorated by
|
||||||
|
``CassetteContextDecorator`` instances ARE reentrant. See the
|
||||||
|
implementation of ``__call__`` on this class for more details.
|
||||||
|
There is also a guard against attempts to reenter instances of
|
||||||
|
this class as a context manager in ``__exit__``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_non_cassette_arguments = ('path_transformer', 'func_path_generator')
|
_non_cassette_arguments = ('path_transformer', 'func_path_generator')
|
||||||
@@ -41,9 +49,14 @@ class CassetteContextDecorator(object):
|
|||||||
with contextlib.ExitStack() as exit_stack:
|
with contextlib.ExitStack() as exit_stack:
|
||||||
for patcher in CassettePatcherBuilder(cassette).build():
|
for patcher in CassettePatcherBuilder(cassette).build():
|
||||||
exit_stack.enter_context(patcher)
|
exit_stack.enter_context(patcher)
|
||||||
log.debug('Entered context for cassette at {0}.'.format(cassette._path))
|
log_format = '{action} context for cassette at {path}.'
|
||||||
|
log.debug(log_format.format(
|
||||||
|
action="Entering", path=cassette._path
|
||||||
|
))
|
||||||
yield cassette
|
yield cassette
|
||||||
log.debug('Exiting context for cassette at {0}.'.format(cassette._path))
|
log.debug(log_format.format(
|
||||||
|
action="Exiting", path=cassette._path
|
||||||
|
))
|
||||||
# TODO(@IvanMalison): Hmmm. it kind of feels like this should be
|
# TODO(@IvanMalison): Hmmm. it kind of feels like this should be
|
||||||
# somewhere else.
|
# somewhere else.
|
||||||
cassette._save()
|
cassette._save()
|
||||||
@@ -78,7 +91,9 @@ class CassetteContextDecorator(object):
|
|||||||
# functions are reentrant. This is required for thread
|
# functions are reentrant. This is required for thread
|
||||||
# safety and the correct operation of recursive functions.
|
# safety and the correct operation of recursive functions.
|
||||||
args_getter = self._build_args_getter_for_decorator(function)
|
args_getter = self._build_args_getter_for_decorator(function)
|
||||||
return type(self)(self.cls, args_getter)._execute_function(function, args, kwargs)
|
return type(self)(self.cls, args_getter)._execute_function(
|
||||||
|
function, args, kwargs
|
||||||
|
)
|
||||||
|
|
||||||
def _execute_function(self, function, args, kwargs):
|
def _execute_function(self, function, args, kwargs):
|
||||||
if inspect.isgeneratorfunction(function):
|
if inspect.isgeneratorfunction(function):
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
|
|||||||
"that is not yet supported by VCR.py. Please make the "
|
"that is not yet supported by VCR.py. Please make the "
|
||||||
"request outside a VCR.py context." % repr(request)
|
"request outside a VCR.py context." % repr(request)
|
||||||
),
|
),
|
||||||
|
request_time=self.io_loop.time() - request.start_time,
|
||||||
)
|
)
|
||||||
return callback(response)
|
return callback(response)
|
||||||
|
|
||||||
@@ -62,6 +63,8 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
|
|||||||
reason=vcr_response['status']['message'],
|
reason=vcr_response['status']['message'],
|
||||||
headers=headers,
|
headers=headers,
|
||||||
buffer=BytesIO(vcr_response['body']['string']),
|
buffer=BytesIO(vcr_response['body']['string']),
|
||||||
|
effective_url=vcr_response.get('url'),
|
||||||
|
request_time=self.io_loop.time() - request.start_time,
|
||||||
)
|
)
|
||||||
return callback(response)
|
return callback(response)
|
||||||
else:
|
else:
|
||||||
@@ -77,6 +80,7 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
|
|||||||
"your current record mode (%r)."
|
"your current record mode (%r)."
|
||||||
% (vcr_request, cassette._path, cassette.record_mode)
|
% (vcr_request, cassette._path, cassette.record_mode)
|
||||||
),
|
),
|
||||||
|
request_time=self.io_loop.time() - request.start_time,
|
||||||
)
|
)
|
||||||
return callback(response)
|
return callback(response)
|
||||||
|
|
||||||
@@ -93,6 +97,7 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
|
|||||||
},
|
},
|
||||||
'headers': headers,
|
'headers': headers,
|
||||||
'body': {'string': response.body},
|
'body': {'string': response.body},
|
||||||
|
'url': response.effective_url,
|
||||||
}
|
}
|
||||||
cassette.append(vcr_request, vcr_response)
|
cassette.append(vcr_request, vcr_response)
|
||||||
return callback(response)
|
return callback(response)
|
||||||
|
|||||||
Reference in New Issue
Block a user