summaryrefslogtreecommitdiff
path: root/lib/yaml/constructor.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yaml/constructor.py')
-rw-r--r--lib/yaml/constructor.py254
1 files changed, 254 insertions, 0 deletions
diff --git a/lib/yaml/constructor.py b/lib/yaml/constructor.py
new file mode 100644
index 0000000..352709b
--- /dev/null
+++ b/lib/yaml/constructor.py
@@ -0,0 +1,254 @@
+
+from error import *
+from nodes import *
+
+try:
+ import datetime
+ datetime_available = True
+except ImportError:
+ datetime_available = False
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+import binascii
+
+class ConstructorError(MarkedYAMLError):
+ pass
+
+class BaseConstructor:
+
+ def __init__(self, resolver):
+ self.resolver = resolver
+ self.constructed_objects = {}
+
+ def check(self):
+ # If there are more documents available?
+ return self.resolver.check()
+
+ def get(self):
+ # Construct and return the next document.
+ if self.resolver.check():
+ return self.construct_document(self.resolver.get())
+
+ def __iter__(self):
+ # Iterator protocol.
+ while self.resolver.check():
+ yield self.construct_document(self.resolver.get())
+
+ def construct_document(self, node):
+ native = self.construct_object(node)
+ self.constructed_objects = {}
+ return native
+
+ def construct_object(self, node):
+ if node in self.constructed_objects:
+ return self.constructed_objects[node]
+ if node.tag in self.yaml_constructors:
+ native = self.yaml_constructors[node.tag](self, node)
+ elif None in self.yaml_constructors:
+ native = self.yaml_constructors[None](self, node)
+ elif isinstance(node, ScalarNode):
+ native = self.construct_scalar(node)
+ elif isinstance(node, SequenceNode):
+ native = self.construct_sequence(node)
+ elif isinstance(node, MappingNode):
+ native = self.construct_mapping(node)
+ self.constructed_objects[node] = native
+ return native
+
+ def construct_scalar(self, node):
+ if not isinstance(node, ScalarNode):
+ if isinstance(node, MappingNode):
+ for key_node in node.value:
+ if key_node.tag == u'tag:yaml.org,2002:value':
+ return self.construct_scalar(node.value[key_node])
+ raise ConstructorError(None, None,
+ "expected a scalar node, but found %s" % node.id,
+ node.start_marker)
+ return node.value
+
+ def construct_sequence(self, node):
+ if not isinstance(node, SequenceNode):
+ raise ConstructorError(None, None,
+ "expected a sequence node, but found %s" % node.id,
+ node.start_marker)
+ return [self.construct_object(child) for child in node.value]
+
+ def construct_mapping(self, node):
+ if not isinstance(node, MappingNode):
+ raise ConstructorError(None, None,
+ "expected a mapping node, but found %s" % node.id,
+ node.start_marker)
+ mapping = {}
+ for key_node in node.value:
+ key = self.construct_object(key_node)
+ try:
+ duplicate_key = key in mapping
+ except TypeError, exc:
+ raise ConstructorError("while constructing a mapping", node.start_marker,
+ "found unacceptable key (%s)" % exc, key_node.start_marker)
+ if duplicate_key:
+ raise ConstructorError("while constructing a mapping", node.start_marker,
+ "found duplicate key", key_node.start_marker)
+ value = self.construct_object(node.value[key_node])
+ mapping[key] = value
+ return mapping
+
+ def construct_pairs(self, node):
+ if not isinstance(node, MappingNode):
+ raise ConstructorError(None, None,
+ "expected a mapping node, but found %s" % node.id,
+ node.start_marker)
+ pairs = []
+ for key_node in node.value:
+ key = self.construct_object(key_node)
+ value = self.construct_object(node.value[key_node])
+ pairs.append((key, value))
+ return pairs
+
+ def add_constructor(cls, tag, constructor):
+ if not 'yaml_constructors' in cls.__dict__:
+ cls.yaml_constructors = cls.yaml_constructors.copy()
+ cls.yaml_constructors[tag] = constructor
+ add_constructor = classmethod(add_constructor)
+
+ yaml_constructors = {}
+
+class Constructor(BaseConstructor):
+
+ def construct_yaml_null(self, node):
+ self.construct_scalar(node)
+ return None
+
+ bool_values = {
+ u'y': True,
+ u'yes': True,
+ u'n': False,
+ u'no': False,
+ u'true': True,
+ u'false': False,
+ u'on': True,
+ u'off': False,
+ }
+
+ def construct_yaml_bool(self, node):
+ value = self.construct_scalar(node)
+ return self.bool_values[value.lower()]
+
+ def construct_yaml_int(self, node):
+ value = str(self.construct_scalar(node))
+ value = value.replace('_', '')
+ sign = +1
+ if value[0] == '-':
+ sign = -1
+ if value[0] in '+-':
+ value = value[1:]
+ if value == '0':
+ return 0
+ elif value.startswith('0b'):
+ return sign*int(value[2:], 2)
+ elif value.startswith('0x'):
+ return sign*int(value[2:], 16)
+ elif value[0] == '0':
+ return sign*int(value, 8)
+ elif ':' in value:
+ digits = [int(part) for part in value.split(':')]
+ digits.reverse()
+ base = 1
+ value = 0
+ for digit in digits:
+ value += digit*base
+ base *= 60
+ return sign*value
+ else:
+ return sign*int(value)
+
+ inf_value = 1e300000
+ nan_value = inf_value/inf_value
+
+ def construct_yaml_float(self, node):
+ value = str(self.construct_scalar(node))
+ value = value.replace('_', '')
+ sign = +1
+ if value[0] == '-':
+ value = -1
+ if value[0] in '+-':
+ value = value[1:]
+ if value.lower() == '.inf':
+ return sign*self.inf_value
+ elif value.lower() == '.nan':
+ return self.nan_value
+ elif ':' in value:
+ digits = [float(part) for part in value.split(':')]
+ digits.reverse()
+ base = 1
+ value = 0.0
+ for digit in digits:
+ value += digit*base
+ base *= 60
+ return sign*value
+ else:
+ return float(value)
+
+ def construct_yaml_binary(self, node):
+ value = self.construct_scalar(node)
+ try:
+ return str(value).decode('base64')
+ except (binascii.Error, UnicodeEncodeError), exc:
+ raise ConstructorError(None, None,
+ "failed to decode base64 data: %s" % exc, node.start_mark)
+
+ def construct_yaml_str(self, node):
+ value = self.construct_scalar(node)
+ try:
+ return str(value)
+ except UnicodeEncodeError:
+ return value
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:null',
+ Constructor.construct_yaml_null)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:bool',
+ Constructor.construct_yaml_bool)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:int',
+ Constructor.construct_yaml_int)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:float',
+ Constructor.construct_yaml_float)
+
+Constructor.add_constructor(
+ u'tag:yaml.org,2002:str',
+ Constructor.construct_yaml_str)
+
+class YAMLObjectMetaclass(type):
+
+ def __init__(cls, name, bases, kwds):
+ super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
+ if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
+ cls.yaml_constructor_class.add_constructor(cls.yaml_tag, cls.from_yaml)
+
+class YAMLObject(object):
+
+ __metaclass__ = YAMLObjectMetaclass
+
+ yaml_constructor_class = Constructor
+
+ yaml_tag = None
+
+ def from_yaml(cls, constructor, node):
+ raise ConstructorError(None, None,
+ "found undefined constructor for the tag %r"
+ % node.tag.encode('utf-8'), node.start_marker)
+ from_yaml = classmethod(from_yaml)
+
+ def to_yaml(self):
+ assert False # needs dumper
+