1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-08 16:53:23 +00:00

Fix for Serialization errors with JSON adapter

This patch aims to fix the issue#222,
where json data in request can not be serialized
because of TypeError in py3
This commit is contained in:
Aliaksandr Buhayeu
2015-12-02 16:33:58 +03:00
committed by Kevin McCarthy
parent 528c9e7b1a
commit 9daf301deb
4 changed files with 96 additions and 19 deletions

View File

@@ -2,7 +2,8 @@
import pytest
from vcr.compat import mock
from vcr.serialize import deserialize
from vcr.request import Request
from vcr.serialize import deserialize, serialize
from vcr.serializers import yamlserializer, jsonserializer
@@ -83,3 +84,50 @@ def test_deserialize_py2py3_yaml_cassette(tmpdir, req_body, expect):
def test_serialize_constructs_UnicodeDecodeError(mock_dumps):
with pytest.raises(UnicodeDecodeError):
jsonserializer.serialize({})
def test_serialize_empty_request():
request = Request(
method='POST',
uri='http://localhost/',
body='',
headers={},
)
serialize(
{'requests': [request], 'responses': [{}]},
jsonserializer
)
def test_serialize_json_request():
request = Request(
method='POST',
uri='http://localhost/',
body="{'hello': 'world'}",
headers={},
)
serialize(
{'requests': [request], 'responses': [{}]},
jsonserializer
)
def test_serialize_binary_request():
msg = "Does this HTTP interaction contain binary data?"
request = Request(
method='POST',
uri='http://localhost/',
body=b'\x8c',
headers={},
)
try:
serialize(
{'requests': [request], 'responses': [{}]},
jsonserializer
)
except (UnicodeDecodeError, TypeError) as exc:
assert msg in str(exc)

View File

@@ -50,7 +50,7 @@ def deserialize(cassette_string, serializer):
def serialize(cassette_dict, serializer):
interactions = ([{
'request': request._to_dict(),
'request': compat.convert_to_unicode(request._to_dict()),
'response': compat.convert_to_unicode(response),
} for request, response in zip(
cassette_dict['requests'],

View File

@@ -37,19 +37,43 @@ def convert_body_to_bytes(resp):
return resp
def _convert_string_to_unicode(string):
"""
If the string is bytes, decode it to a string (for python3 support)
"""
result = string
try:
if string is not None and not isinstance(string, six.text_type):
result = string.decode('utf-8')
except (TypeError, UnicodeDecodeError, AttributeError):
# Sometimes the string actually is binary or StringIO object,
# so if you can't decode it, just give up.
pass
return result
def convert_body_to_unicode(resp):
"""
If the request body is bytes, decode it to a string (for python3 support)
If the request or responses body is bytes, decode it to a string
(for python3 support)
"""
try:
if not isinstance(resp['body']['string'], six.text_type):
resp['body']['string'] = resp['body']['string'].decode('utf-8')
except (KeyError, TypeError, UnicodeDecodeError):
# The thing we were converting either wasn't a dictionary or didn't
# have the keys we were expecting. Some of the tests just serialize
# and deserialize a string.
if type(resp) is not dict:
# Some of the tests just serialize and deserialize a string.
return _convert_string_to_unicode(resp)
else:
body = resp.get('body')
if body is not None:
try:
body['string'] = _convert_string_to_unicode(
body['string']
)
except (KeyError, TypeError, AttributeError):
# The thing we were converting either wasn't a dictionary or
# didn't have the keys we were expecting.
# For example request object has no 'string' key.
resp['body'] = _convert_string_to_unicode(body)
# Also, sometimes the thing actually is binary, so if you can't decode
# it, just give up.
pass
return resp

View File

@@ -9,16 +9,21 @@ def deserialize(cassette_string):
def serialize(cassette_dict):
error_message = (
"Does this HTTP interaction contain binary data? "
"If so, use a different serializer (like the yaml serializer) "
"for this request?"
)
try:
return json.dumps(cassette_dict, indent=4)
except UnicodeDecodeError as original:
except UnicodeDecodeError as original: # py2
raise UnicodeDecodeError(
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?")
original.args[-1] + error_message
)
except TypeError as original: # py3
raise TypeError(error_message)