2 __all__
= ['BaseRepresenter', 'SafeRepresenter', 'Representer',
10 datetime_available
= True
12 datetime_available
= False
17 from sets
import Set
as set
21 class RepresenterError(YAMLError
):
24 class BaseRepresenter
:
26 yaml_representers
= {}
27 yaml_multi_representers
= {}
30 self
.represented_objects
= {}
32 def represent(self
, data
):
33 node
= self
.represent_data(data
)
35 self
.represented_objects
= {}
40 classobj_type
= type(C
)
41 instance_type
= type(c
)
42 function_type
= type(f
)
43 builtin_function_type
= type(abs)
44 module_type
= type(sys
)
47 def get_classobj_bases(self
, cls
):
49 for base
in cls
.__bases
__:
50 bases
.extend(self
.get_classobj_bases(base
))
53 def represent_data(self
, data
):
54 if self
.ignore_aliases(data
):
58 if alias_key
is not None:
59 if alias_key
in self
.represented_objects
:
60 node
= self
.represented_objects
[alias_key
]
62 raise RepresenterError("recursive objects are not allowed: %r" % data
)
64 self
.represented_objects
[alias_key
] = None
65 data_types
= type(data
).__mro
__
66 if type(data
) is self
.instance_type
:
67 data_types
= self
.get_classobj_bases(data
.__class
__)+list(data_types
)
68 if data_types
[0] in self
.yaml_representers
:
69 node
= self
.yaml_representers
[data_types
[0]](self
, data
)
71 for data_type
in data_types
:
72 if data_type
in self
.yaml_multi_representers
:
73 node
= self
.yaml_multi_representers
[data_type
](self
, data
)
76 if None in self
.yaml_multi_representers
:
77 node
= self
.yaml_multi_representers
[None](self
, data
)
78 elif None in self
.yaml_representers
:
79 node
= self
.yaml_representers
[None](self
, data
)
81 node
= ScalarNode(None, unicode(data
))
82 if alias_key
is not None:
83 self
.represented_objects
[alias_key
] = node
86 def add_representer(cls
, data_type
, representer
):
87 if not 'yaml_representers' in cls
.__dict
__:
88 cls
.yaml_representers
= cls
.yaml_representers
.copy()
89 cls
.yaml_representers
[data_type
] = representer
90 add_representer
= classmethod(add_representer
)
92 def add_multi_representer(cls
, data_type
, representer
):
93 if not 'yaml_multi_representers' in cls
.__dict
__:
94 cls
.yaml_multi_representers
= cls
.yaml_multi_representers
.copy()
95 cls
.yaml_multi_representers
[data_type
] = representer
96 add_multi_representer
= classmethod(add_multi_representer
)
98 def represent_scalar(self
, tag
, value
, style
=None):
99 return ScalarNode(tag
, value
, style
=style
)
101 def represent_sequence(self
, tag
, sequence
, flow_style
=None):
104 for item
in sequence
:
105 node_item
= self
.represent_data(item
)
106 if not (isinstance(node_item
, ScalarNode
) and not node_item
.style
):
108 value
.append(self
.represent_data(item
))
109 if flow_style
is None:
110 flow_style
= best_style
111 return SequenceNode(tag
, value
, flow_style
=flow_style
)
113 def represent_mapping(self
, tag
, mapping
, flow_style
=None):
115 if hasattr(mapping
, 'keys'):
117 for item_key
in mapping
.keys():
118 item_value
= mapping
[item_key
]
119 node_key
= self
.represent_data(item_key
)
120 node_value
= self
.represent_data(item_value
)
121 if not (isinstance(node_key
, ScalarNode
) and not node_key
.style
):
123 if not (isinstance(node_value
, ScalarNode
) and not node_value
.style
):
125 value
[node_key
] = node_value
128 for item_key
, item_value
in mapping
:
129 node_key
= self
.represent_data(item_key
)
130 node_value
= self
.represent_data(item_value
)
131 if not (isinstance(node_key
, ScalarNode
) and not node_key
.style
):
133 if not (isinstance(node_value
, ScalarNode
) and not node_value
.style
):
135 value
.append((node_key
, node_value
))
136 if flow_style
is None:
137 flow_style
= best_style
138 return MappingNode(tag
, value
, flow_style
=flow_style
)
140 def ignore_aliases(self
, data
):
143 class SafeRepresenter(BaseRepresenter
):
145 def ignore_aliases(self
, data
):
146 if data
in [None, ()]:
148 if isinstance(data
, (str, unicode, bool, int, float)):
151 def represent_none(self
, data
):
152 return self
.represent_scalar(u
'tag:yaml.org,2002:null',
155 def represent_str(self
, data
):
159 data
= unicode(data
, 'ascii')
160 tag
= u
'tag:yaml.org,2002:str'
161 except UnicodeDecodeError:
163 data
= unicode(data
, 'utf-8')
164 tag
= u
'tag:yaml.org,2002:str'
165 except UnicodeDecodeError:
166 data
= data
.encode('base64')
167 tag
= u
'tag:yaml.org,2002:binary'
169 return self
.represent_scalar(tag
, data
, style
=style
)
171 def represent_unicode(self
, data
):
172 return self
.represent_scalar(u
'tag:yaml.org,2002:str', data
)
174 def represent_bool(self
, data
):
179 return self
.represent_scalar(u
'tag:yaml.org,2002:bool', value
)
181 def represent_int(self
, data
):
182 return self
.represent_scalar(u
'tag:yaml.org,2002:int', unicode(data
))
184 def represent_long(self
, data
):
185 return self
.represent_scalar(u
'tag:yaml.org,2002:int', unicode(data
))
188 nan_value
= inf_value
/inf_value
190 def represent_float(self
, data
):
191 if data
== self
.inf_value
:
193 elif data
== -self
.inf_value
:
195 elif data
== self
.nan_value
or data
!= data
:
198 value
= unicode(repr(data
))
199 return self
.represent_scalar(u
'tag:yaml.org,2002:float', value
)
201 def represent_list(self
, data
):
202 pairs
= (len(data
) > 0 and isinstance(data
, list))
205 if not isinstance(item
, tuple) or len(item
) != 2:
209 return self
.represent_sequence(u
'tag:yaml.org,2002:seq', data
)
211 for item_key
, item_value
in data
:
212 value
.append(self
.represent_mapping(u
'tag:yaml.org,2002:map',
213 [(item_key
, item_value
)]))
214 return SequenceNode(u
'tag:yaml.org,2002:pairs', value
)
216 def represent_dict(self
, data
):
217 return self
.represent_mapping(u
'tag:yaml.org,2002:map', data
)
219 def represent_set(self
, data
):
223 return self
.represent_mapping(u
'tag:yaml.org,2002:set', value
)
225 def represent_date(self
, data
):
226 value
= u
'%04d-%02d-%02d' % (data
.year
, data
.month
, data
.day
)
227 return self
.represent_scalar(u
'tag:yaml.org,2002:timestamp', value
)
229 def represent_datetime(self
, data
):
230 value
= u
'%04d-%02d-%02d %02d:%02d:%02d' \
231 % (data
.year
, data
.month
, data
.day
,
232 data
.hour
, data
.minute
, data
.second
)
234 value
+= u
'.' + unicode(data
.microsecond
/1000000.0).split(u
'.')[1]
236 value
+= unicode(data
.utcoffset())
237 return self
.represent_scalar(u
'tag:yaml.org,2002:timestamp', value
)
239 def represent_yaml_object(self
, tag
, data
, cls
, flow_style
=None):
240 if hasattr(data
, '__getstate__'):
241 state
= data
.__getstate
__()
243 state
= data
.__dict
__.copy()
244 if isinstance(state
, dict):
245 state
= state
.items()
247 return self
.represent_mapping(tag
, state
, flow_style
=flow_style
)
249 def represent_undefined(self
, data
):
250 raise RepresenterError("cannot represent an object: %s" % data
)
252 SafeRepresenter
.add_representer(type(None),
253 SafeRepresenter
.represent_none
)
255 SafeRepresenter
.add_representer(str,
256 SafeRepresenter
.represent_str
)
258 SafeRepresenter
.add_representer(unicode,
259 SafeRepresenter
.represent_unicode
)
261 SafeRepresenter
.add_representer(bool,
262 SafeRepresenter
.represent_bool
)
264 SafeRepresenter
.add_representer(int,
265 SafeRepresenter
.represent_int
)
267 SafeRepresenter
.add_representer(long,
268 SafeRepresenter
.represent_long
)
270 SafeRepresenter
.add_representer(float,
271 SafeRepresenter
.represent_float
)
273 SafeRepresenter
.add_representer(list,
274 SafeRepresenter
.represent_list
)
276 SafeRepresenter
.add_representer(tuple,
277 SafeRepresenter
.represent_list
)
279 SafeRepresenter
.add_representer(dict,
280 SafeRepresenter
.represent_dict
)
282 SafeRepresenter
.add_representer(set,
283 SafeRepresenter
.represent_set
)
285 if datetime_available
:
286 SafeRepresenter
.add_representer(datetime
.date
,
287 SafeRepresenter
.represent_date
)
288 SafeRepresenter
.add_representer(datetime
.datetime
,
289 SafeRepresenter
.represent_datetime
)
291 SafeRepresenter
.add_representer(None,
292 SafeRepresenter
.represent_undefined
)
294 class Representer(SafeRepresenter
):
296 def represent_str(self
, data
):
300 data
= unicode(data
, 'ascii')
301 tag
= u
'tag:yaml.org,2002:str'
302 except UnicodeDecodeError:
304 data
= unicode(data
, 'utf-8')
305 tag
= u
'tag:yaml.org,2002:python/str'
306 except UnicodeDecodeError:
307 data
= data
.encode('base64')
308 tag
= u
'tag:yaml.org,2002:binary'
310 return self
.represent_scalar(tag
, data
, style
=style
)
312 def represent_unicode(self
, data
):
316 tag
= u
'tag:yaml.org,2002:python/unicode'
317 except UnicodeEncodeError:
318 tag
= u
'tag:yaml.org,2002:str'
319 return self
.represent_scalar(tag
, data
)
321 def represent_long(self
, data
):
322 tag
= u
'tag:yaml.org,2002:int'
323 if int(data
) is not data
:
324 tag
= u
'tag:yaml.org,2002:python/long'
325 return self
.represent_scalar(tag
, unicode(data
))
327 def represent_complex(self
, data
):
329 data
= u
'%r' % data
.real
330 elif data
.real
== 0.0:
331 data
= u
'%rj' % data
.imag
333 data
= u
'%r+%rj' % (data
.real
, data
.imag
)
335 data
= u
'%r%rj' % (data
.real
, data
.imag
)
336 return self
.represent_scalar(u
'tag:yaml.org,2002:python/complex', data
)
338 def represent_tuple(self
, data
):
339 return self
.represent_sequence(u
'tag:yaml.org,2002:python/tuple', data
)
341 def represent_name(self
, data
):
342 name
= u
'%s.%s' % (data
.__module
__, data
.__name
__)
343 return self
.represent_scalar(u
'tag:yaml.org,2002:python/name:'+name
, u
'')
345 def represent_module(self
, data
):
346 return self
.represent_scalar(
347 u
'tag:yaml.org,2002:python/module:'+data
.__name
__, u
'')
349 def represent_instance(self
, data
):
350 # For instances of classic classes, we use __getinitargs__ and
351 # __getstate__ to serialize the data.
353 # If data.__getinitargs__ exists, the object must be reconstructed by
354 # calling cls(**args), where args is a tuple returned by
355 # __getinitargs__. Otherwise, the cls.__init__ method should never be
356 # called and the class instance is created by instantiating a trivial
357 # class and assigning to the instance's __class__ variable.
359 # If data.__getstate__ exists, it returns the state of the object.
360 # Otherwise, the state of the object is data.__dict__.
362 # We produce either a !!python/object or !!python/object/new node.
363 # If data.__getinitargs__ does not exist and state is a dictionary, we
364 # produce a !!python/object node . Otherwise we produce a
365 # !!python/object/new node.
368 class_name
= u
'%s.%s' % (cls
.__module
__, cls
.__name
__)
371 if hasattr(data
, '__getinitargs__'):
372 args
= list(data
.__getinitargs
__())
373 if hasattr(data
, '__getstate__'):
374 state
= data
.__getstate
__()
376 state
= data
.__dict
__
377 if args
is None and isinstance(state
, dict):
378 state
= state
.items()
380 return self
.represent_mapping(
381 u
'tag:yaml.org,2002:python/object:'+class_name
, state
)
382 if isinstance(state
, dict) and not state
:
383 return self
.represent_sequence(
384 u
'tag:yaml.org,2002:python/object/new:'+class_name
, args
)
388 value
['state'] = state
389 return self
.represent_mapping(
390 u
'tag:yaml.org,2002:python/object/new:'+class_name
, value
)
392 def represent_object(self
, data
):
393 # We use __reduce__ API to save the data. data.__reduce__ returns
394 # a tuple of length 2-5:
395 # (function, args, state, listitems, dictitems)
397 # For reconstructing, we calls function(*args), then set its state,
398 # listitems, and dictitems if they are not None.
400 # A special case is when function.__name__ == '__newobj__'. In this
401 # case we create the object with args[0].__new__(*args).
403 # Another special case is when __reduce__ returns a string - we don't
406 # We produce a !!python/object, !!python/object/new or
407 # !!python/object/apply node.
410 if cls
in copy_reg
.dispatch_table
:
411 reduce = copy_reg
.dispatch_table
[cls
]
412 elif hasattr(data
, '__reduce_ex__'):
413 reduce = data
.__reduce
_ex
__(2)
414 elif hasattr(data
, '__reduce__'):
415 reduce = data
.__reduce
__()
417 raise RepresenterError("cannot represent object: %r" % data
)
418 reduce = (list(reduce)+[None]*5)[:5]
419 function
, args
, state
, listitems
, dictitems
= reduce
423 if listitems
is not None:
424 listitems
= list(listitems
)
425 if dictitems
is not None:
426 dictitems
= dict(dictitems
)
427 if function
.__name
__ == '__newobj__':
430 tag
= u
'tag:yaml.org,2002:python/object/new:'
433 tag
= u
'tag:yaml.org,2002:python/object/apply:'
435 function_name
= u
'%s.%s' % (function
.__module
__, function
.__name
__)
436 if not args
and not listitems
and not dictitems \
437 and isinstance(state
, dict) and newobj
:
438 state
= state
.items()
440 return self
.represent_mapping(
441 u
'tag:yaml.org,2002:python/object:'+function_name
, state
)
442 if not listitems
and not dictitems \
443 and isinstance(state
, dict) and not state
:
444 return self
.represent_sequence(tag
+function_name
, args
)
448 if state
or not isinstance(state
, dict):
449 value
['state'] = state
451 value
['listitems'] = listitems
453 value
['dictitems'] = dictitems
454 return self
.represent_mapping(tag
+function_name
, value
)
456 Representer
.add_representer(str,
457 Representer
.represent_str
)
459 Representer
.add_representer(unicode,
460 Representer
.represent_unicode
)
462 Representer
.add_representer(long,
463 Representer
.represent_long
)
465 Representer
.add_representer(complex,
466 Representer
.represent_complex
)
468 Representer
.add_representer(tuple,
469 Representer
.represent_tuple
)
471 Representer
.add_representer(type,
472 Representer
.represent_name
)
474 Representer
.add_representer(Representer
.classobj_type
,
475 Representer
.represent_name
)
477 Representer
.add_representer(Representer
.function_type
,
478 Representer
.represent_name
)
480 Representer
.add_representer(Representer
.builtin_function_type
,
481 Representer
.represent_name
)
483 Representer
.add_representer(Representer
.module_type
,
484 Representer
.represent_module
)
486 Representer
.add_multi_representer(Representer
.instance_type
,
487 Representer
.represent_instance
)
489 Representer
.add_multi_representer(object,
490 Representer
.represent_object
)