mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-08 16:53:23 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d3f887ebc | ||
|
|
49929e3064 | ||
|
|
188b57a2fa | ||
|
|
b84f8e963b | ||
|
|
ea13d51677 | ||
|
|
5ba4000f77 |
@@ -162,7 +162,7 @@ part of the API. The fields are as follows:
|
||||
* `responses`: A list of the responses made.
|
||||
* `play_count`: The number of times this cassette has had a response
|
||||
played back
|
||||
* `response_of(request)`: Access the response for a given request.
|
||||
* `responses_of(request)`: Access the responses that match a given request
|
||||
|
||||
The Request object has the following properties
|
||||
|
||||
@@ -257,6 +257,7 @@ This library is a work in progress, so the API might change on you.
|
||||
There are probably some [bugs](https://github.com/kevin1024/vcrpy/issues?labels=bug&page=1&state=open) floating around too.
|
||||
|
||||
##Changelog
|
||||
* 0.5.0: Change the `response_of` method to `responses_of` since cassettes can now contain more than one response for a request. Since this changes the API, I'm bumping the version. Also includes 2 bugfixes: a better error message when attempting to overwrite a cassette file, and a fix for a bug with requests sessions (thanks @msabramo)
|
||||
* 0.4.0: Change default request recording behavior for multiple requests. If you make the same request multiple times to the same URL, the response might be different each time (maybe the response has a timestamp in it or something), so this will make the same request multiple times and save them all. Then, when you are replaying the cassette, the responses will be played back in the same order in which they were received. If you were making multiple requests to the same URL in a cassette before version 0.4.0, you might need to regenerate your cassette files. Also, removes support for the cassette.play_count counter API, since individual requests aren't unique anymore. A cassette might contain the same request several times. Also removes secure overwrite feature since that was breaking overwriting files in Windows, and fixes a bug preventing request's automatic body decompression from working.
|
||||
* 0.3.5: Fix compatibility with requests 2.x
|
||||
* 0.3.4: Bugfix: close file before renaming it. This fixes an issue on Windows. Thanks @smallcode for the fix.
|
||||
|
||||
@@ -130,3 +130,18 @@ def test_gzip(tmpdir, scheme):
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))) as cass:
|
||||
assert_is_json(response.content)
|
||||
|
||||
|
||||
def test_session_and_connection_close(tmpdir, scheme):
|
||||
'''
|
||||
This tests the issue in https://github.com/kevin1024/vcrpy/issues/48
|
||||
|
||||
If you use a requests.session and the connection is closed, then an
|
||||
exception is raised in the urllib3 module vendored into requests:
|
||||
`AttributeError: 'NoneType' object has no attribute 'settimeout'`
|
||||
'''
|
||||
with vcr.use_cassette(str(tmpdir.join('session_connection_closed.yaml'))):
|
||||
session = requests.session()
|
||||
|
||||
resp = session.get('http://httpbin.org/get', headers={'Connection': 'close'})
|
||||
resp = session.get('http://httpbin.org/get', headers={'Connection': 'close'})
|
||||
|
||||
@@ -44,14 +44,22 @@ def test_cassette_contains():
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
def test_cassette_response_of():
|
||||
def test_cassette_responses_of():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
assert a.response_of('foo') == 'bar'
|
||||
assert a.responses_of('foo') == ['bar']
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
def test_cassette_get_missing_response():
|
||||
a = Cassette('test')
|
||||
with pytest.raises(KeyError):
|
||||
a.response_of('foo')
|
||||
a.responses_of('foo')
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
def test_cassette_cant_read_same_request_twice():
|
||||
a = Cassette('test')
|
||||
a.append('foo','bar')
|
||||
a.play_response('foo')
|
||||
with pytest.raises(KeyError):
|
||||
a.play_response('foo')
|
||||
|
||||
@@ -61,10 +61,10 @@ class Cassette(object):
|
||||
self.data.append((request, response))
|
||||
self.dirty = True
|
||||
|
||||
def response_of(self, request):
|
||||
def play_response(self, request):
|
||||
'''
|
||||
Find the response corresponding to a request
|
||||
|
||||
Get the response corresponding to a request, but only if it
|
||||
hasn't been played back before, and mark it as playe.d
|
||||
'''
|
||||
for index, (stored_request, response) in enumerate(self.data):
|
||||
if requests_match(request, stored_request, self._match_on):
|
||||
@@ -75,6 +75,22 @@ class Cassette(object):
|
||||
# if the cassette doesn't contain the request asked for.
|
||||
raise KeyError
|
||||
|
||||
def responses_of(self, request):
|
||||
'''
|
||||
Find the responses corresponding to a request.
|
||||
This function isn't actually used by VCR internally, but is
|
||||
provided as an external API.
|
||||
'''
|
||||
responses = \
|
||||
[resp for req, resp in self.data if
|
||||
requests_match(req, request, self._match_on)]
|
||||
|
||||
if responses:
|
||||
return responses
|
||||
# I decided that a KeyError is the best exception to raise
|
||||
# if the cassette doesn't contain the request asked for.
|
||||
raise KeyError
|
||||
|
||||
def _as_dict(self):
|
||||
return {"requests": self.requests, "responses": self.responses}
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ class FilesystemPersister(object):
|
||||
dirname, filename = os.path.split(cassette_path)
|
||||
if dirname and not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
with open(cassette_path, 'w') as f:
|
||||
f.write(data)
|
||||
with open(cassette_path, 'w') as f:
|
||||
f.write(data)
|
||||
|
||||
@@ -56,6 +56,10 @@ class VCRConnectionMixin:
|
||||
|
||||
def request(self, method, url, body=None, headers=None):
|
||||
'''Persist the request metadata in self._vcr_request'''
|
||||
# see VCRConnectionMixin._restore_socket for the motivation here
|
||||
if hasattr(self, 'sock'):
|
||||
del self.sock
|
||||
|
||||
self._vcr_request = Request(
|
||||
protocol=self._protocol,
|
||||
host=self.host,
|
||||
@@ -161,12 +165,17 @@ class VCRConnectionMixin:
|
||||
'''Retrieve a the response'''
|
||||
# Check to see if the cassette has a response for this request. If so,
|
||||
# then return it
|
||||
if self._vcr_request in self.cassette and self.cassette.record_mode != "all" and self.cassette.rewound:
|
||||
response = self.cassette.response_of(self._vcr_request)
|
||||
if self._vcr_request in self.cassette and \
|
||||
self.cassette.record_mode != "all" and \
|
||||
self.cassette.rewound:
|
||||
response = self.cassette.play_response(self._vcr_request)
|
||||
return VCRHTTPResponse(response)
|
||||
else:
|
||||
if self.cassette.write_protected:
|
||||
raise Exception("cassette is write protected")
|
||||
raise Exception(
|
||||
"Can't overwrite existing cassette in \
|
||||
your current record mode."
|
||||
)
|
||||
|
||||
# Otherwise, we should send the request, then get the response
|
||||
# and return it.
|
||||
@@ -205,11 +214,6 @@ class VCRHTTPConnection(VCRConnectionMixin, HTTPConnection):
|
||||
_baseclass = HTTPConnection
|
||||
_protocol = 'http'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
HTTPConnection.__init__(self, *args, **kwargs)
|
||||
# see VCRConnectionMixin._restore_socket for the motivation here
|
||||
del self.sock
|
||||
|
||||
|
||||
class VCRHTTPSConnection(VCRConnectionMixin, HTTPSConnection):
|
||||
'''A Mocked class for HTTPS requests'''
|
||||
@@ -223,5 +227,3 @@ class VCRHTTPSConnection(VCRConnectionMixin, HTTPSConnection):
|
||||
HTTPConnection.__init__(self, *args, **kwargs)
|
||||
self.key_file = kwargs.pop('key_file', None)
|
||||
self.cert_file = kwargs.pop('cert_file', None)
|
||||
# see VCRConnectionMixin._restore_socket for the motivation here
|
||||
del self.sock
|
||||
|
||||
Reference in New Issue
Block a user