mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-09 01:03:24 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9480954c33 | ||
|
|
8432ad32f1 | ||
|
|
fabef3d988 | ||
|
|
da45f46b2d | ||
|
|
562a0ebadc | ||
|
|
ef8ba6d51b | ||
|
|
f6aa6eac84 | ||
|
|
821e148752 | ||
|
|
7306205b8a | ||
|
|
2a128893cc | ||
|
|
5162d183e5 | ||
|
|
9d52c3ed42 | ||
|
|
0e37759175 | ||
|
|
78c6258ba3 | ||
|
|
b047336690 | ||
|
|
c955a5ea88 | ||
|
|
5423d99f5a | ||
|
|
a71c15f398 | ||
|
|
6e049ba7a1 | ||
|
|
916e7839e5 | ||
|
|
99692a92d2 | ||
|
|
a9a68ba44b | ||
|
|
e9f35db405 | ||
|
|
7193407a07 | ||
|
|
c3427ae3a2 | ||
|
|
3a46a6f210 | ||
|
|
163181844b | ||
|
|
2c6f072d11 |
@@ -8,6 +8,7 @@ env:
|
||||
- WITH_LIB="requests2.2"
|
||||
- WITH_LIB="requests2.3"
|
||||
- WITH_LIB="requests2.4"
|
||||
- WITH_LIB="requests2.5"
|
||||
- WITH_LIB="requests1.x"
|
||||
- WITH_LIB="httplib2"
|
||||
- WITH_LIB="boto"
|
||||
@@ -33,6 +34,7 @@ install:
|
||||
- if [ $WITH_LIB = "requests2.2" ] ; then pip install requests==2.2.1; fi
|
||||
- if [ $WITH_LIB = "requests2.3" ] ; then pip install requests==2.3.0; fi
|
||||
- if [ $WITH_LIB = "requests2.4" ] ; then pip install requests==2.4.0; fi
|
||||
- if [ $WITH_LIB = "requests2.5" ] ; then pip install requests==2.5.0; fi
|
||||
- if [ $WITH_LIB = "httplib2" ] ; then pip install httplib2; fi
|
||||
- if [ $WITH_LIB = "boto" ] ; then pip install boto; fi
|
||||
script: python setup.py test
|
||||
|
||||
@@ -457,6 +457,11 @@ API in version 1.0.x
|
||||
|
||||
|
||||
## Changelog
|
||||
* 1.1.3 Fix python3 headers field (thanks @rtaboada), fix boto test (thanks
|
||||
@telaviv), fix new_episodes record mode (thanks @jashugan), fix Windows
|
||||
connectionpool stub bug (thanks @gazpachoking)
|
||||
* 1.1.2 Add urllib==1.7.1 support. Make json serialize error handling correct
|
||||
Improve logging of match failures.
|
||||
* 1.1.1 Use function signature preserving `wrapt.decorator` to write the
|
||||
decorator version of use_cassette in order to ensure compatibility with
|
||||
py.test fixtures and python 2. Move all request filtering into the
|
||||
|
||||
2
setup.py
2
setup.py
@@ -20,7 +20,7 @@ class PyTest(TestCommand):
|
||||
|
||||
setup(
|
||||
name='vcrpy',
|
||||
version='1.1.1',
|
||||
version='1.1.3',
|
||||
description=(
|
||||
"Automatically mock your HTTP interactions to simplify and "
|
||||
"speed up testing"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Basic tests about cassettes'''
|
||||
'''Basic tests for cassettes'''
|
||||
# coding=utf-8
|
||||
|
||||
# External imports
|
||||
|
||||
@@ -14,7 +14,7 @@ def test_boto_stubs(tmpdir):
|
||||
from boto.https_connection import CertValidatingHTTPSConnection
|
||||
from vcr.stubs.boto_stubs import VCRCertValidatingHTTPSConnection
|
||||
# Prove that the class was patched by the stub and that we can instantiate it.
|
||||
assert CertValidatingHTTPSConnection is VCRCertValidatingHTTPSConnection
|
||||
assert issubclass(CertValidatingHTTPSConnection, VCRCertValidatingHTTPSConnection)
|
||||
CertValidatingHTTPSConnection('hostname.does.not.matter')
|
||||
|
||||
def test_boto_without_vcr():
|
||||
|
||||
@@ -72,6 +72,31 @@ def test_new_episodes_record_mode(tmpdir):
|
||||
assert len(cass.responses) == 2
|
||||
|
||||
|
||||
def test_new_episodes_record_mode_two_times(tmpdir):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
url = 'http://httpbin.org/bytes/1024'
|
||||
with vcr.use_cassette(testfile, record_mode="new_episodes"):
|
||||
# cassette file doesn't exist, so create.
|
||||
original_first_response = urlopen(url).read()
|
||||
|
||||
with vcr.use_cassette(testfile, record_mode="new_episodes"):
|
||||
# make the same request again
|
||||
assert urlopen(url).read() == original_first_response
|
||||
|
||||
# in the "new_episodes" record mode, we can add the same request
|
||||
# to the cassette without repercussions
|
||||
original_second_response = urlopen(url).read()
|
||||
|
||||
with vcr.use_cassette(testfile, record_mode="once"):
|
||||
# make the same request again
|
||||
assert urlopen(url).read() == original_first_response
|
||||
assert urlopen(url).read() == original_second_response
|
||||
# now that we are back in once mode, this should raise
|
||||
# an error.
|
||||
with pytest.raises(Exception):
|
||||
urlopen(url).read()
|
||||
|
||||
|
||||
def test_all_record_mode(tmpdir):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
|
||||
|
||||
68
tests/unit/test_response.py
Normal file
68
tests/unit/test_response.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# coding: UTF-8
|
||||
from vcr.stubs import VCRHTTPResponse
|
||||
|
||||
|
||||
def test_response_should_have_headers_field():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": "OK",
|
||||
"code": 200
|
||||
},
|
||||
"headers": {
|
||||
"content-length": ["0"],
|
||||
"server": ["gunicorn/18.0"],
|
||||
"connection": ["Close"],
|
||||
"access-control-allow-credentials": ["true"],
|
||||
"date": ["Fri, 24 Oct 2014 18:35:37 GMT"],
|
||||
"access-control-allow-origin": ["*"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
}
|
||||
response = VCRHTTPResponse(recorded_response)
|
||||
|
||||
assert response.headers is not None
|
||||
|
||||
|
||||
def test_response_headers_should_be_equal_to_msg():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": b"OK",
|
||||
"code": 200
|
||||
},
|
||||
"headers": {
|
||||
"content-length": ["0"],
|
||||
"server": ["gunicorn/18.0"],
|
||||
"connection": ["Close"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
}
|
||||
response = VCRHTTPResponse(recorded_response)
|
||||
|
||||
assert response.headers == response.msg
|
||||
|
||||
|
||||
def test_response_headers_should_have_correct_values():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": "OK",
|
||||
"code": 200
|
||||
},
|
||||
"headers": {
|
||||
"content-length": ["10806"],
|
||||
"date": ["Fri, 24 Oct 2014 18:35:37 GMT"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
}
|
||||
response = VCRHTTPResponse(recorded_response)
|
||||
|
||||
assert response.headers.get('content-length') == "10806"
|
||||
assert response.headers.get('date') == "Fri, 24 Oct 2014 18:35:37 GMT"
|
||||
@@ -1,21 +1,35 @@
|
||||
import mock
|
||||
import pytest
|
||||
|
||||
from vcr.serialize import deserialize
|
||||
from vcr.serializers import yamlserializer, jsonserializer
|
||||
|
||||
|
||||
def test_deserialize_old_yaml_cassette():
|
||||
with open('tests/fixtures/migration/old_cassette.yaml', 'r') as f:
|
||||
with pytest.raises(ValueError):
|
||||
deserialize(f.read(), yamlserializer)
|
||||
|
||||
|
||||
def test_deserialize_old_json_cassette():
|
||||
with open('tests/fixtures/migration/old_cassette.json', 'r') as f:
|
||||
with pytest.raises(ValueError):
|
||||
deserialize(f.read(), jsonserializer)
|
||||
|
||||
|
||||
def test_deserialize_new_yaml_cassette():
|
||||
with open('tests/fixtures/migration/new_cassette.yaml', 'r') as f:
|
||||
deserialize(f.read(), yamlserializer)
|
||||
|
||||
|
||||
def test_deserialize_new_json_cassette():
|
||||
with open('tests/fixtures/migration/new_cassette.json', 'r') as f:
|
||||
deserialize(f.read(), jsonserializer)
|
||||
|
||||
|
||||
@mock.patch.object(jsonserializer.json, 'dumps',
|
||||
side_effect=UnicodeDecodeError('utf-8', b'unicode error in serialization',
|
||||
0, 10, 'blew up'))
|
||||
def test_serialize_constructs_UnicodeDecodeError(mock_dumps):
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
jsonserializer.serialize({})
|
||||
|
||||
193
tox.ini
193
tox.ini
@@ -1,188 +1,25 @@
|
||||
# Tox (http://tox.testrun.org/) is a tool for running tests
|
||||
# in multiple virtualenvs. This configuration file will run the
|
||||
# test suite on all supported python versions. To use it, "pip install tox"
|
||||
# and then run "tox" from this directory.
|
||||
|
||||
[tox]
|
||||
envlist =
|
||||
py26,
|
||||
py27,
|
||||
py33,
|
||||
py34,
|
||||
pypy,
|
||||
py26requests24,
|
||||
py27requests24,
|
||||
py34requests24,
|
||||
pypyrequests24,
|
||||
py26requests23,
|
||||
py27requests23,
|
||||
py34requests23,
|
||||
pypyrequests23,
|
||||
py26requests22,
|
||||
py27requests22,
|
||||
py34requests22,
|
||||
pypyrequests22,
|
||||
py26requests1,
|
||||
py27requests1,
|
||||
py33requests1,
|
||||
pypyrequests1,
|
||||
py26httplib2,
|
||||
py27httplib2,
|
||||
py33httplib2,
|
||||
py34httplib2,
|
||||
pypyhttplib2,
|
||||
envlist = {py26,py27,py33,py34,pypy}-{requests25,requests24,requests23,requests22,requests1,httplib2,urllib3,boto}
|
||||
|
||||
[testenv]
|
||||
commands =
|
||||
py.test {posargs}
|
||||
basepython =
|
||||
py26: python2.6
|
||||
py27: python2.7
|
||||
py33: python3.3
|
||||
py34: python3.4
|
||||
pypy: pypy
|
||||
deps =
|
||||
mock
|
||||
pytest
|
||||
pytest-localserver
|
||||
PyYAML
|
||||
ipdb
|
||||
|
||||
[testenv:py26requests1]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==1.2.3
|
||||
|
||||
[testenv:py27requests1]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==1.2.3
|
||||
|
||||
[testenv:py33requests1]
|
||||
basepython = python3.3
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==1.2.3
|
||||
|
||||
[testenv:pypyrequests1]
|
||||
basepython = pypy
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==1.2.3
|
||||
|
||||
[testenv:py26requests24]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.4.0
|
||||
|
||||
[testenv:py27requests24]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.4.0
|
||||
|
||||
[testenv:py33requests24]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.4.0
|
||||
|
||||
[testenv:py34requests24]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.4.0
|
||||
|
||||
[testenv:pypyrequests24]
|
||||
basepython = pypy
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.4.0
|
||||
|
||||
[testenv:py26requests23]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.3.0
|
||||
|
||||
[testenv:py27requests23]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.3.0
|
||||
|
||||
[testenv:py33requests23]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.3.0
|
||||
|
||||
[testenv:py34requests23]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.3.0
|
||||
|
||||
[testenv:pypyrequests23]
|
||||
basepython = pypy
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.3.0
|
||||
|
||||
[testenv:py26requests22]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.2.1
|
||||
|
||||
[testenv:py27requests22]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.2.1
|
||||
|
||||
[testenv:py33requests22]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.2.1
|
||||
|
||||
[testenv:py34requests22]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.2.1
|
||||
|
||||
|
||||
[testenv:pypyrequests22]
|
||||
basepython = pypy
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
requests==2.2.1
|
||||
|
||||
[testenv:py26httplib2]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
httplib2
|
||||
|
||||
[testenv:py27httplib2]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
httplib2
|
||||
|
||||
[testenv:py33httplib2]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
httplib2
|
||||
|
||||
[testenv:py34httplib2]
|
||||
basepython = python3.4
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
httplib2
|
||||
|
||||
[testenv:pypyhttplib2]
|
||||
basepython = pypy
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
httplib2
|
||||
requests1: requests==1.2.3
|
||||
requests25: requests==2.5.0
|
||||
requests24: requests==2.4.0
|
||||
requests23: requests==2.3.0
|
||||
requests22: requests==2.2.1
|
||||
httplib2: httplib2
|
||||
urllib3: urllib3==1.7.1
|
||||
boto: boto
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''The container for recorded requests and responses'''
|
||||
"""The container for recorded requests and responses"""
|
||||
import logging
|
||||
|
||||
import contextlib2
|
||||
@@ -24,7 +24,7 @@ class CassetteContextDecorator(object):
|
||||
removing cassettes.
|
||||
|
||||
This class defers the creation of a new cassette instance until the point at
|
||||
which it is installned by context manager or decorator. The fact that a new
|
||||
which it is installed by context manager or decorator. The fact that a new
|
||||
cassette is used with each application prevents the state of any cassette
|
||||
from interfering with another.
|
||||
"""
|
||||
@@ -45,7 +45,8 @@ class CassetteContextDecorator(object):
|
||||
log.debug('Entered context for cassette at {0}.'.format(cassette._path))
|
||||
yield cassette
|
||||
log.debug('Exiting context for cassette at {0}.'.format(cassette._path))
|
||||
# TODO(@IvanMalison): Hmmm. it kind of feels like this should be somewhere else.
|
||||
# TODO(@IvanMalison): Hmmm. it kind of feels like this should be
|
||||
# somewhere else.
|
||||
cassette._save()
|
||||
|
||||
def __enter__(self):
|
||||
@@ -65,11 +66,11 @@ class CassetteContextDecorator(object):
|
||||
|
||||
|
||||
class Cassette(object):
|
||||
'''A container for recorded requests and responses'''
|
||||
"""A container for recorded requests and responses"""
|
||||
|
||||
@classmethod
|
||||
def load(cls, path, **kwargs):
|
||||
'''Instantiate and load the cassette stored at the specified path.'''
|
||||
"""Instantiate and load the cassette stored at the specified path."""
|
||||
new_cassette = cls(path, **kwargs)
|
||||
new_cassette._load()
|
||||
return new_cassette
|
||||
@@ -85,7 +86,8 @@ class Cassette(object):
|
||||
def __init__(self, path, serializer=yamlserializer, record_mode='once',
|
||||
match_on=(uri, method), filter_headers=(),
|
||||
filter_query_parameters=(), before_record_request=None,
|
||||
before_record_response=None, ignore_hosts=(), ignore_localhost=()):
|
||||
before_record_response=None, ignore_hosts=(),
|
||||
ignore_localhost=()):
|
||||
self._path = path
|
||||
self._serializer = serializer
|
||||
self._match_on = match_on
|
||||
@@ -105,9 +107,7 @@ class Cassette(object):
|
||||
|
||||
@property
|
||||
def all_played(self):
|
||||
"""
|
||||
Returns True if all responses have been played, False otherwise.
|
||||
"""
|
||||
"""Returns True if all responses have been played, False otherwise."""
|
||||
return self.play_count == len(self)
|
||||
|
||||
@property
|
||||
@@ -124,7 +124,7 @@ class Cassette(object):
|
||||
self.record_mode == 'none'
|
||||
|
||||
def append(self, request, response):
|
||||
'''Add a request, response pair to this cassette'''
|
||||
"""Add a request, response pair to this cassette"""
|
||||
request = self._before_record_request(request)
|
||||
if not request:
|
||||
return
|
||||
@@ -153,10 +153,10 @@ class Cassette(object):
|
||||
self.rewound
|
||||
|
||||
def play_response(self, request):
|
||||
'''
|
||||
"""
|
||||
Get the response corresponding to a request, but only if it
|
||||
hasn't been played back before, and mark it as played
|
||||
'''
|
||||
"""
|
||||
for index, response in self._responses(request):
|
||||
if self.play_counts[index] == 0:
|
||||
self.play_counts[index] += 1
|
||||
@@ -168,11 +168,11 @@ class Cassette(object):
|
||||
)
|
||||
|
||||
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 = [response for index, response in self._responses(request)]
|
||||
|
||||
if responses:
|
||||
@@ -214,11 +214,12 @@ class Cassette(object):
|
||||
)
|
||||
|
||||
def __len__(self):
|
||||
'''Return the number of request,response pairs stored in here'''
|
||||
"""Return the number of request,response pairs stored in here"""
|
||||
return len(self.data)
|
||||
|
||||
def __contains__(self, request):
|
||||
'''Return whether or not a request has been stored'''
|
||||
for response in self._responses(request):
|
||||
return True
|
||||
"""Return whether or not a request has been stored"""
|
||||
for index, response in self._responses(request):
|
||||
if self.play_counts[index] == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -38,16 +38,16 @@ def headers(r1, r2):
|
||||
return r1.headers == r2.headers
|
||||
|
||||
|
||||
def _log_matches(matches):
|
||||
def _log_matches(r1, r2, matches):
|
||||
differences = [m for m in matches if not m[0]]
|
||||
if differences:
|
||||
log.debug(
|
||||
'Requests differ according to the following matchers: ' +
|
||||
str(differences)
|
||||
"Requests {0} and {1} differ according to "
|
||||
"the following matchers: {2}".format(r1, r2, differences)
|
||||
)
|
||||
|
||||
|
||||
def requests_match(r1, r2, matchers):
|
||||
matches = [(m(r1, r2), m) for m in matchers]
|
||||
_log_matches(matches)
|
||||
_log_matches(r1, r2, matches)
|
||||
return all([m[0] for m in matches])
|
||||
|
||||
12
vcr/patch.py
12
vcr/patch.py
@@ -59,7 +59,9 @@ class CassettePatcherBuilder(object):
|
||||
def _build_patchers_from_mock_triples_decorator(function):
|
||||
@functools.wraps(function)
|
||||
def wrapped(self, *args, **kwargs):
|
||||
return self._build_patchers_from_mock_triples(function(self, *args, **kwargs))
|
||||
return self._build_patchers_from_mock_triples(
|
||||
function(self, *args, **kwargs)
|
||||
)
|
||||
return wrapped
|
||||
|
||||
def __init__(self, cassette):
|
||||
@@ -134,6 +136,7 @@ class CassettePatcherBuilder(object):
|
||||
(cpool, 'VerifiedHTTPSConnection', VCRRequestsHTTPSConnection),
|
||||
(cpool, 'HTTPConnection', VCRRequestsHTTPConnection),
|
||||
(cpool, 'HTTPSConnection', VCRRequestsHTTPSConnection),
|
||||
(cpool, 'is_connection_dropped', mock.Mock(return_value=False)), # Needed on Windows only
|
||||
(cpool.HTTPConnectionPool, 'ConnectionCls', VCRRequestsHTTPConnection),
|
||||
(cpool.HTTPSConnectionPool, 'ConnectionCls', VCRRequestsHTTPSConnection),
|
||||
)
|
||||
@@ -234,7 +237,7 @@ class ConnectionRemover(object):
|
||||
def __exit__(self, *args):
|
||||
for pool, connections in self._connection_pool_to_connections.items():
|
||||
readd_connections = []
|
||||
while not pool.pool.empty() and connections:
|
||||
while pool.pool and not pool.pool.empty() and connections:
|
||||
connection = pool.pool.get()
|
||||
if isinstance(connection, self._connection_class):
|
||||
connections.remove(connection)
|
||||
@@ -273,8 +276,9 @@ def reset_patchers():
|
||||
yield mock.patch.object(cpool, 'VerifiedHTTPSConnection', _VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, 'HTTPConnection', _HTTPConnection)
|
||||
yield mock.patch.object(cpool, 'HTTPSConnection', _HTTPSConnection)
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, 'ConnectionCls', _HTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, 'ConnectionCls', _HTTPSConnection)
|
||||
if hasattr(cpool.HTTPConnectionPool, 'ConnectionCls'):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, 'ConnectionCls', _HTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, 'ConnectionCls', _HTTPSConnection)
|
||||
|
||||
try:
|
||||
import httplib2 as cpool
|
||||
|
||||
@@ -11,10 +11,14 @@ def deserialize(cassette_string):
|
||||
def serialize(cassette_dict):
|
||||
try:
|
||||
return json.dumps(cassette_dict, indent=4)
|
||||
except UnicodeDecodeError:
|
||||
except UnicodeDecodeError as original:
|
||||
raise UnicodeDecodeError(
|
||||
"Error serializing cassette to JSON. ",
|
||||
"Does this HTTP interaction contain binary data? ",
|
||||
"If so, use a different serializer (like the yaml serializer) ",
|
||||
"for this request"
|
||||
original.encoding,
|
||||
b"Error serializing cassette to JSON",
|
||||
original.start,
|
||||
original.end,
|
||||
original.args[-1] +
|
||||
("Does this HTTP interaction contain binary data? "
|
||||
"If so, use a different serializer (like the yaml serializer) "
|
||||
"for this request?")
|
||||
)
|
||||
|
||||
@@ -76,7 +76,7 @@ class VCRHTTPResponse(HTTPResponse):
|
||||
self._closed = False
|
||||
|
||||
headers = self.recorded_response['headers']
|
||||
self.msg = parse_headers(headers)
|
||||
self.headers = self.msg = parse_headers(headers)
|
||||
|
||||
self.length = compat.get_header(self.msg, 'content-length') or None
|
||||
|
||||
@@ -217,11 +217,15 @@ class VCRConnection(object):
|
||||
response = self.cassette.play_response(self._vcr_request)
|
||||
return VCRHTTPResponse(response)
|
||||
else:
|
||||
if self.cassette.write_protected and self.cassette.filter_request(self._vcr_request):
|
||||
if self.cassette.write_protected and self.cassette.filter_request(
|
||||
self._vcr_request
|
||||
):
|
||||
raise CannotOverwriteExistingCassetteException(
|
||||
"No match for the request (%r) was found. "
|
||||
"Can't overwrite existing cassette (%r) in "
|
||||
"your current record mode (%r)."
|
||||
% (self.cassette._path, self.cassette.record_mode)
|
||||
% (self._vcr_request, self.cassette._path,
|
||||
self.cassette.record_mode)
|
||||
)
|
||||
|
||||
# Otherwise, we should send the request, then get the response
|
||||
@@ -310,3 +314,4 @@ class VCRHTTPSConnection(VCRConnection):
|
||||
'''A Mocked class for HTTPS requests'''
|
||||
_baseclass = HTTPSConnection
|
||||
_protocol = 'https'
|
||||
is_verified = True
|
||||
|
||||
Reference in New Issue
Block a user