Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
constructor.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__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
8  'ConstructorError']
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 binascii, re, sys, types
21 
23  pass
24 
25 class BaseConstructor(object):
26 
27  yaml_constructors = {}
28  yaml_multi_constructors = {}
29 
30  def __init__(self):
33  self.state_generators = []
34  self.deep_construct = False
35 
36  def check_data(self):
37  # If there are more documents available?
38  return self.check_node()
39 
40  def get_data(self):
41  # Construct and return the next document.
42  if self.check_node():
43  return self.construct_document(self.get_node())
44 
45  def construct_document(self, node):
46  data = self.construct_object(node)
47  while self.state_generators:
48  state_generators = self.state_generators
49  self.state_generators = []
50  for generator in state_generators:
51  for dummy in generator:
52  pass
53  self.constructed_objects = {}
54  self.recursive_objects = {}
55  self.deep_construct = False
56  return data
57 
58  def construct_object(self, node, deep=False):
59  if deep:
60  old_deep = self.deep_construct
61  self.deep_construct = True
62  if node in self.constructed_objects:
63  return self.constructed_objects[node]
64  if node in self.recursive_objects:
65  raise ConstructorError(None, None,
66  "found unconstructable recursive node", node.start_mark)
67  self.recursive_objects[node] = None
68  constructor = None
69  state_constructor = None
70  tag_suffix = None
71  if node.tag in self.yaml_constructors:
72  constructor = self.yaml_constructors[node.tag]
73  else:
74  for tag_prefix in self.yaml_multi_constructors:
75  if node.tag.startswith(tag_prefix):
76  tag_suffix = node.tag[len(tag_prefix):]
77  constructor = self.yaml_multi_constructors[tag_prefix]
78  break
79  else:
80  if None in self.yaml_multi_constructors:
81  tag_suffix = node.tag
82  constructor = self.yaml_multi_constructors[None]
83  elif None in self.yaml_constructors:
84  constructor = self.yaml_constructors[None]
85  elif isinstance(node, ScalarNode):
86  constructor = self.__class__.construct_scalar
87  elif isinstance(node, SequenceNode):
88  constructor = self.__class__.construct_sequence
89  elif isinstance(node, MappingNode):
90  constructor = self.__class__.construct_mapping
91  if tag_suffix is None:
92  data = constructor(self, node)
93  else:
94  data = constructor(self, tag_suffix, node)
95  if isinstance(data, types.GeneratorType):
96  generator = data
97  data = generator.next()
98  if self.deep_construct:
99  for dummy in generator:
100  pass
101  else:
102  self.state_generators.append(generator)
103  self.constructed_objects[node] = data
104  del self.recursive_objects[node]
105  if deep:
106  self.deep_construct = old_deep
107  return data
108 
109  def construct_scalar(self, node):
110  if not isinstance(node, ScalarNode):
111  raise ConstructorError(None, None,
112  "expected a scalar node, but found %s" % node.id,
113  node.start_mark)
114  return node.value
115 
116  def construct_sequence(self, node, deep=False):
117  if not isinstance(node, SequenceNode):
118  raise ConstructorError(None, None,
119  "expected a sequence node, but found %s" % node.id,
120  node.start_mark)
121  return [self.construct_object(child, deep=deep)
122  for child in node.value]
123 
124  def construct_mapping(self, node, deep=False):
125  if not isinstance(node, MappingNode):
126  raise ConstructorError(None, None,
127  "expected a mapping node, but found %s" % node.id,
128  node.start_mark)
129  mapping = {}
130  for key_node, value_node in node.value:
131  key = self.construct_object(key_node, deep=deep)
132  try:
133  hash(key)
134  except TypeError, exc:
135  raise ConstructorError("while constructing a mapping", node.start_mark,
136  "found unacceptable key (%s)" % exc, key_node.start_mark)
137  value = self.construct_object(value_node, deep=deep)
138  mapping[key] = value
139  return mapping
140 
141  def construct_pairs(self, node, deep=False):
142  if not isinstance(node, MappingNode):
143  raise ConstructorError(None, None,
144  "expected a mapping node, but found %s" % node.id,
145  node.start_mark)
146  pairs = []
147  for key_node, value_node in node.value:
148  key = self.construct_object(key_node, deep=deep)
149  value = self.construct_object(value_node, deep=deep)
150  pairs.append((key, value))
151  return pairs
152 
153  def add_constructor(cls, tag, constructor):
154  if not 'yaml_constructors' in cls.__dict__:
155  cls.yaml_constructors = cls.yaml_constructors.copy()
156  cls.yaml_constructors[tag] = constructor
157  add_constructor = classmethod(add_constructor)
158 
159  def add_multi_constructor(cls, tag_prefix, multi_constructor):
160  if not 'yaml_multi_constructors' in cls.__dict__:
161  cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
162  cls.yaml_multi_constructors[tag_prefix] = multi_constructor
163  add_multi_constructor = classmethod(add_multi_constructor)
164 
166 
167  def construct_scalar(self, node):
168  if isinstance(node, MappingNode):
169  for key_node, value_node in node.value:
170  if key_node.tag == u'tag:yaml.org,2002:value':
171  return self.construct_scalar(value_node)
172  return BaseConstructor.construct_scalar(self, node)
173 
174  def flatten_mapping(self, node):
175  merge = []
176  index = 0
177  while index < len(node.value):
178  key_node, value_node = node.value[index]
179  if key_node.tag == u'tag:yaml.org,2002:merge':
180  del node.value[index]
181  if isinstance(value_node, MappingNode):
182  self.flatten_mapping(value_node)
183  merge.extend(value_node.value)
184  elif isinstance(value_node, SequenceNode):
185  submerge = []
186  for subnode in value_node.value:
187  if not isinstance(subnode, MappingNode):
188  raise ConstructorError("while constructing a mapping",
189  node.start_mark,
190  "expected a mapping for merging, but found %s"
191  % subnode.id, subnode.start_mark)
192  self.flatten_mapping(subnode)
193  submerge.append(subnode.value)
194  submerge.reverse()
195  for value in submerge:
196  merge.extend(value)
197  else:
198  raise ConstructorError("while constructing a mapping", node.start_mark,
199  "expected a mapping or list of mappings for merging, but found %s"
200  % value_node.id, value_node.start_mark)
201  elif key_node.tag == u'tag:yaml.org,2002:value':
202  key_node.tag = u'tag:yaml.org,2002:str'
203  index += 1
204  else:
205  index += 1
206  if merge:
207  node.value = merge + node.value
208 
209  def construct_mapping(self, node, deep=False):
210  if isinstance(node, MappingNode):
211  self.flatten_mapping(node)
212  return BaseConstructor.construct_mapping(self, node, deep=deep)
213 
214  def construct_yaml_null(self, node):
215  self.construct_scalar(node)
216  return None
217 
218  bool_values = {
219  u'yes': True,
220  u'no': False,
221  u'true': True,
222  u'false': False,
223  u'on': True,
224  u'off': False,
225  }
226 
227  def construct_yaml_bool(self, node):
228  value = self.construct_scalar(node)
229  return self.bool_values[value.lower()]
230 
231  def construct_yaml_int(self, node):
232  value = str(self.construct_scalar(node))
233  value = value.replace('_', '')
234  sign = +1
235  if value[0] == '-':
236  sign = -1
237  if value[0] in '+-':
238  value = value[1:]
239  if value == '0':
240  return 0
241  elif value.startswith('0b'):
242  return sign*int(value[2:], 2)
243  elif value.startswith('0x'):
244  return sign*int(value[2:], 16)
245  elif value[0] == '0':
246  return sign*int(value, 8)
247  elif ':' in value:
248  digits = [int(part) for part in value.split(':')]
249  digits.reverse()
250  base = 1
251  value = 0
252  for digit in digits:
253  value += digit*base
254  base *= 60
255  return sign*value
256  else:
257  return sign*int(value)
258 
259  inf_value = 1e300
260  while inf_value != inf_value*inf_value:
261  inf_value *= inf_value
262  nan_value = -inf_value/inf_value # Trying to make a quiet NaN (like C99).
263 
264  def construct_yaml_float(self, node):
265  value = str(self.construct_scalar(node))
266  value = value.replace('_', '').lower()
267  sign = +1
268  if value[0] == '-':
269  sign = -1
270  if value[0] in '+-':
271  value = value[1:]
272  if value == '.inf':
273  return sign*self.inf_value
274  elif value == '.nan':
275  return self.nan_value
276  elif ':' in value:
277  digits = [float(part) for part in value.split(':')]
278  digits.reverse()
279  base = 1
280  value = 0.0
281  for digit in digits:
282  value += digit*base
283  base *= 60
284  return sign*value
285  else:
286  return sign*float(value)
287 
288  def construct_yaml_binary(self, node):
289  value = self.construct_scalar(node)
290  try:
291  return str(value).decode('base64')
292  except (binascii.Error, UnicodeEncodeError), exc:
293  raise ConstructorError(None, None,
294  "failed to decode base64 data: %s" % exc, node.start_mark)
295 
296  timestamp_regexp = re.compile(
297  ur'''^(?P<year>[0-9][0-9][0-9][0-9])
298  -(?P<month>[0-9][0-9]?)
299  -(?P<day>[0-9][0-9]?)
300  (?:(?:[Tt]|[ \t]+)
301  (?P<hour>[0-9][0-9]?)
302  :(?P<minute>[0-9][0-9])
303  :(?P<second>[0-9][0-9])
304  (?:\.(?P<fraction>[0-9]*))?
305  (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
306  (?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
307 
308  def construct_yaml_timestamp(self, node):
309  value = self.construct_scalar(node)
310  match = self.timestamp_regexp.match(node.value)
311  values = match.groupdict()
312  year = int(values['year'])
313  month = int(values['month'])
314  day = int(values['day'])
315  if not values['hour']:
316  return datetime.date(year, month, day)
317  hour = int(values['hour'])
318  minute = int(values['minute'])
319  second = int(values['second'])
320  fraction = 0
321  if values['fraction']:
322  fraction = int(values['fraction'][:6].ljust(6, '0'))
323  delta = None
324  if values['tz_sign']:
325  tz_hour = int(values['tz_hour'])
326  tz_minute = int(values['tz_minute'] or 0)
327  delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
328  if values['tz_sign'] == '-':
329  delta = -delta
330  data = datetime.datetime(year, month, day, hour, minute, second, fraction)
331  if delta:
332  data -= delta
333  return data
334 
335  def construct_yaml_omap(self, node):
336  # Note: we do not check for duplicate keys, because it's too
337  # CPU-expensive.
338  omap = []
339  yield omap
340  if not isinstance(node, SequenceNode):
341  raise ConstructorError("while constructing an ordered map", node.start_mark,
342  "expected a sequence, but found %s" % node.id, node.start_mark)
343  for subnode in node.value:
344  if not isinstance(subnode, MappingNode):
345  raise ConstructorError("while constructing an ordered map", node.start_mark,
346  "expected a mapping of length 1, but found %s" % subnode.id,
347  subnode.start_mark)
348  if len(subnode.value) != 1:
349  raise ConstructorError("while constructing an ordered map", node.start_mark,
350  "expected a single mapping item, but found %d items" % len(subnode.value),
351  subnode.start_mark)
352  key_node, value_node = subnode.value[0]
353  key = self.construct_object(key_node)
354  value = self.construct_object(value_node)
355  omap.append((key, value))
356 
357  def construct_yaml_pairs(self, node):
358  # Note: the same code as `construct_yaml_omap`.
359  pairs = []
360  yield pairs
361  if not isinstance(node, SequenceNode):
362  raise ConstructorError("while constructing pairs", node.start_mark,
363  "expected a sequence, but found %s" % node.id, node.start_mark)
364  for subnode in node.value:
365  if not isinstance(subnode, MappingNode):
366  raise ConstructorError("while constructing pairs", node.start_mark,
367  "expected a mapping of length 1, but found %s" % subnode.id,
368  subnode.start_mark)
369  if len(subnode.value) != 1:
370  raise ConstructorError("while constructing pairs", node.start_mark,
371  "expected a single mapping item, but found %d items" % len(subnode.value),
372  subnode.start_mark)
373  key_node, value_node = subnode.value[0]
374  key = self.construct_object(key_node)
375  value = self.construct_object(value_node)
376  pairs.append((key, value))
377 
378  def construct_yaml_set(self, node):
379  data = set()
380  yield data
381  value = self.construct_mapping(node)
382  data.update(value)
383 
384  def construct_yaml_str(self, node):
385  value = self.construct_scalar(node)
386  try:
387  return value.encode('ascii')
388  except UnicodeEncodeError:
389  return value
390 
391  def construct_yaml_seq(self, node):
392  data = []
393  yield data
394  data.extend(self.construct_sequence(node))
395 
396  def construct_yaml_map(self, node):
397  data = {}
398  yield data
399  value = self.construct_mapping(node)
400  data.update(value)
401 
402  def construct_yaml_object(self, node, cls):
403  data = cls.__new__(cls)
404  yield data
405  if hasattr(data, '__setstate__'):
406  state = self.construct_mapping(node, deep=True)
407  data.__setstate__(state)
408  else:
409  state = self.construct_mapping(node)
410  data.__dict__.update(state)
411 
412  def construct_undefined(self, node):
413  raise ConstructorError(None, None,
414  "could not determine a constructor for the tag %r" % node.tag.encode('utf-8'),
415  node.start_mark)
416 
417 SafeConstructor.add_constructor(
418  u'tag:yaml.org,2002:null',
419  SafeConstructor.construct_yaml_null)
420 
421 SafeConstructor.add_constructor(
422  u'tag:yaml.org,2002:bool',
423  SafeConstructor.construct_yaml_bool)
424 
425 SafeConstructor.add_constructor(
426  u'tag:yaml.org,2002:int',
427  SafeConstructor.construct_yaml_int)
428 
429 SafeConstructor.add_constructor(
430  u'tag:yaml.org,2002:float',
431  SafeConstructor.construct_yaml_float)
432 
433 SafeConstructor.add_constructor(
434  u'tag:yaml.org,2002:binary',
435  SafeConstructor.construct_yaml_binary)
436 
437 SafeConstructor.add_constructor(
438  u'tag:yaml.org,2002:timestamp',
439  SafeConstructor.construct_yaml_timestamp)
440 
441 SafeConstructor.add_constructor(
442  u'tag:yaml.org,2002:omap',
443  SafeConstructor.construct_yaml_omap)
444 
445 SafeConstructor.add_constructor(
446  u'tag:yaml.org,2002:pairs',
447  SafeConstructor.construct_yaml_pairs)
448 
449 SafeConstructor.add_constructor(
450  u'tag:yaml.org,2002:set',
451  SafeConstructor.construct_yaml_set)
452 
453 SafeConstructor.add_constructor(
454  u'tag:yaml.org,2002:str',
455  SafeConstructor.construct_yaml_str)
456 
457 SafeConstructor.add_constructor(
458  u'tag:yaml.org,2002:seq',
459  SafeConstructor.construct_yaml_seq)
460 
461 SafeConstructor.add_constructor(
462  u'tag:yaml.org,2002:map',
463  SafeConstructor.construct_yaml_map)
464 
465 SafeConstructor.add_constructor(None,
466  SafeConstructor.construct_undefined)
467 
469 
470  def construct_python_str(self, node):
471  return self.construct_scalar(node).encode('utf-8')
472 
473  def construct_python_unicode(self, node):
474  return self.construct_scalar(node)
475 
476  def construct_python_long(self, node):
477  return long(self.construct_yaml_int(node))
478 
479  def construct_python_complex(self, node):
480  return complex(self.construct_scalar(node))
481 
482  def construct_python_tuple(self, node):
483  return tuple(self.construct_sequence(node))
484 
485  def find_python_module(self, name, mark):
486  if not name:
487  raise ConstructorError("while constructing a Python module", mark,
488  "expected non-empty name appended to the tag", mark)
489  try:
490  __import__(name)
491  except ImportError, exc:
492  raise ConstructorError("while constructing a Python module", mark,
493  "cannot find module %r (%s)" % (name.encode('utf-8'), exc), mark)
494  return sys.modules[name]
495 
496  def find_python_name(self, name, mark):
497  if not name:
498  raise ConstructorError("while constructing a Python object", mark,
499  "expected non-empty name appended to the tag", mark)
500  if u'.' in name:
501  # Python 2.4 only
502  #module_name, object_name = name.rsplit('.', 1)
503  items = name.split('.')
504  object_name = items.pop()
505  module_name = '.'.join(items)
506  else:
507  module_name = '__builtin__'
508  object_name = name
509  try:
510  __import__(module_name)
511  except ImportError, exc:
512  raise ConstructorError("while constructing a Python object", mark,
513  "cannot find module %r (%s)" % (module_name.encode('utf-8'), exc), mark)
514  module = sys.modules[module_name]
515  if not hasattr(module, object_name):
516  raise ConstructorError("while constructing a Python object", mark,
517  "cannot find %r in the module %r" % (object_name.encode('utf-8'),
518  module.__name__), mark)
519  return getattr(module, object_name)
520 
521  def construct_python_name(self, suffix, node):
522  value = self.construct_scalar(node)
523  if value:
524  raise ConstructorError("while constructing a Python name", node.start_mark,
525  "expected the empty value, but found %r" % value.encode('utf-8'),
526  node.start_mark)
527  return self.find_python_name(suffix, node.start_mark)
528 
529  def construct_python_module(self, suffix, node):
530  value = self.construct_scalar(node)
531  if value:
532  raise ConstructorError("while constructing a Python module", node.start_mark,
533  "expected the empty value, but found %r" % value.encode('utf-8'),
534  node.start_mark)
535  return self.find_python_module(suffix, node.start_mark)
536 
537  class classobj: pass
538 
539  def make_python_instance(self, suffix, node,
540  args=None, kwds=None, newobj=False):
541  if not args:
542  args = []
543  if not kwds:
544  kwds = {}
545  cls = self.find_python_name(suffix, node.start_mark)
546  if newobj and isinstance(cls, type(self.classobj)) \
547  and not args and not kwds:
548  instance = self.classobj()
549  instance.__class__ = cls
550  return instance
551  elif newobj and isinstance(cls, type):
552  return cls.__new__(cls, *args, **kwds)
553  else:
554  return cls(*args, **kwds)
555 
556  def set_python_instance_state(self, instance, state):
557  if hasattr(instance, '__setstate__'):
558  instance.__setstate__(state)
559  else:
560  slotstate = {}
561  if isinstance(state, tuple) and len(state) == 2:
562  state, slotstate = state
563  if hasattr(instance, '__dict__'):
564  instance.__dict__.update(state)
565  elif state:
566  slotstate.update(state)
567  for key, value in slotstate.items():
568  setattr(object, key, value)
569 
570  def construct_python_object(self, suffix, node):
571  # Format:
572  # !!python/object:module.name { ... state ... }
573  instance = self.make_python_instance(suffix, node, newobj=True)
574  yield instance
575  deep = hasattr(instance, '__setstate__')
576  state = self.construct_mapping(node, deep=deep)
577  self.set_python_instance_state(instance, state)
578 
579  def construct_python_object_apply(self, suffix, node, newobj=False):
580  # Format:
581  # !!python/object/apply # (or !!python/object/new)
582  # args: [ ... arguments ... ]
583  # kwds: { ... keywords ... }
584  # state: ... state ...
585  # listitems: [ ... listitems ... ]
586  # dictitems: { ... dictitems ... }
587  # or short format:
588  # !!python/object/apply [ ... arguments ... ]
589  # The difference between !!python/object/apply and !!python/object/new
590  # is how an object is created, check make_python_instance for details.
591  if isinstance(node, SequenceNode):
592  args = self.construct_sequence(node, deep=True)
593  kwds = {}
594  state = {}
595  listitems = []
596  dictitems = {}
597  else:
598  value = self.construct_mapping(node, deep=True)
599  args = value.get('args', [])
600  kwds = value.get('kwds', {})
601  state = value.get('state', {})
602  listitems = value.get('listitems', [])
603  dictitems = value.get('dictitems', {})
604  instance = self.make_python_instance(suffix, node, args, kwds, newobj)
605  if state:
606  self.set_python_instance_state(instance, state)
607  if listitems:
608  instance.extend(listitems)
609  if dictitems:
610  for key in dictitems:
611  instance[key] = dictitems[key]
612  return instance
613 
614  def construct_python_object_new(self, suffix, node):
615  return self.construct_python_object_apply(suffix, node, newobj=True)
616 
617 Constructor.add_constructor(
618  u'tag:yaml.org,2002:python/none',
619  Constructor.construct_yaml_null)
620 
621 Constructor.add_constructor(
622  u'tag:yaml.org,2002:python/bool',
623  Constructor.construct_yaml_bool)
624 
625 Constructor.add_constructor(
626  u'tag:yaml.org,2002:python/str',
627  Constructor.construct_python_str)
628 
629 Constructor.add_constructor(
630  u'tag:yaml.org,2002:python/unicode',
631  Constructor.construct_python_unicode)
632 
633 Constructor.add_constructor(
634  u'tag:yaml.org,2002:python/int',
635  Constructor.construct_yaml_int)
636 
637 Constructor.add_constructor(
638  u'tag:yaml.org,2002:python/long',
639  Constructor.construct_python_long)
640 
641 Constructor.add_constructor(
642  u'tag:yaml.org,2002:python/float',
643  Constructor.construct_yaml_float)
644 
645 Constructor.add_constructor(
646  u'tag:yaml.org,2002:python/complex',
647  Constructor.construct_python_complex)
648 
649 Constructor.add_constructor(
650  u'tag:yaml.org,2002:python/list',
651  Constructor.construct_yaml_seq)
652 
653 Constructor.add_constructor(
654  u'tag:yaml.org,2002:python/tuple',
655  Constructor.construct_python_tuple)
656 
657 Constructor.add_constructor(
658  u'tag:yaml.org,2002:python/dict',
659  Constructor.construct_yaml_map)
660 
661 Constructor.add_multi_constructor(
662  u'tag:yaml.org,2002:python/name:',
663  Constructor.construct_python_name)
664 
665 Constructor.add_multi_constructor(
666  u'tag:yaml.org,2002:python/module:',
667  Constructor.construct_python_module)
668 
669 Constructor.add_multi_constructor(
670  u'tag:yaml.org,2002:python/object:',
671  Constructor.construct_python_object)
672 
673 Constructor.add_multi_constructor(
674  u'tag:yaml.org,2002:python/object/apply:',
675  Constructor.construct_python_object_apply)
676 
677 Constructor.add_multi_constructor(
678  u'tag:yaml.org,2002:python/object/new:',
679  Constructor.construct_python_object_new)
680 
Fstring::size_type len(Fstring const &s)
Length.
Definition: Fstring.hh:2207
Fstring ljust(Fstring const &s)
Left-Justified Copy.
Definition: Fstring.hh:2404