diff --git a/tests/unit/test_cassettes.py b/tests/unit/test_cassettes.py index 1c5b84c..4c4818f 100644 --- a/tests/unit/test_cassettes.py +++ b/tests/unit/test_cassettes.py @@ -7,10 +7,10 @@ from vcr.errors import UnhandledHTTPRequestError def test_cassette_load(tmpdir): a_file = tmpdir.join('test_cassette.yml') - a_file.write(yaml.dump([ + a_file.write(yaml.dump({'interactions': [ {'request': {'body': '', 'uri': 'foo', 'method': 'GET', 'headers': {}}, 'response': 'bar'} - ])) + ]})) a_cassette = Cassette.load(str(a_file)) assert len(a_cassette) == 1 diff --git a/tests/unit/test_migration.py b/tests/unit/test_migration.py index 5f2472c..7638910 100644 --- a/tests/unit/test_migration.py +++ b/tests/unit/test_migration.py @@ -7,7 +7,7 @@ import vcr.migration def test_try_migrate_with_json(tmpdir): - cassette = tmpdir.join('cassette').strpath + cassette = tmpdir.join('cassette.json').strpath shutil.copy('tests/fixtures/migration/old_cassette.json', cassette) assert vcr.migration.try_migrate(cassette) with open('tests/fixtures/migration/new_cassette.json', 'r') as f: @@ -18,7 +18,7 @@ def test_try_migrate_with_json(tmpdir): def test_try_migrate_with_yaml(tmpdir): - cassette = tmpdir.join('cassette').strpath + cassette = tmpdir.join('cassette.yaml').strpath shutil.copy('tests/fixtures/migration/old_cassette.yaml', cassette) assert vcr.migration.try_migrate(cassette) with open('tests/fixtures/migration/new_cassette.yaml', 'r') as f: diff --git a/vcr/migration.py b/vcr/migration.py index e4c7d3f..e8ea73a 100644 --- a/vcr/migration.py +++ b/vcr/migration.py @@ -48,6 +48,7 @@ def build_uri(**parts): def migrate_json(in_fp, out_fp): data = json.load(in_fp) + interactions = [] for item in data: req = item['request'] res = item['response'] @@ -62,9 +63,10 @@ def migrate_json(in_fp, out_fp): response_headers.setdefault(k, []) response_headers[k].append(v) res['headers'] = response_headers + interactions.append({'request':req, 'response': res}) - json.dump(data, out_fp, indent=4) + json.dump({'interactions':interactions, 'version':1}, out_fp, indent=4) def _restore_frozenset(): @@ -93,6 +95,7 @@ def _old_deserialize(cassette_string): def migrate_yml(in_fp, out_fp): (requests, responses) = _old_deserialize(in_fp.read()) + interactions = [] for req, res in zip(requests, responses): if not isinstance(req, request.Request): raise Exception("already migrated") @@ -114,10 +117,11 @@ def migrate_yml(in_fp, out_fp): response_headers.setdefault(k, []) response_headers[k].append(v) res['headers'] = response_headers + interactions.append({'request': req._to_dict(), 'response': res}) data = yamlserializer.serialize({ - "requests": requests, - "responses": responses, + "interactions": interactions, + "version": 1 }) out_fp.write(data) @@ -134,14 +138,13 @@ def migrate(file_path, migration_fn): def try_migrate(path): - try: # try to migrate as json + if path.endswith('.json'): migrate(path, migrate_json) - except Exception as e: # probably the file is not a json - try: # let's try to migrate as yaml - migrate(path, migrate_yml) - except Exception: # oops probably the file is not a cassette - return False - return True + return True + elif path.endswith('.yaml') or path.endswith('.yml'): + migrate(path, migrate_yml) + return True + return False def main(): diff --git a/vcr/serialize.py b/vcr/serialize.py index 36275b4..ac1754c 100644 --- a/vcr/serialize.py +++ b/vcr/serialize.py @@ -1,5 +1,6 @@ from vcr.serializers import compat from vcr.request import Request +import yaml #version 1 cassettes started with VCR 1.0.x. Before 1.0.x, there was no versioning. CASSETTE_FORMAT_VERSION = 1 @@ -16,15 +17,25 @@ Serializing: bytestring -> string (yaml persists to utf-8) Deserializing: string (yaml converts from utf-8) -> bytestring """ +def _looks_like_an_old_cassette(data): + return isinstance(data, list) and len(data) and 'request' in data[0] + +def _warn_about_old_cassette_format(data): + raise ValueError( + "Your cassette files were generated in an older version " + "of VCR. Delete your cassettes or run the migration script." + "See http://git.io/mHhLBg for more details." + ) def deserialize(cassette_string, serializer): - data = serializer.deserialize(cassette_string) - if not isinstance(data, dict): - raise ValueError( - "Your cassette files were generated in an older version " - "of VCR. Delete your cassettes or run the migration script." - "See http://git.io/mHhLBg for more details." - ) + try: + data = serializer.deserialize(cassette_string) + # Old cassettes used to use yaml object thingy so I have to + # check for some fairly stupid exceptions here + except (ImportError, yaml.constructor.ConstructorError): + _warn_about_old_cassette_format(data) + if _looks_like_an_old_cassette(data): + _warn_about_old_cassette_format(data) requests = [Request._from_dict(r['request']) for r in data['interactions']] responses = [compat.convert_to_bytes(r['response']) for r in data['interactions']]