2 __all__
= ['BaseRepresenter', 'SafeRepresenter', 'Representer',
13 from sets
import Set
as set
15 import sys
, copy_reg
, types
17 class RepresenterError(YAMLError
):
20 class BaseRepresenter(object):
22 yaml_representers
= {}
23 yaml_multi_representers
= {}
25 def __init__(self
, default_style
=None, default_flow_style
=None):
26 self
.default_style
= default_style
27 self
.default_flow_style
= default_flow_style
28 self
.represented_objects
= {}
29 self
.object_keeper
= []
32 def represent(self
, data
):
33 node
= self
.represent_data(data
)
35 self
.represented_objects
= {}
36 self
.object_keeper
= []
39 def get_classobj_bases(self
, cls
):
41 for base
in cls
.__bases
__:
42 bases
.extend(self
.get_classobj_bases(base
))
45 def represent_data(self
, data
):
46 if self
.ignore_aliases(data
):
49 self
.alias_key
= id(data
)
50 if self
.alias_key
is not None:
51 if self
.alias_key
in self
.represented_objects
:
52 node
= self
.represented_objects
[self
.alias_key
]
54 # raise RepresenterError("recursive objects are not allowed: %r" % data)
56 #self.represented_objects[alias_key] = None
57 self
.object_keeper
.append(data
)
58 data_types
= type(data
).__mro
__
59 if type(data
) is types
.InstanceType
:
60 data_types
= self
.get_classobj_bases(data
.__class
__)+list(data_types
)
61 if data_types
[0] in self
.yaml_representers
:
62 node
= self
.yaml_representers
[data_types
[0]](self
, data
)
64 for data_type
in data_types
:
65 if data_type
in self
.yaml_multi_representers
:
66 node
= self
.yaml_multi_representers
[data_type
](self
, data
)
69 if None in self
.yaml_multi_representers
:
70 node
= self
.yaml_multi_representers
[None](self
, data
)
71 elif None in self
.yaml_representers
:
72 node
= self
.yaml_representers
[None](self
, data
)
74 node
= ScalarNode(None, unicode(data
))
75 #if alias_key is not None:
76 # self.represented_objects[alias_key] = node
79 def add_representer(cls
, data_type
, representer
):
80 if not 'yaml_representers' in cls
.__dict
__:
81 cls
.yaml_representers
= cls
.yaml_representers
.copy()
82 cls
.yaml_representers
[data_type
] = representer
83 add_representer
= classmethod(add_representer
)
85 def add_multi_representer(cls
, data_type
, representer
):
86 if not 'yaml_multi_representers' in cls
.__dict
__:
87 cls
.yaml_multi_representers
= cls
.yaml_multi_representers
.copy()
88 cls
.yaml_multi_representers
[data_type
] = representer
89 add_multi_representer
= classmethod(add_multi_representer
)
91 def represent_scalar(self
, tag
, value
, style
=None):
93 style
= self
.default_style
94 node
= ScalarNode(tag
, value
, style
=style
)
95 if self
.alias_key
is not None:
96 self
.represented_objects
[self
.alias_key
] = node
99 def represent_sequence(self
, tag
, sequence
, flow_style
=None):
101 node
= SequenceNode(tag
, value
, flow_style
=flow_style
)
102 if self
.alias_key
is not None:
103 self
.represented_objects
[self
.alias_key
] = node
105 for item
in sequence
:
106 node_item
= self
.represent_data(item
)
107 if not (isinstance(node_item
, ScalarNode
) and not node_item
.style
):
109 value
.append(node_item
)
110 if flow_style
is None:
111 if self
.default_flow_style
is not None:
112 node
.flow_style
= self
.default_flow_style
114 node
.flow_style
= best_style
117 def represent_mapping(self
, tag
, mapping
, flow_style
=None):
119 node
= MappingNode(tag
, value
, flow_style
=flow_style
)
120 if self
.alias_key
is not None:
121 self
.represented_objects
[self
.alias_key
] = node
123 if hasattr(mapping
, 'items'):
124 mapping
= mapping
.items()
126 for item_key
, item_value
in mapping
:
127 node_key
= self
.represent_data(item_key
)
128 node_value
= self
.represent_data(item_value
)
129 if not (isinstance(node_key
, ScalarNode
) and not node_key
.style
):
131 if not (isinstance(node_value
, ScalarNode
) and not node_value
.style
):
133 value
.append((node_key
, node_value
))
134 if flow_style
is None:
135 if self
.default_flow_style
is not None:
136 node
.flow_style
= self
.default_flow_style
138 node
.flow_style
= best_style
141 def ignore_aliases(self
, data
):
144 class SafeRepresenter(BaseRepresenter
):
146 def ignore_aliases(self
, data
):
147 if data
in [None, ()]:
149 if isinstance(data
, (str, unicode, bool, int, float)):
152 def represent_none(self
, data
):
153 return self
.represent_scalar(u
'tag:yaml.org,2002:null',
156 def represent_str(self
, data
):
160 data
= unicode(data
, 'ascii')
161 tag
= u
'tag:yaml.org,2002:str'
162 except UnicodeDecodeError:
164 data
= unicode(data
, 'utf-8')
165 tag
= u
'tag:yaml.org,2002:str'
166 except UnicodeDecodeError:
167 data
= data
.encode('base64')
168 tag
= u
'tag:yaml.org,2002:binary'
170 return self
.represent_scalar(tag
, data
, style
=style
)
172 def represent_unicode(self
, data
):
173 return self
.represent_scalar(u
'tag:yaml.org,2002:str', data
)
175 def represent_bool(self
, data
):
180 return self
.represent_scalar(u
'tag:yaml.org,2002:bool', value
)
182 def represent_int(self
, data
):
183 return self
.represent_scalar(u
'tag:yaml.org,2002:int', unicode(data
))
185 def represent_long(self
, data
):
186 return self
.represent_scalar(u
'tag:yaml.org,2002:int', unicode(data
))
189 while repr(inf_value
) != repr(inf_value
*inf_value
):
190 inf_value
*= inf_value
192 def represent_float(self
, data
):
193 if data
!= data
or (data
== 0.0 and data
== 1.0):
195 elif data
== self
.inf_value
:
197 elif data
== -self
.inf_value
:
200 value
= unicode(repr(data
)).lower()
201 # Note that in some cases `repr(data)` represents a float number
202 # without the decimal parts. For instance:
205 # Unfortunately, this is not a valid float representation according
206 # to the definition of the `!!float` tag. We fix this by adding
207 # '.0' before the 'e' symbol.
208 if u
'.' not in value
and u
'e' in value
:
209 value
= value
.replace(u
'e', u
'.0e', 1)
210 return self
.represent_scalar(u
'tag:yaml.org,2002:float', value
)
212 def represent_list(self
, data
):
213 #pairs = (len(data) > 0 and isinstance(data, list))
216 # if not isinstance(item, tuple) or len(item) != 2:
220 return self
.represent_sequence(u
'tag:yaml.org,2002:seq', data
)
222 #for item_key, item_value in data:
223 # value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
224 # [(item_key, item_value)]))
225 #return SequenceNode(u'tag:yaml.org,2002:pairs', value)
227 def represent_dict(self
, data
):
228 return self
.represent_mapping(u
'tag:yaml.org,2002:map', data
)
230 def represent_set(self
, data
):
234 return self
.represent_mapping(u
'tag:yaml.org,2002:set', value
)
236 def represent_date(self
, data
):
237 value
= unicode(data
.isoformat())
238 return self
.represent_scalar(u
'tag:yaml.org,2002:timestamp', value
)
240 def represent_datetime(self
, data
):
241 value
= unicode(data
.isoformat(' '))
242 return self
.represent_scalar(u
'tag:yaml.org,2002:timestamp', value
)
244 def represent_yaml_object(self
, tag
, data
, cls
, flow_style
=None):
245 if hasattr(data
, '__getstate__'):
246 state
= data
.__getstate
__()
248 state
= data
.__dict
__.copy()
249 return self
.represent_mapping(tag
, state
, flow_style
=flow_style
)
251 def represent_undefined(self
, data
):
252 raise RepresenterError("cannot represent an object: %s" % data
)
254 SafeRepresenter
.add_representer(type(None),
255 SafeRepresenter
.represent_none
)
257 SafeRepresenter
.add_representer(str,
258 SafeRepresenter
.represent_str
)
260 SafeRepresenter
.add_representer(unicode,
261 SafeRepresenter
.represent_unicode
)
263 SafeRepresenter
.add_representer(bool,
264 SafeRepresenter
.represent_bool
)
266 SafeRepresenter
.add_representer(int,
267 SafeRepresenter
.represent_int
)
269 SafeRepresenter
.add_representer(long,
270 SafeRepresenter
.represent_long
)
272 SafeRepresenter
.add_representer(float,
273 SafeRepresenter
.represent_float
)
275 SafeRepresenter
.add_representer(list,
276 SafeRepresenter
.represent_list
)
278 SafeRepresenter
.add_representer(tuple,
279 SafeRepresenter
.represent_list
)
281 SafeRepresenter
.add_representer(dict,
282 SafeRepresenter
.represent_dict
)
284 SafeRepresenter
.add_representer(set,
285 SafeRepresenter
.represent_set
)
287 SafeRepresenter
.add_representer(datetime
.date
,
288 SafeRepresenter
.represent_date
)
289 SafeRepresenter
.add_representer(datetime
.datetime
,
290 SafeRepresenter
.represent_datetime
)
292 SafeRepresenter
.add_representer(None,
293 SafeRepresenter
.represent_undefined
)
295 class Representer(SafeRepresenter
):
297 def represent_str(self
, data
):
301 data
= unicode(data
, 'ascii')
302 tag
= u
'tag:yaml.org,2002:str'
303 except UnicodeDecodeError:
305 data
= unicode(data
, 'utf-8')
306 tag
= u
'tag:yaml.org,2002:python/str'
307 except UnicodeDecodeError:
308 data
= data
.encode('base64')
309 tag
= u
'tag:yaml.org,2002:binary'
311 return self
.represent_scalar(tag
, data
, style
=style
)
313 def represent_unicode(self
, data
):
317 tag
= u
'tag:yaml.org,2002:python/unicode'
318 except UnicodeEncodeError:
319 tag
= u
'tag:yaml.org,2002:str'
320 return self
.represent_scalar(tag
, data
)
322 def represent_long(self
, data
):
323 tag
= u
'tag:yaml.org,2002:int'
324 if int(data
) is not data
:
325 tag
= u
'tag:yaml.org,2002:python/long'
326 return self
.represent_scalar(tag
, unicode(data
))
328 def represent_complex(self
, data
):
330 data
= u
'%r' % data
.real
331 elif data
.real
== 0.0:
332 data
= u
'%rj' % data
.imag
334 data
= u
'%r+%rj' % (data
.real
, data
.imag
)
336 data
= u
'%r%rj' % (data
.real
, data
.imag
)
337 return self
.represent_scalar(u
'tag:yaml.org,2002:python/complex', data
)
339 def represent_tuple(self
, data
):
340 return self
.represent_sequence(u
'tag:yaml.org,2002:python/tuple', data
)
342 def represent_name(self
, data
):
343 name
= u
'%s.%s' % (data
.__module
__, data
.__name
__)
344 return self
.represent_scalar(u
'tag:yaml.org,2002:python/name:'+name
, u
'')
346 def represent_module(self
, data
):
347 return self
.represent_scalar(
348 u
'tag:yaml.org,2002:python/module:'+data
.__name
__, u
'')
350 def represent_instance(self
, data
):
351 # For instances of classic classes, we use __getinitargs__ and
352 # __getstate__ to serialize the data.
354 # If data.__getinitargs__ exists, the object must be reconstructed by
355 # calling cls(**args), where args is a tuple returned by
356 # __getinitargs__. Otherwise, the cls.__init__ method should never be
357 # called and the class instance is created by instantiating a trivial
358 # class and assigning to the instance's __class__ variable.
360 # If data.__getstate__ exists, it returns the state of the object.
361 # Otherwise, the state of the object is data.__dict__.
363 # We produce either a !!python/object or !!python/object/new node.
364 # If data.__getinitargs__ does not exist and state is a dictionary, we
365 # produce a !!python/object node . Otherwise we produce a
366 # !!python/object/new node.
369 class_name
= u
'%s.%s' % (cls
.__module
__, cls
.__name
__)
372 if hasattr(data
, '__getinitargs__'):
373 args
= list(data
.__getinitargs
__())
374 if hasattr(data
, '__getstate__'):
375 state
= data
.__getstate
__()
377 state
= data
.__dict
__
378 if args
is None and isinstance(state
, dict):
379 return self
.represent_mapping(
380 u
'tag:yaml.org,2002:python/object:'+class_name
, state
)
381 if isinstance(state
, dict) and not state
:
382 return self
.represent_sequence(
383 u
'tag:yaml.org,2002:python/object/new:'+class_name
, args
)
387 value
['state'] = state
388 return self
.represent_mapping(
389 u
'tag:yaml.org,2002:python/object/new:'+class_name
, value
)
391 def represent_object(self
, data
):
392 # We use __reduce__ API to save the data. data.__reduce__ returns
393 # a tuple of length 2-5:
394 # (function, args, state, listitems, dictitems)
396 # For reconstructing, we calls function(*args), then set its state,
397 # listitems, and dictitems if they are not None.
399 # A special case is when function.__name__ == '__newobj__'. In this
400 # case we create the object with args[0].__new__(*args).
402 # Another special case is when __reduce__ returns a string - we don't
405 # We produce a !!python/object, !!python/object/new or
406 # !!python/object/apply node.
409 if cls
in copy_reg
.dispatch_table
:
410 reduce = copy_reg
.dispatch_table
[cls
](data
)
411 elif hasattr(data
, '__reduce_ex__'):
412 reduce = data
.__reduce
_ex
__(2)
413 elif hasattr(data
, '__reduce__'):
414 reduce = data
.__reduce
__()
416 raise RepresenterError("cannot represent object: %r" % data
)
417 reduce = (list(reduce)+[None]*5)[:5]
418 function
, args
, state
, listitems
, dictitems
= reduce
422 if listitems
is not None:
423 listitems
= list(listitems
)
424 if dictitems
is not None:
425 dictitems
= dict(dictitems
)
426 if function
.__name
__ == '__newobj__':
429 tag
= u
'tag:yaml.org,2002:python/object/new:'
432 tag
= u
'tag:yaml.org,2002:python/object/apply:'
434 function_name
= u
'%s.%s' % (function
.__module
__, function
.__name
__)
435 if not args
and not listitems
and not dictitems \
436 and isinstance(state
, dict) and newobj
:
437 return self
.represent_mapping(
438 u
'tag:yaml.org,2002:python/object:'+function_name
, state
)
439 if not listitems
and not dictitems \
440 and isinstance(state
, dict) and not state
:
441 return self
.represent_sequence(tag
+function_name
, args
)
445 if state
or not isinstance(state
, dict):
446 value
['state'] = state
448 value
['listitems'] = listitems
450 value
['dictitems'] = dictitems
451 return self
.represent_mapping(tag
+function_name
, value
)
453 Representer
.add_representer(str,
454 Representer
.represent_str
)
456 Representer
.add_representer(unicode,
457 Representer
.represent_unicode
)
459 Representer
.add_representer(long,
460 Representer
.represent_long
)
462 Representer
.add_representer(complex,
463 Representer
.represent_complex
)
465 Representer
.add_representer(tuple,
466 Representer
.represent_tuple
)
468 Representer
.add_representer(type,
469 Representer
.represent_name
)
471 Representer
.add_representer(types
.ClassType
,
472 Representer
.represent_name
)
474 Representer
.add_representer(types
.FunctionType
,
475 Representer
.represent_name
)
477 Representer
.add_representer(types
.BuiltinFunctionType
,
478 Representer
.represent_name
)
480 Representer
.add_representer(types
.ModuleType
,
481 Representer
.represent_module
)
483 Representer
.add_multi_representer(types
.InstanceType
,
484 Representer
.represent_instance
)
486 Representer
.add_multi_representer(object,
487 Representer
.represent_object
)