1 2__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer', 3 'RepresenterError'] 4 5from .error import * 6from .nodes import * 7 8import datetime, sys, copyreg, types, base64, collections 9 10class RepresenterError(YAMLError): 11 pass 12 13class BaseRepresenter: 14 15 yaml_representers = {} 16 yaml_multi_representers = {} 17 18 def __init__(self, default_style=None, default_flow_style=None): 19 self.default_style = default_style 20 self.default_flow_style = default_flow_style 21 self.represented_objects = {} 22 self.object_keeper = [] 23 self.alias_key = None 24 25 def represent(self, data): 26 node = self.represent_data(data) 27 self.serialize(node) 28 self.represented_objects = {} 29 self.object_keeper = [] 30 self.alias_key = None 31 32 def represent_data(self, data): 33 if self.ignore_aliases(data): 34 self.alias_key = None 35 else: 36 self.alias_key = id(data) 37 if self.alias_key is not None: 38 if self.alias_key in self.represented_objects: 39 node = self.represented_objects[self.alias_key] 40 #if node is None: 41 # raise RepresenterError("recursive objects are not allowed: %r" % data) 42 return node 43 #self.represented_objects[alias_key] = None 44 self.object_keeper.append(data) 45 data_types = type(data).__mro__ 46 if data_types[0] in self.yaml_representers: 47 node = self.yaml_representers[data_types[0]](self, data) 48 else: 49 for data_type in data_types: 50 if data_type in self.yaml_multi_representers: 51 node = self.yaml_multi_representers[data_type](self, data) 52 break 53 else: 54 if None in self.yaml_multi_representers: 55 node = self.yaml_multi_representers[None](self, data) 56 elif None in self.yaml_representers: 57 node = self.yaml_representers[None](self, data) 58 else: 59 node = ScalarNode(None, str(data)) 60 #if alias_key is not None: 61 # self.represented_objects[alias_key] = node 62 return node 63 64 @classmethod 65 def add_representer(cls, data_type, representer): 66 if not 'yaml_representers' in cls.__dict__: 67 cls.yaml_representers = cls.yaml_representers.copy() 68 cls.yaml_representers[data_type] = representer 69 70 @classmethod 71 def add_multi_representer(cls, data_type, representer): 72 if not 'yaml_multi_representers' in cls.__dict__: 73 cls.yaml_multi_representers = cls.yaml_multi_representers.copy() 74 cls.yaml_multi_representers[data_type] = representer 75 76 def represent_scalar(self, tag, value, style=None): 77 if style is None: 78 style = self.default_style 79 node = ScalarNode(tag, value, style=style) 80 if self.alias_key is not None: 81 self.represented_objects[self.alias_key] = node 82 return node 83 84 def represent_sequence(self, tag, sequence, flow_style=None): 85 value = [] 86 node = SequenceNode(tag, value, flow_style=flow_style) 87 if self.alias_key is not None: 88 self.represented_objects[self.alias_key] = node 89 best_style = True 90 for item in sequence: 91 node_item = self.represent_data(item) 92 if not (isinstance(node_item, ScalarNode) and not node_item.style): 93 best_style = False 94 value.append(node_item) 95 if flow_style is None: 96 if self.default_flow_style is not None: 97 node.flow_style = self.default_flow_style 98 else: 99 node.flow_style = best_style 100 return node 101 102 def represent_mapping(self, tag, mapping, flow_style=None): 103 value = [] 104 node = MappingNode(tag, value, flow_style=flow_style) 105 if self.alias_key is not None: 106 self.represented_objects[self.alias_key] = node 107 best_style = True 108 if hasattr(mapping, 'items'): 109 mapping = list(mapping.items()) 110 try: 111 mapping = sorted(mapping) 112 except TypeError: 113 pass 114 for item_key, item_value in mapping: 115 node_key = self.represent_data(item_key) 116 node_value = self.represent_data(item_value) 117 if not (isinstance(node_key, ScalarNode) and not node_key.style): 118 best_style = False 119 if not (isinstance(node_value, ScalarNode) and not node_value.style): 120 best_style = False 121 value.append((node_key, node_value)) 122 if flow_style is None: 123 if self.default_flow_style is not None: 124 node.flow_style = self.default_flow_style 125 else: 126 node.flow_style = best_style 127 return node 128 129 def ignore_aliases(self, data): 130 return False 131 132class SafeRepresenter(BaseRepresenter): 133 134 def ignore_aliases(self, data): 135 if data is None: 136 return True 137 if isinstance(data, tuple) and data == (): 138 return True 139 if isinstance(data, (str, bytes, bool, int, float)): 140 return True 141 142 def represent_none(self, data): 143 return self.represent_scalar('tag:yaml.org,2002:null', 'null') 144 145 def represent_str(self, data): 146 return self.represent_scalar('tag:yaml.org,2002:str', data) 147 148 def represent_binary(self, data): 149 if hasattr(base64, 'encodebytes'): 150 data = base64.encodebytes(data).decode('ascii') 151 else: 152 data = base64.encodestring(data).decode('ascii') 153 return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|') 154 155 def represent_bool(self, data): 156 if data: 157 value = 'true' 158 else: 159 value = 'false' 160 return self.represent_scalar('tag:yaml.org,2002:bool', value) 161 162 def represent_int(self, data): 163 return self.represent_scalar('tag:yaml.org,2002:int', str(data)) 164 165 inf_value = 1e300 166 while repr(inf_value) != repr(inf_value*inf_value): 167 inf_value *= inf_value 168 169 def represent_float(self, data): 170 if data != data or (data == 0.0 and data == 1.0): 171 value = '.nan' 172 elif data == self.inf_value: 173 value = '.inf' 174 elif data == -self.inf_value: 175 value = '-.inf' 176 else: 177 value = repr(data).lower() 178 # Note that in some cases `repr(data)` represents a float number 179 # without the decimal parts. For instance: 180 # >>> repr(1e17) 181 # '1e17' 182 # Unfortunately, this is not a valid float representation according 183 # to the definition of the `!!float` tag. We fix this by adding 184 # '.0' before the 'e' symbol. 185 if '.' not in value and 'e' in value: 186 value = value.replace('e', '.0e', 1) 187 return self.represent_scalar('tag:yaml.org,2002:float', value) 188 189 def represent_list(self, data): 190 #pairs = (len(data) > 0 and isinstance(data, list)) 191 #if pairs: 192 # for item in data: 193 # if not isinstance(item, tuple) or len(item) != 2: 194 # pairs = False 195 # break 196 #if not pairs: 197 return self.represent_sequence('tag:yaml.org,2002:seq', data) 198 #value = [] 199 #for item_key, item_value in data: 200 # value.append(self.represent_mapping(u'tag:yaml.org,2002:map', 201 # [(item_key, item_value)])) 202 #return SequenceNode(u'tag:yaml.org,2002:pairs', value) 203 204 def represent_dict(self, data): 205 return self.represent_mapping('tag:yaml.org,2002:map', data) 206 207 def represent_set(self, data): 208 value = {} 209 for key in data: 210 value[key] = None 211 return self.represent_mapping('tag:yaml.org,2002:set', value) 212 213 def represent_date(self, data): 214 value = data.isoformat() 215 return self.represent_scalar('tag:yaml.org,2002:timestamp', value) 216 217 def represent_datetime(self, data): 218 value = data.isoformat(' ') 219 return self.represent_scalar('tag:yaml.org,2002:timestamp', value) 220 221 def represent_yaml_object(self, tag, data, cls, flow_style=None): 222 if hasattr(data, '__getstate__'): 223 state = data.__getstate__() 224 else: 225 state = data.__dict__.copy() 226 return self.represent_mapping(tag, state, flow_style=flow_style) 227 228 def represent_undefined(self, data): 229 raise RepresenterError("cannot represent an object: %s" % data) 230 231SafeRepresenter.add_representer(type(None), 232 SafeRepresenter.represent_none) 233 234SafeRepresenter.add_representer(str, 235 SafeRepresenter.represent_str) 236 237SafeRepresenter.add_representer(bytes, 238 SafeRepresenter.represent_binary) 239 240SafeRepresenter.add_representer(bool, 241 SafeRepresenter.represent_bool) 242 243SafeRepresenter.add_representer(int, 244 SafeRepresenter.represent_int) 245 246SafeRepresenter.add_representer(float, 247 SafeRepresenter.represent_float) 248 249SafeRepresenter.add_representer(list, 250 SafeRepresenter.represent_list) 251 252SafeRepresenter.add_representer(tuple, 253 SafeRepresenter.represent_list) 254 255SafeRepresenter.add_representer(dict, 256 SafeRepresenter.represent_dict) 257 258SafeRepresenter.add_representer(set, 259 SafeRepresenter.represent_set) 260 261SafeRepresenter.add_representer(datetime.date, 262 SafeRepresenter.represent_date) 263 264SafeRepresenter.add_representer(datetime.datetime, 265 SafeRepresenter.represent_datetime) 266 267SafeRepresenter.add_representer(None, 268 SafeRepresenter.represent_undefined) 269 270class Representer(SafeRepresenter): 271 272 def represent_complex(self, data): 273 if data.imag == 0.0: 274 data = '%r' % data.real 275 elif data.real == 0.0: 276 data = '%rj' % data.imag 277 elif data.imag > 0: 278 data = '%r+%rj' % (data.real, data.imag) 279 else: 280 data = '%r%rj' % (data.real, data.imag) 281 return self.represent_scalar('tag:yaml.org,2002:python/complex', data) 282 283 def represent_tuple(self, data): 284 return self.represent_sequence('tag:yaml.org,2002:python/tuple', data) 285 286 def represent_name(self, data): 287 name = '%s.%s' % (data.__module__, data.__name__) 288 return self.represent_scalar('tag:yaml.org,2002:python/name:'+name, '') 289 290 def represent_module(self, data): 291 return self.represent_scalar( 292 'tag:yaml.org,2002:python/module:'+data.__name__, '') 293 294 def represent_object(self, data): 295 # We use __reduce__ API to save the data. data.__reduce__ returns 296 # a tuple of length 2-5: 297 # (function, args, state, listitems, dictitems) 298 299 # For reconstructing, we calls function(*args), then set its state, 300 # listitems, and dictitems if they are not None. 301 302 # A special case is when function.__name__ == '__newobj__'. In this 303 # case we create the object with args[0].__new__(*args). 304 305 # Another special case is when __reduce__ returns a string - we don't 306 # support it. 307 308 # We produce a !!python/object, !!python/object/new or 309 # !!python/object/apply node. 310 311 cls = type(data) 312 if cls in copyreg.dispatch_table: 313 reduce = copyreg.dispatch_table[cls](data) 314 elif hasattr(data, '__reduce_ex__'): 315 reduce = data.__reduce_ex__(2) 316 elif hasattr(data, '__reduce__'): 317 reduce = data.__reduce__() 318 else: 319 raise RepresenterError("cannot represent object: %r" % data) 320 reduce = (list(reduce)+[None]*5)[:5] 321 function, args, state, listitems, dictitems = reduce 322 args = list(args) 323 if state is None: 324 state = {} 325 if listitems is not None: 326 listitems = list(listitems) 327 if dictitems is not None: 328 dictitems = dict(dictitems) 329 if function.__name__ == '__newobj__': 330 function = args[0] 331 args = args[1:] 332 tag = 'tag:yaml.org,2002:python/object/new:' 333 newobj = True 334 else: 335 tag = 'tag:yaml.org,2002:python/object/apply:' 336 newobj = False 337 function_name = '%s.%s' % (function.__module__, function.__name__) 338 if not args and not listitems and not dictitems \ 339 and isinstance(state, dict) and newobj: 340 return self.represent_mapping( 341 'tag:yaml.org,2002:python/object:'+function_name, state) 342 if not listitems and not dictitems \ 343 and isinstance(state, dict) and not state: 344 return self.represent_sequence(tag+function_name, args) 345 value = {} 346 if args: 347 value['args'] = args 348 if state or not isinstance(state, dict): 349 value['state'] = state 350 if listitems: 351 value['listitems'] = listitems 352 if dictitems: 353 value['dictitems'] = dictitems 354 return self.represent_mapping(tag+function_name, value) 355 356 def represent_ordered_dict(self, data): 357 # Provide uniform representation across different Python versions. 358 data_type = type(data) 359 tag = 'tag:yaml.org,2002:python/object/apply:%s.%s' \ 360 % (data_type.__module__, data_type.__name__) 361 items = [[key, value] for key, value in data.items()] 362 return self.represent_sequence(tag, [items]) 363 364Representer.add_representer(complex, 365 Representer.represent_complex) 366 367Representer.add_representer(tuple, 368 Representer.represent_tuple) 369 370Representer.add_representer(type, 371 Representer.represent_name) 372 373Representer.add_representer(collections.OrderedDict, 374 Representer.represent_ordered_dict) 375 376Representer.add_representer(types.FunctionType, 377 Representer.represent_name) 378 379Representer.add_representer(types.BuiltinFunctionType, 380 Representer.represent_name) 381 382Representer.add_representer(types.ModuleType, 383 Representer.represent_module) 384 385Representer.add_multi_representer(object, 386 Representer.represent_object) 387 388