1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-09 01:03:24 +00:00

Add Python 2.3 support

This commit also adds the 'six' dependency
This commit is contained in:
Åsmund Grammeltvedt
2014-02-02 21:53:12 +01:00
committed by Kevin McCarthy
parent 2385176084
commit a73da71159
25 changed files with 296 additions and 122 deletions

66
vcr/serializers/compat.py Normal file
View File

@@ -0,0 +1,66 @@
import six
def convert_to_bytes(resp):
resp = convert_headers_to_bytes(resp)
resp = convert_body_to_bytes(resp)
return resp
def convert_to_unicode(resp):
resp = convert_headers_to_unicode(resp)
resp = convert_body_to_unicode(resp)
return resp
def convert_headers_to_bytes(resp):
try:
resp['headers'] = [h.encode('utf-8') for h in resp['headers']]
except (KeyError, TypeError):
pass
return resp
def convert_headers_to_unicode(resp):
try:
resp['headers'] = [h.decode('utf-8') for h in resp['headers']]
except (KeyError, TypeError):
pass
return resp
def convert_body_to_bytes(resp):
"""
If the request body is a string, encode it to bytes (for python3 support)
By default yaml serializes to utf-8 encoded bytestrings.
When this cassette is loaded by python3, it's automatically decoded
into unicode strings. This makes sure that it stays a bytestring, since
that's what all the internal httplib machinery is expecting.
For more info on py3 yaml: http://pyyaml.org/wiki/PyYAMLDocumentation#Python3support
"""
try:
if not isinstance(resp['body']['string'], six.binary_type):
resp['body']['string'] = resp['body']['string'].encode('utf-8')
except (KeyError, TypeError, UnicodeEncodeError):
# 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.
# Also, sometimes the thing actually is binary, so if you can't encode
# it, just give up.
pass
return resp
def convert_body_to_unicode(resp):
"""
If the request 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.
# Also, sometimes the thing actually is binary, so if you can't decode
# it, just give up.
pass
return resp

View File

@@ -1,4 +1,5 @@
from vcr.request import Request
from . import compat
try:
import simplejson as json
except ImportError:
@@ -11,22 +12,17 @@ def _json_default(obj):
return obj
def _fix_response_unicode(d):
d['body']['string'] = d['body']['string'].encode('utf-8')
return d
def deserialize(cassette_string):
data = json.loads(cassette_string)
requests = [Request._from_dict(r['request']) for r in data]
responses = [_fix_response_unicode(r['response']) for r in data]
responses = [compat.convert_to_bytes(r['response']) for r in data]
return requests, responses
def serialize(cassette_dict):
data = ([{
'request': request._to_dict(),
'response': response,
'response': compat.convert_to_unicode(response),
} for request, response in zip(
cassette_dict['requests'],
cassette_dict['responses']

View File

@@ -1,4 +1,6 @@
import sys
import yaml
from . import compat
# Use the libYAML versions if possible
try:
@@ -6,11 +8,38 @@ try:
except ImportError:
from yaml import Loader, Dumper
"""
Just a general note on the serialization philosophy here:
I prefer cassettes to be human-readable if possible. Yaml serializes
bytestrings to !!binary, which isn't readable, so I would like to serialize to
strings and from strings, which yaml will encode as utf-8 automatically.
All the internal HTTP stuff expects bytestrings, so this whole serialization
process feels backwards.
Serializing: bytestring -> string (yaml persists to utf-8)
Deserializing: string (yaml converts from utf-8) -> bytestring
"""
def _restore_frozenset():
"""
Restore __builtin__.frozenset for cassettes serialized in python2 but
deserialized in python3 and builtins.frozenset for cassettes serialized
in python3 and deserialized in python2
"""
if '__builtin__' not in sys.modules:
import builtins
sys.modules['__builtin__'] = builtins
if 'builtins' not in sys.modules:
sys.modules['builtins'] = sys.modules['__builtin__']
def deserialize(cassette_string):
_restore_frozenset()
data = yaml.load(cassette_string, Loader=Loader)
requests = [r['request'] for r in data]
responses = [r['response'] for r in data]
responses = [compat.convert_to_bytes(r['response']) for r in data]
return requests, responses
@@ -20,6 +49,6 @@ def serialize(cassette_dict):
'response': response,
} for request, response in zip(
cassette_dict['requests'],
cassette_dict['responses']
[compat.convert_to_unicode(r) for r in cassette_dict['responses']],
)])
return yaml.dump(data, Dumper=Dumper)