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:
committed by
Kevin McCarthy
parent
528c9e7b1a
commit
9daf301deb
@@ -2,7 +2,8 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from vcr.compat import mock
|
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
|
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):
|
def test_serialize_constructs_UnicodeDecodeError(mock_dumps):
|
||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
jsonserializer.serialize({})
|
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)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ def deserialize(cassette_string, serializer):
|
|||||||
|
|
||||||
def serialize(cassette_dict, serializer):
|
def serialize(cassette_dict, serializer):
|
||||||
interactions = ([{
|
interactions = ([{
|
||||||
'request': request._to_dict(),
|
'request': compat.convert_to_unicode(request._to_dict()),
|
||||||
'response': compat.convert_to_unicode(response),
|
'response': compat.convert_to_unicode(response),
|
||||||
} for request, response in zip(
|
} for request, response in zip(
|
||||||
cassette_dict['requests'],
|
cassette_dict['requests'],
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def convert_body_to_bytes(resp):
|
|||||||
|
|
||||||
By default yaml serializes to utf-8 encoded bytestrings.
|
By default yaml serializes to utf-8 encoded bytestrings.
|
||||||
When this cassette is loaded by python3, it's automatically decoded
|
When this cassette is loaded by python3, it's automatically decoded
|
||||||
into unicode strings. This makes sure that it stays a bytestring, since
|
into unicode strings. This makes sure that it stays a bytestring, since
|
||||||
that's what all the internal httplib machinery is expecting.
|
that's what all the internal httplib machinery is expecting.
|
||||||
|
|
||||||
For more info on py3 yaml:
|
For more info on py3 yaml:
|
||||||
@@ -37,19 +37,43 @@ def convert_body_to_bytes(resp):
|
|||||||
return 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):
|
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 type(resp) is not dict:
|
||||||
if not isinstance(resp['body']['string'], six.text_type):
|
# Some of the tests just serialize and deserialize a string.
|
||||||
resp['body']['string'] = resp['body']['string'].decode('utf-8')
|
return _convert_string_to_unicode(resp)
|
||||||
except (KeyError, TypeError, UnicodeDecodeError):
|
else:
|
||||||
# The thing we were converting either wasn't a dictionary or didn't
|
body = resp.get('body')
|
||||||
# have the keys we were expecting. Some of the tests just serialize
|
|
||||||
# and deserialize a string.
|
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
|
return resp
|
||||||
|
|||||||
@@ -9,16 +9,21 @@ def deserialize(cassette_string):
|
|||||||
|
|
||||||
|
|
||||||
def serialize(cassette_dict):
|
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:
|
try:
|
||||||
return json.dumps(cassette_dict, indent=4)
|
return json.dumps(cassette_dict, indent=4)
|
||||||
except UnicodeDecodeError as original:
|
except UnicodeDecodeError as original: # py2
|
||||||
raise UnicodeDecodeError(
|
raise UnicodeDecodeError(
|
||||||
original.encoding,
|
original.encoding,
|
||||||
b"Error serializing cassette to JSON",
|
b"Error serializing cassette to JSON",
|
||||||
original.start,
|
original.start,
|
||||||
original.end,
|
original.end,
|
||||||
original.args[-1] +
|
original.args[-1] + error_message
|
||||||
("Does this HTTP interaction contain binary data? "
|
|
||||||
"If so, use a different serializer (like the yaml serializer) "
|
|
||||||
"for this request?")
|
|
||||||
)
|
)
|
||||||
|
except TypeError as original: # py3
|
||||||
|
raise TypeError(error_message)
|
||||||
|
|||||||
Reference in New Issue
Block a user