From e50f917cf4da65ff2bde3291e3da56822145f97e Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Tue, 6 May 2014 18:48:29 -1000 Subject: [PATCH] Make Serializers Dumber Let's have the serializer just worry about serializing the dict that we hand it, and move the unicode stuff up to a serialize module. This should hopefully let us move toward using a version string in cassettes. --- tests/integration/test_register_serializer.py | 2 +- vcr/persist.py | 5 +-- vcr/serialize.py | 33 +++++++++++++++++++ vcr/serializers/jsonserializer.py | 18 ++-------- vcr/serializers/yamlserializer.py | 31 ++--------------- 5 files changed, 42 insertions(+), 47 deletions(-) create mode 100644 vcr/serialize.py diff --git a/tests/integration/test_register_serializer.py b/tests/integration/test_register_serializer.py index 8e121f8..0349c39 100644 --- a/tests/integration/test_register_serializer.py +++ b/tests/integration/test_register_serializer.py @@ -10,7 +10,7 @@ class MockSerializer(object): def deserialize(self, cassette_string): self.serialize_count += 1 self.cassette_string = cassette_string - return ([], []) + return [] def serialize(self, cassette_dict): self.deserialize_count += 1 diff --git a/vcr/persist.py b/vcr/persist.py index 8c00b32..4ae8ec3 100644 --- a/vcr/persist.py +++ b/vcr/persist.py @@ -2,6 +2,7 @@ import tempfile from .persisters.filesystem import FilesystemPersister from . import migration +from . import serialize def _check_for_old_cassette(cassette_content): @@ -21,7 +22,7 @@ def load_cassette(cassette_path, serializer): with open(cassette_path) as f: cassette_content = f.read() try: - cassette = serializer.deserialize(cassette_content) + cassette = serialize.deserialize(cassette_content, serializer) except TypeError: _check_for_old_cassette(cassette_content) raise @@ -29,5 +30,5 @@ def load_cassette(cassette_path, serializer): def save_cassette(cassette_path, cassette_dict, serializer): - data = serializer.serialize(cassette_dict) + data = serialize.serialize(cassette_dict, serializer) FilesystemPersister.write(cassette_path, data) diff --git a/vcr/serialize.py b/vcr/serialize.py new file mode 100644 index 0000000..6bdfa56 --- /dev/null +++ b/vcr/serialize.py @@ -0,0 +1,33 @@ +from serializers import compat +from vcr.request import Request + +""" +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 deserialize(cassette_string, serializer): + data = serializer.deserialize(cassette_string) + requests = [Request._from_dict(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 + + +def serialize(cassette_dict, serializer): + data = ([{ + 'request': request._to_dict(), + 'response': compat.convert_to_unicode(response), + } for request, response in zip( + cassette_dict['requests'], + cassette_dict['responses'], + )]) + return serializer.serialize(data) diff --git a/vcr/serializers/jsonserializer.py b/vcr/serializers/jsonserializer.py index 2dcfa09..85a5462 100644 --- a/vcr/serializers/jsonserializer.py +++ b/vcr/serializers/jsonserializer.py @@ -1,5 +1,3 @@ -from vcr.request import Request -from . import compat try: import simplejson as json except ImportError: @@ -7,26 +5,16 @@ except ImportError: def deserialize(cassette_string): - data = json.loads(cassette_string) - requests = [Request._from_dict(r['request']) for r in data] - responses = [compat.convert_to_bytes(r['response']) for r in data] - return requests, responses + return json.loads(cassette_string) def serialize(cassette_dict): - data = ([{ - 'request': request._to_dict(), - 'response': compat.convert_to_unicode(response), - } for request, response in zip( - cassette_dict['requests'], - cassette_dict['responses'] - )]) try: - return json.dumps(data, indent=4) + return json.dumps(cassette_dict, indent=4) except UnicodeDecodeError: 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", + "If so, use a different serializer (like the yaml serializer) for ", "this request" ) diff --git a/vcr/serializers/yamlserializer.py b/vcr/serializers/yamlserializer.py index df42d9c..78862e7 100644 --- a/vcr/serializers/yamlserializer.py +++ b/vcr/serializers/yamlserializer.py @@ -1,41 +1,14 @@ import yaml -from vcr.request import Request -from . import compat - # Use the libYAML versions if possible try: from yaml import CLoader as Loader, CDumper as Dumper 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 deserialize(cassette_string): - data = yaml.load(cassette_string, Loader=Loader) - requests = [Request._from_dict(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 + return yaml.load(cassette_string, Loader=Loader) def serialize(cassette_dict): - data = ([{ - 'request': request._to_dict(), - 'response': response, - } for request, response in zip( - cassette_dict['requests'], - [compat.convert_to_unicode(r) for r in cassette_dict['responses']], - )]) - return yaml.dump(data, Dumper=Dumper) + return yaml.dump(cassette_dict, Dumper=Dumper)