OLD | NEW |
(Empty) | |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import difflib |
| 6 import json |
| 7 import os |
| 8 import pprint |
| 9 |
| 10 from collections import OrderedDict |
| 11 |
| 12 try: |
| 13 import yaml # pylint: disable=F0401 |
| 14 except ImportError: |
| 15 yaml = None |
| 16 |
| 17 |
| 18 NonExistant = object() |
| 19 |
| 20 |
| 21 SUPPORTED_SERIALIZERS = {'json', 'yaml'} |
| 22 SERIALIZERS = {} |
| 23 |
| 24 |
| 25 # JSON support |
| 26 def re_encode(obj): |
| 27 if isinstance(obj, dict): |
| 28 return {re_encode(k): re_encode(v) for k, v in obj.iteritems()} |
| 29 elif isinstance(obj, list): |
| 30 return [re_encode(i) for i in obj] |
| 31 elif isinstance(obj, unicode): |
| 32 return obj.encode('utf-8') |
| 33 else: |
| 34 return obj |
| 35 |
| 36 |
| 37 SERIALIZERS['json'] = ( |
| 38 lambda s: re_encode(json.load(s)), |
| 39 lambda data, stream: json.dump( |
| 40 data, stream, sort_keys=True, indent=2, separators=(',', ': '))) |
| 41 |
| 42 |
| 43 # YAML support |
| 44 if yaml: |
| 45 _YAMLSafeLoader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) |
| 46 _YAMLSafeDumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) |
| 47 |
| 48 MAPPING_TAG = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG |
| 49 |
| 50 class OrderedLoader(_YAMLSafeLoader): |
| 51 def __init__(self, *args, **kwargs): # pylint: disable=E1002 |
| 52 super(OrderedLoader, self).__init__(*args, **kwargs) |
| 53 self.add_constructor( |
| 54 MAPPING_TAG, |
| 55 lambda loader, node: OrderedDict(loader.construct_pairs(node))) |
| 56 |
| 57 class OrderedDumper(_YAMLSafeDumper): |
| 58 def __init__(self, *args, **kwargs): # pylint: disable=E1002 |
| 59 super(OrderedDumper, self).__init__(*args, **kwargs) |
| 60 def _dict_representer(dumper, data): |
| 61 return dumper.represent_mapping(MAPPING_TAG, data.items()) |
| 62 self.add_representer(OrderedDict, _dict_representer) |
| 63 |
| 64 SERIALIZERS['yaml'] = ( |
| 65 lambda stream: yaml.load(stream, OrderedLoader), |
| 66 lambda data, stream: yaml.dump( |
| 67 data, stream, OrderedDumper, default_flow_style=False, |
| 68 encoding='utf-8')) |
| 69 |
| 70 |
| 71 def GetCurrentData(test): |
| 72 """ |
| 73 @type test: Test() |
| 74 @returns: The deserialized data (or NonExistant), and a boolean indicating if |
| 75 the current serialized data is in the same format which was |
| 76 requested by |test|. |
| 77 @rtype: (dict, bool) |
| 78 """ |
| 79 for ext in sorted(SUPPORTED_SERIALIZERS, key=lambda s: s != test.ext): |
| 80 path = test.expect_path(ext) |
| 81 if path is None: |
| 82 return None, True |
| 83 |
| 84 if ext not in SERIALIZERS and ext == test.ext: |
| 85 raise Exception('The package to support %s is not installed.' % ext) |
| 86 if os.path.exists(path): |
| 87 try: |
| 88 with open(path, 'rb') as f: |
| 89 data = SERIALIZERS[ext][0](f) |
| 90 except ValueError as err: |
| 91 raise ValueError('Bad format of %s: %s' % (path, err)) |
| 92 return data, ext == test.ext |
| 93 return NonExistant, True |
| 94 |
| 95 |
| 96 def WriteNewData(test, data): |
| 97 """ |
| 98 @type test: Test() |
| 99 """ |
| 100 if data is None: |
| 101 return |
| 102 if test.ext not in SUPPORTED_SERIALIZERS: |
| 103 raise Exception('%s is not a supported serializer.' % test.ext) |
| 104 if test.ext not in SERIALIZERS: |
| 105 raise Exception('The package to support %s is not installed.' % test.ext) |
| 106 with open(test.expect_path(), 'wb') as f: |
| 107 SERIALIZERS[test.ext][1](data, f) |
| 108 |
| 109 |
| 110 def DiffData(old, new): |
| 111 """ |
| 112 Takes old data and new data, then returns a textual diff as a list of lines. |
| 113 @type old: dict |
| 114 @type new: dict |
| 115 @rtype: [str] |
| 116 """ |
| 117 if old is NonExistant: |
| 118 return new |
| 119 if old == new: |
| 120 return None |
| 121 else: |
| 122 return list(difflib.context_diff( |
| 123 pprint.pformat(old).splitlines(), |
| 124 pprint.pformat(new).splitlines(), |
| 125 fromfile='expected', tofile='current', |
| 126 n=4, lineterm='' |
| 127 )) |
OLD | NEW |