Kirill Simonov | cc316a4 | 2006-04-11 00:34:16 +0000 | [diff] [blame^] | 1 | |
| 2 | __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer', |
| 3 | 'RepresenterError'] |
| 4 | |
| 5 | from error import * |
| 6 | from nodes import * |
| 7 | from detector import * |
| 8 | |
| 9 | try: |
| 10 | import datetime |
| 11 | datetime_available = True |
| 12 | except ImportError: |
| 13 | datetime_available = False |
| 14 | |
| 15 | try: |
| 16 | set |
| 17 | except NameError: |
| 18 | from sets import Set as set |
| 19 | |
| 20 | class RepresenterError(YAMLError): |
| 21 | pass |
| 22 | |
| 23 | class BaseRepresenter(BaseDetector): |
| 24 | |
| 25 | DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str' |
| 26 | DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq' |
| 27 | DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map' |
| 28 | |
| 29 | def __init__(self, serializer): |
| 30 | self.serializer = serializer |
| 31 | self.represented_objects = {} |
| 32 | |
| 33 | def close(self): |
| 34 | self.serializer.close() |
| 35 | |
| 36 | def represent(self, native): |
| 37 | node = self.represent_object(native) |
| 38 | self.serializer.serialize(node) |
| 39 | self.represented_objects = {} |
| 40 | |
| 41 | def represent_object(self, native): |
| 42 | if self.ignore_aliases(native): |
| 43 | alias_key = None |
| 44 | else: |
| 45 | alias_key = id(native) |
| 46 | if alias_key is not None: |
| 47 | if alias_key in self.represented_objects: |
| 48 | node = self.represented_objects[alias_key] |
| 49 | if node is None: |
| 50 | raise RepresenterError("recursive objects are not allowed: %r" % native) |
| 51 | return node |
| 52 | self.represented_objects[alias_key] = None |
| 53 | for native_type in type(native).__mro__: |
| 54 | if native_type in self.yaml_representers: |
| 55 | node = self.yaml_representers[native_type](self, native) |
| 56 | break |
| 57 | else: |
| 58 | if None in self.yaml_representers: |
| 59 | node = self.yaml_representers[None](self, native) |
| 60 | else: |
| 61 | node = ScalarNode(None, unicode(native)) |
| 62 | if alias_key is not None: |
| 63 | self.represented_objects[alias_key] = node |
| 64 | return node |
| 65 | |
| 66 | def add_representer(cls, native_type, representer): |
| 67 | if not 'yaml_representers' in cls.__dict__: |
| 68 | cls.yaml_representers = cls.yaml_representers.copy() |
| 69 | cls.yaml_representers[native_type] = representer |
| 70 | add_representer = classmethod(add_representer) |
| 71 | |
| 72 | yaml_representers = {} |
| 73 | |
| 74 | def represent_scalar(self, tag, value, style=None): |
| 75 | detected_tag = self.detect(value) |
| 76 | if detected_tag is None: |
| 77 | detected_tag = self.DEFAULT_SCALAR_TAG |
| 78 | implicit = (tag == detected_tag) |
| 79 | if tag == self.DEFAULT_SCALAR_TAG: |
| 80 | tag = None |
| 81 | return ScalarNode(tag, value, implicit=implicit, style=style) |
| 82 | |
| 83 | def represent_sequence(self, tag, sequence, flow_style=None): |
| 84 | if tag == self.DEFAULT_SEQUENCE_TAG: |
| 85 | tag = None |
| 86 | value = [] |
| 87 | for item in sequence: |
| 88 | value.append(self.represent_object(item)) |
| 89 | return SequenceNode(tag, value, flow_style=flow_style) |
| 90 | |
| 91 | def represent_mapping(self, tag, mapping, flow_style=None): |
| 92 | if tag == self.DEFAULT_MAPPING_TAG: |
| 93 | tag = None |
| 94 | value = {} |
| 95 | if hasattr(mapping, 'keys'): |
| 96 | for item_key in mapping.keys(): |
| 97 | item_value = mapping[item_key] |
| 98 | value[self.represent_object(item_key)] = \ |
| 99 | self.represent_object(item_value) |
| 100 | else: |
| 101 | for item_key, item_value in mapping: |
| 102 | value[self.represent_object(item_key)] = \ |
| 103 | self.represent_object(item_value) |
| 104 | return MappingNode(tag, value, flow_style=flow_style) |
| 105 | |
| 106 | def ignore_aliases(self, native): |
| 107 | return False |
| 108 | |
| 109 | class SafeRepresenter(Detector, BaseRepresenter): |
| 110 | |
| 111 | def ignore_aliases(self, native): |
| 112 | if native in [None, ()]: |
| 113 | return True |
| 114 | if isinstance(native, (str, unicode, bool, int, float)): |
| 115 | return True |
| 116 | |
| 117 | def represent_none(self, native): |
| 118 | return self.represent_scalar(u'tag:yaml.org,2002:null', |
| 119 | u'null') |
| 120 | |
| 121 | def represent_str(self, native): |
| 122 | try: |
| 123 | native.encode('ascii') |
| 124 | ascii = True |
| 125 | except (UnicodeDecodeError, UnicodeEncodeError): |
| 126 | ascii = False |
| 127 | if ascii: |
| 128 | return self.represent_scalar(u'tag:yaml.org,2002:str', |
| 129 | unicode(native, 'ascii')) |
| 130 | else: |
| 131 | return self.represent_scalar(u'tag:yaml.org,2002:binary', |
| 132 | unicode(native.encode('base64')), style='|') |
| 133 | |
| 134 | def represent_unicode(self, native): |
| 135 | return self.represent_scalar(u'tag:yaml.org,2002:str', native) |
| 136 | |
| 137 | def represent_bool(self, native): |
| 138 | if native: |
| 139 | value = u'true' |
| 140 | else: |
| 141 | value = u'false' |
| 142 | return self.represent_scalar(u'tag:yaml.org,2002:bool', value) |
| 143 | |
| 144 | def represent_int(self, native): |
| 145 | return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(native)) |
| 146 | |
| 147 | def represent_long(self, native): |
| 148 | return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(native)) |
| 149 | |
| 150 | inf_value = 1e300000 |
| 151 | nan_value = inf_value/inf_value |
| 152 | |
| 153 | def represent_float(self, native): |
| 154 | if native == self.inf_value: |
| 155 | value = u'.inf' |
| 156 | elif native == -self.inf_value: |
| 157 | value = u'-.inf' |
| 158 | elif native == self.nan_value or native != native: |
| 159 | value = u'.nan' |
| 160 | else: |
| 161 | value = unicode(native) |
| 162 | return self.represent_scalar(u'tag:yaml.org,2002:float', value) |
| 163 | |
| 164 | def represent_list(self, native): |
| 165 | pairs = (len(native) > 0) |
| 166 | for item in native: |
| 167 | if not isinstance(item, tuple) or len(item) != 2: |
| 168 | pairs = False |
| 169 | break |
| 170 | if not pairs: |
| 171 | return self.represent_sequence(u'tag:yaml.org,2002:seq', native) |
| 172 | value = [] |
| 173 | for item_key, item_value in native: |
| 174 | value.append(self.represent_mapping(u'tag:yaml.org,2002:map', |
| 175 | [(item_key, item_value)])) |
| 176 | return SequenceNode(u'tag:yaml.org,2002:pairs', value) |
| 177 | |
| 178 | def represent_dict(self, native): |
| 179 | return self.represent_mapping(u'tag:yaml.org,2002:map', native) |
| 180 | |
| 181 | def represent_set(self, native): |
| 182 | value = {} |
| 183 | for key in native: |
| 184 | value[key] = None |
| 185 | return self.represent_mapping(u'tag:yaml.org,2002:set', value) |
| 186 | |
| 187 | def represent_date(self, native): |
| 188 | value = u'%04d-%02d-%02d' % (native.year, native.month, native.day) |
| 189 | return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value) |
| 190 | |
| 191 | def represent_datetime(self, native): |
| 192 | value = u'%04d-%02d-%02d %02d:%02d:%02d' \ |
| 193 | % (native.year, native.month, native.day, |
| 194 | native.hour, native.minute, native.second) |
| 195 | if native.microsecond: |
| 196 | value += u'.' + unicode(native.microsecond/1000000.0).split(u'.')[1] |
| 197 | if native.utcoffset(): |
| 198 | value += unicode(native.utcoffset()) |
| 199 | return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value) |
| 200 | |
| 201 | def represent_undefined(self, native): |
| 202 | raise RepresenterError("cannot represent an object: %s" % native) |
| 203 | |
| 204 | SafeRepresenter.add_representer(type(None), |
| 205 | SafeRepresenter.represent_none) |
| 206 | |
| 207 | SafeRepresenter.add_representer(str, |
| 208 | SafeRepresenter.represent_str) |
| 209 | |
| 210 | SafeRepresenter.add_representer(unicode, |
| 211 | SafeRepresenter.represent_unicode) |
| 212 | |
| 213 | SafeRepresenter.add_representer(bool, |
| 214 | SafeRepresenter.represent_bool) |
| 215 | |
| 216 | SafeRepresenter.add_representer(int, |
| 217 | SafeRepresenter.represent_int) |
| 218 | |
| 219 | SafeRepresenter.add_representer(long, |
| 220 | SafeRepresenter.represent_long) |
| 221 | |
| 222 | SafeRepresenter.add_representer(float, |
| 223 | SafeRepresenter.represent_float) |
| 224 | |
| 225 | SafeRepresenter.add_representer(list, |
| 226 | SafeRepresenter.represent_list) |
| 227 | |
| 228 | SafeRepresenter.add_representer(dict, |
| 229 | SafeRepresenter.represent_dict) |
| 230 | |
| 231 | SafeRepresenter.add_representer(set, |
| 232 | SafeRepresenter.represent_set) |
| 233 | |
| 234 | if datetime_available: |
| 235 | SafeRepresenter.add_representer(datetime.date, |
| 236 | SafeRepresenter.represent_date) |
| 237 | SafeRepresenter.add_representer(datetime.datetime, |
| 238 | SafeRepresenter.represent_datetime) |
| 239 | |
| 240 | SafeRepresenter.add_representer(None, |
| 241 | SafeRepresenter.represent_undefined) |
| 242 | |
| 243 | class Representer(SafeRepresenter): |
| 244 | pass |
| 245 | |