Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
representer.py
Go to the documentation of this file.
1 # (c) Copyright Rosetta Commons Member Institutions.
2 # (c) This file is part of the Rosetta software suite and is made available under license.
3 # (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
4 # (c) For more information, see http://www.rosettacommons.org. Questions about this can be
5 # (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
6 
7 __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
8  'RepresenterError']
9 
10 from error import *
11 from nodes import *
12 
13 import datetime
14 
15 try:
16  set
17 except NameError:
18  from sets import Set as set
19 
20 import sys, copy_reg, types
21 
23  pass
24 
25 class BaseRepresenter(object):
26 
27  yaml_representers = {}
28  yaml_multi_representers = {}
29 
30  def __init__(self, default_style=None, default_flow_style=None):
31  self.default_style = default_style
32  self.default_flow_style = default_flow_style
34  self.object_keeper = []
35  self.alias_key = None
36 
37  def represent(self, data):
38  node = self.represent_data(data)
39  self.serialize(node)
40  self.represented_objects = {}
41  self.object_keeper = []
42  self.alias_key = None
43 
44  def get_classobj_bases(self, cls):
45  bases = [cls]
46  for base in cls.__bases__:
47  bases.extend(self.get_classobj_bases(base))
48  return bases
49 
50  def represent_data(self, data):
51  if self.ignore_aliases(data):
52  self.alias_key = None
53  else:
54  self.alias_key = id(data)
55  if self.alias_key is not None:
56  if self.alias_key in self.represented_objects:
57  node = self.represented_objects[self.alias_key]
58  #if node is None:
59  # raise RepresenterError("recursive objects are not allowed: %r" % data)
60  return node
61  #self.represented_objects[alias_key] = None
62  self.object_keeper.append(data)
63  data_types = type(data).__mro__
64  if type(data) is types.InstanceType:
65  data_types = self.get_classobj_bases(data.__class__)+list(data_types)
66  if data_types[0] in self.yaml_representers:
67  node = self.yaml_representers[data_types[0]](self, data)
68  else:
69  for data_type in data_types:
70  if data_type in self.yaml_multi_representers:
71  node = self.yaml_multi_representers[data_type](self, data)
72  break
73  else:
74  if None in self.yaml_multi_representers:
75  node = self.yaml_multi_representers[None](self, data)
76  elif None in self.yaml_representers:
77  node = self.yaml_representers[None](self, data)
78  else:
79  node = ScalarNode(None, unicode(data))
80  #if alias_key is not None:
81  # self.represented_objects[alias_key] = node
82  return node
83 
84  def add_representer(cls, data_type, representer):
85  if not 'yaml_representers' in cls.__dict__:
86  cls.yaml_representers = cls.yaml_representers.copy()
87  cls.yaml_representers[data_type] = representer
88  add_representer = classmethod(add_representer)
89 
90  def add_multi_representer(cls, data_type, representer):
91  if not 'yaml_multi_representers' in cls.__dict__:
92  cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
93  cls.yaml_multi_representers[data_type] = representer
94  add_multi_representer = classmethod(add_multi_representer)
95 
96  def represent_scalar(self, tag, value, style=None):
97  if style is None:
98  style = self.default_style
99  node = ScalarNode(tag, value, style=style)
100  if self.alias_key is not None:
101  self.represented_objects[self.alias_key] = node
102  return node
103 
104  def represent_sequence(self, tag, sequence, flow_style=None):
105  value = []
106  node = SequenceNode(tag, value, flow_style=flow_style)
107  if self.alias_key is not None:
108  self.represented_objects[self.alias_key] = node
109  best_style = True
110  for item in sequence:
111  node_item = self.represent_data(item)
112  if not (isinstance(node_item, ScalarNode) and not node_item.style):
113  best_style = False
114  value.append(node_item)
115  if flow_style is None:
116  if self.default_flow_style is not None:
117  node.flow_style = self.default_flow_style
118  else:
119  node.flow_style = best_style
120  return node
121 
122  def represent_mapping(self, tag, mapping, flow_style=None):
123  value = []
124  node = MappingNode(tag, value, flow_style=flow_style)
125  if self.alias_key is not None:
126  self.represented_objects[self.alias_key] = node
127  best_style = True
128  if hasattr(mapping, 'items'):
129  mapping = mapping.items()
130  mapping.sort()
131  for item_key, item_value in mapping:
132  node_key = self.represent_data(item_key)
133  node_value = self.represent_data(item_value)
134  if not (isinstance(node_key, ScalarNode) and not node_key.style):
135  best_style = False
136  if not (isinstance(node_value, ScalarNode) and not node_value.style):
137  best_style = False
138  value.append((node_key, node_value))
139  if flow_style is None:
140  if self.default_flow_style is not None:
141  node.flow_style = self.default_flow_style
142  else:
143  node.flow_style = best_style
144  return node
145 
146  def ignore_aliases(self, data):
147  return False
148 
150 
151  def ignore_aliases(self, data):
152  if data in [None, ()]:
153  return True
154  if isinstance(data, (str, unicode, bool, int, float)):
155  return True
156 
157  def represent_none(self, data):
158  return self.represent_scalar(u'tag:yaml.org,2002:null',
159  u'null')
160 
161  def represent_str(self, data):
162  tag = None
163  style = None
164  try:
165  data = unicode(data, 'ascii')
166  tag = u'tag:yaml.org,2002:str'
167  except UnicodeDecodeError:
168  try:
169  data = unicode(data, 'utf-8')
170  tag = u'tag:yaml.org,2002:str'
171  except UnicodeDecodeError:
172  data = data.encode('base64')
173  tag = u'tag:yaml.org,2002:binary'
174  style = '|'
175  return self.represent_scalar(tag, data, style=style)
176 
177  def represent_unicode(self, data):
178  return self.represent_scalar(u'tag:yaml.org,2002:str', data)
179 
180  def represent_bool(self, data):
181  if data:
182  value = u'true'
183  else:
184  value = u'false'
185  return self.represent_scalar(u'tag:yaml.org,2002:bool', value)
186 
187  def represent_int(self, data):
188  return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
189 
190  def represent_long(self, data):
191  return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
192 
193  inf_value = 1e300
194  while repr(inf_value) != repr(inf_value*inf_value):
195  inf_value *= inf_value
196 
197  def represent_float(self, data):
198  if data != data or (data == 0.0 and data == 1.0):
199  value = u'.nan'
200  elif data == self.inf_value:
201  value = u'.inf'
202  elif data == -self.inf_value:
203  value = u'-.inf'
204  else:
205  value = unicode(repr(data)).lower()
206  # Note that in some cases `repr(data)` represents a float number
207  # without the decimal parts. For instance:
208  # >>> repr(1e17)
209  # '1e17'
210  # Unfortunately, this is not a valid float representation according
211  # to the definition of the `!!float` tag. We fix this by adding
212  # '.0' before the 'e' symbol.
213  if u'.' not in value and u'e' in value:
214  value = value.replace(u'e', u'.0e', 1)
215  return self.represent_scalar(u'tag:yaml.org,2002:float', value)
216 
217  def represent_list(self, data):
218  #pairs = (len(data) > 0 and isinstance(data, list))
219  #if pairs:
220  # for item in data:
221  # if not isinstance(item, tuple) or len(item) != 2:
222  # pairs = False
223  # break
224  #if not pairs:
225  return self.represent_sequence(u'tag:yaml.org,2002:seq', data)
226  #value = []
227  #for item_key, item_value in data:
228  # value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
229  # [(item_key, item_value)]))
230  #return SequenceNode(u'tag:yaml.org,2002:pairs', value)
231 
232  def represent_dict(self, data):
233  return self.represent_mapping(u'tag:yaml.org,2002:map', data)
234 
235  def represent_set(self, data):
236  value = {}
237  for key in data:
238  value[key] = None
239  return self.represent_mapping(u'tag:yaml.org,2002:set', value)
240 
241  def represent_date(self, data):
242  value = unicode(data.isoformat())
243  return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
244 
245  def represent_datetime(self, data):
246  value = unicode(data.isoformat(' '))
247  return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
248 
249  def represent_yaml_object(self, tag, data, cls, flow_style=None):
250  if hasattr(data, '__getstate__'):
251  state = data.__getstate__()
252  else:
253  state = data.__dict__.copy()
254  return self.represent_mapping(tag, state, flow_style=flow_style)
255 
256  def represent_undefined(self, data):
257  raise RepresenterError("cannot represent an object: %s" % data)
258 
259 SafeRepresenter.add_representer(type(None),
260  SafeRepresenter.represent_none)
261 
262 SafeRepresenter.add_representer(str,
263  SafeRepresenter.represent_str)
264 
265 SafeRepresenter.add_representer(unicode,
266  SafeRepresenter.represent_unicode)
267 
268 SafeRepresenter.add_representer(bool,
269  SafeRepresenter.represent_bool)
270 
271 SafeRepresenter.add_representer(int,
272  SafeRepresenter.represent_int)
273 
274 SafeRepresenter.add_representer(long,
275  SafeRepresenter.represent_long)
276 
277 SafeRepresenter.add_representer(float,
278  SafeRepresenter.represent_float)
279 
280 SafeRepresenter.add_representer(list,
281  SafeRepresenter.represent_list)
282 
283 SafeRepresenter.add_representer(tuple,
284  SafeRepresenter.represent_list)
285 
286 SafeRepresenter.add_representer(dict,
287  SafeRepresenter.represent_dict)
288 
289 SafeRepresenter.add_representer(set,
290  SafeRepresenter.represent_set)
291 
292 SafeRepresenter.add_representer(datetime.date,
293  SafeRepresenter.represent_date)
294 SafeRepresenter.add_representer(datetime.datetime,
295  SafeRepresenter.represent_datetime)
296 
297 SafeRepresenter.add_representer(None,
298  SafeRepresenter.represent_undefined)
299 
301 
302  def represent_str(self, data):
303  tag = None
304  style = None
305  try:
306  data = unicode(data, 'ascii')
307  tag = u'tag:yaml.org,2002:str'
308  except UnicodeDecodeError:
309  try:
310  data = unicode(data, 'utf-8')
311  tag = u'tag:yaml.org,2002:python/str'
312  except UnicodeDecodeError:
313  data = data.encode('base64')
314  tag = u'tag:yaml.org,2002:binary'
315  style = '|'
316  return self.represent_scalar(tag, data, style=style)
317 
318  def represent_unicode(self, data):
319  tag = None
320  try:
321  data.encode('ascii')
322  tag = u'tag:yaml.org,2002:python/unicode'
323  except UnicodeEncodeError:
324  tag = u'tag:yaml.org,2002:str'
325  return self.represent_scalar(tag, data)
326 
327  def represent_long(self, data):
328  tag = u'tag:yaml.org,2002:int'
329  if int(data) is not data:
330  tag = u'tag:yaml.org,2002:python/long'
331  return self.represent_scalar(tag, unicode(data))
332 
333  def represent_complex(self, data):
334  if data.imag == 0.0:
335  data = u'%r' % data.real
336  elif data.real == 0.0:
337  data = u'%rj' % data.imag
338  elif data.imag > 0:
339  data = u'%r+%rj' % (data.real, data.imag)
340  else:
341  data = u'%r%rj' % (data.real, data.imag)
342  return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
343 
344  def represent_tuple(self, data):
345  return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
346 
347  def represent_name(self, data):
348  name = u'%s.%s' % (data.__module__, data.__name__)
349  return self.represent_scalar(u'tag:yaml.org,2002:python/name:'+name, u'')
350 
351  def represent_module(self, data):
352  return self.represent_scalar(
353  u'tag:yaml.org,2002:python/module:'+data.__name__, u'')
354 
355  def represent_instance(self, data):
356  # For instances of classic classes, we use __getinitargs__ and
357  # __getstate__ to serialize the data.
358 
359  # If data.__getinitargs__ exists, the object must be reconstructed by
360  # calling cls(**args), where args is a tuple returned by
361  # __getinitargs__. Otherwise, the cls.__init__ method should never be
362  # called and the class instance is created by instantiating a trivial
363  # class and assigning to the instance's __class__ variable.
364 
365  # If data.__getstate__ exists, it returns the state of the object.
366  # Otherwise, the state of the object is data.__dict__.
367 
368  # We produce either a !!python/object or !!python/object/new node.
369  # If data.__getinitargs__ does not exist and state is a dictionary, we
370  # produce a !!python/object node . Otherwise we produce a
371  # !!python/object/new node.
372 
373  cls = data.__class__
374  class_name = u'%s.%s' % (cls.__module__, cls.__name__)
375  args = None
376  state = None
377  if hasattr(data, '__getinitargs__'):
378  args = list(data.__getinitargs__())
379  if hasattr(data, '__getstate__'):
380  state = data.__getstate__()
381  else:
382  state = data.__dict__
383  if args is None and isinstance(state, dict):
384  return self.represent_mapping(
385  u'tag:yaml.org,2002:python/object:'+class_name, state)
386  if isinstance(state, dict) and not state:
387  return self.represent_sequence(
388  u'tag:yaml.org,2002:python/object/new:'+class_name, args)
389  value = {}
390  if args:
391  value['args'] = args
392  value['state'] = state
393  return self.represent_mapping(
394  u'tag:yaml.org,2002:python/object/new:'+class_name, value)
395 
396  def represent_object(self, data):
397  # We use __reduce__ API to save the data. data.__reduce__ returns
398  # a tuple of length 2-5:
399  # (function, args, state, listitems, dictitems)
400 
401  # For reconstructing, we calls function(*args), then set its state,
402  # listitems, and dictitems if they are not None.
403 
404  # A special case is when function.__name__ == '__newobj__'. In this
405  # case we create the object with args[0].__new__(*args).
406 
407  # Another special case is when __reduce__ returns a string - we don't
408  # support it.
409 
410  # We produce a !!python/object, !!python/object/new or
411  # !!python/object/apply node.
412 
413  cls = type(data)
414  if cls in copy_reg.dispatch_table:
415  reduce = copy_reg.dispatch_table[cls](data)
416  elif hasattr(data, '__reduce_ex__'):
417  reduce = data.__reduce_ex__(2)
418  elif hasattr(data, '__reduce__'):
419  reduce = data.__reduce__()
420  else:
421  raise RepresenterError("cannot represent object: %r" % data)
422  reduce = (list(reduce)+[None]*5)[:5]
423  function, args, state, listitems, dictitems = reduce
424  args = list(args)
425  if state is None:
426  state = {}
427  if listitems is not None:
428  listitems = list(listitems)
429  if dictitems is not None:
430  dictitems = dict(dictitems)
431  if function.__name__ == '__newobj__':
432  function = args[0]
433  args = args[1:]
434  tag = u'tag:yaml.org,2002:python/object/new:'
435  newobj = True
436  else:
437  tag = u'tag:yaml.org,2002:python/object/apply:'
438  newobj = False
439  function_name = u'%s.%s' % (function.__module__, function.__name__)
440  if not args and not listitems and not dictitems \
441  and isinstance(state, dict) and newobj:
442  return self.represent_mapping(
443  u'tag:yaml.org,2002:python/object:'+function_name, state)
444  if not listitems and not dictitems \
445  and isinstance(state, dict) and not state:
446  return self.represent_sequence(tag+function_name, args)
447  value = {}
448  if args:
449  value['args'] = args
450  if state or not isinstance(state, dict):
451  value['state'] = state
452  if listitems:
453  value['listitems'] = listitems
454  if dictitems:
455  value['dictitems'] = dictitems
456  return self.represent_mapping(tag+function_name, value)
457 
458 Representer.add_representer(str,
459  Representer.represent_str)
460 
461 Representer.add_representer(unicode,
462  Representer.represent_unicode)
463 
464 Representer.add_representer(long,
465  Representer.represent_long)
466 
467 Representer.add_representer(complex,
468  Representer.represent_complex)
469 
470 Representer.add_representer(tuple,
471  Representer.represent_tuple)
472 
473 Representer.add_representer(type,
474  Representer.represent_name)
475 
476 Representer.add_representer(types.ClassType,
477  Representer.represent_name)
478 
479 Representer.add_representer(types.FunctionType,
480  Representer.represent_name)
481 
482 Representer.add_representer(types.BuiltinFunctionType,
483  Representer.represent_name)
484 
485 Representer.add_representer(types.ModuleType,
486  Representer.represent_module)
487 
488 Representer.add_multi_representer(types.InstanceType,
489  Representer.represent_instance)
490 
491 Representer.add_multi_representer(object,
492  Representer.represent_object)
493