# Python 2.2 compatibility from __future__ import generators try: import datetime except ImportError: pass try: import sets except ImportError: class _sets: def Set(self, items): set = {} for items in items: set[items] = None return set sets = _sets() import _syck import re __all__ = ['GenericLoader', 'Loader', 'parse', 'load', 'parse_documents', 'load_documents'] class GenericLoader(_syck.Parser): def load(self): node = self.parse() if self.eof: return return self._convert(node, {}) def _convert(self, node, node_to_object): if node in node_to_object: return node_to_object[node] value = None if node.kind == 'scalar': value = node.value elif node.kind == 'seq': value = [] for item_node in node.value: value.append(self._convert(item_node, node_to_object)) elif node.kind == 'map': value = {} for key_node in node.value: key_object = self._convert(key_node, node_to_object) value_object = self._convert(node.value[key_node], node_to_object) if key_object in value: value = None break try: value[key_object] = value_object except TypeError: value = None break if value is None: value = [] for key_node in node.value: key_object = self_convert(key_node, node_to_object) value_object = self._convert(node.value[key_node], node_to_object) value.append((key_object, value_object)) node.value = value object = self.construct(node) node_to_object[node] = object return object def construct(self, node): return node.value class Merge: pass class Default: pass class Loader(GenericLoader): inf_value = 1e300000 nan_value = inf_value/inf_value ymd_expr = re.compile(r'(?P\d\d\d\d)-(?P\d\d)-(?P\d\d)') timestamp_expr = re.compile(r'(?P\d\d\d\d)-(?P\d\d)-(?P\d\d)' r'(?:' r'(?:[Tt]|[ \t]+)(?P\d\d):(?P\d\d):(?P\d\d)' r'(?:\.(?P\d+)?)?' r'[ \t]*(?:Z|(?P[+-]\d\d)(?::(?P\d\d))?)?' r')?') merge_key = Merge() default_key = Default() def __init__(self, *args, **kwds): super(Loader, self).__init__(*args, **kwds) self.tags = {} self.add_builtin_types() def add_builtin_types(self): self.add_builtin_type('null', lambda node: None) self.add_builtin_type('bool#yes', lambda node: True) self.add_builtin_type('bool#no', lambda node: False) self.add_builtin_type('float#fix', lambda node: float(node.value)) self.add_builtin_type('float#exp', lambda node: float(node.value)) self.add_builtin_type('float#base60', 'construct_base60_float') self.add_builtin_type('float#inf', lambda node: self.inf_value) self.add_builtin_type('float#neginf', lambda node: -self.inf_value) self.add_builtin_type('float#nan', lambda node: self.nan_value) self.add_builtin_type('int', lambda node: int(node.value)) self.add_builtin_type('int#hex', lambda node: int(node.value, 16)) self.add_builtin_type('int#oct', lambda node: int(node.value, 8)) self.add_builtin_type('int#base60', 'construct_base60_int') self.add_builtin_type('binary', lambda node: node.value.decode('base64')) self.add_builtin_type('timestamp#ymd', 'construct_timestamp') self.add_builtin_type('timestamp#iso8601', 'construct_timestamp') self.add_builtin_type('timestamp#spaced', 'construct_timestamp') self.add_builtin_type('timestamp', 'construct_timestamp') self.add_builtin_type('merge', 'construct_merge') self.add_builtin_type('default', 'construct_default') self.add_builtin_type('omap', 'construct_omap') self.add_builtin_type('pairs', 'construct_pairs') self.add_builtin_type('set', 'construct_set') def add_type(self, type_tag, constuctor): self.tags[type_tag] = constructor def add_domain_type(self, domain, type_tag, constructor): self.tags['tag:%s:%s' % (domain, type_tag)] = constructor def add_builtin_type(self, type_tag, constructor): self.tags['tag:yaml.org,2002:'+type_tag] = constructor def add_python_type(self, type_tag, constructor): self.tags['tag:python.yaml.org,2002:'+type_tag] = constructor def add_private_type(self, type_tag, constructor): self.tags['x-private:'+type_tag] = constructor def construct(self, node): if node.kind == 'map' and self.merge_key in node.value: self.merge_maps(node) if node.tag in self.tags: constructor = self.tags[node.tag] if isinstance(constructor, str): constructor = getattr(self, constructor) return constructor(node) else: return node.value def construct_base60_float(self, node): return self.construct_base60(float, node) def construct_base60_int(self, node): return self.construct_base60(int, node) def construct_base60(self, num_type, node): digits = [num_type(part) for part in node.value.split(':')] digits.reverse() base = 1 value = num_type(0) for digit in digits: value += digit*base base *= 60 return value def construct_timestamp(self, node): match = self.timestamp_expr.match(node.value) values = match.groupdict() for key in values: if values[key]: values[key] = int(values[key]) else: values[key] = 0 micro = values['micro'] if micro: while 10*micro < 1000000: micro *= 10 stamp = datetime.datetime(values['year'], values['month'], values['day'], values['hour'], values['minute'], values['second'], micro) diff = datetime.timedelta(hours=values['zhour'], minutes=values['zminute']) return stamp-diff def construct_merge(self, node): return self.merge_key def construct_default(self, node): return self.default_key def merge_maps(self, node): maps = node.value[self.merge_key] del node.value[self.merge_key] if not isinstance(maps, list): maps = [maps] maps.reverse() maps.append(node.value.copy()) for item in maps: node.value.update(item) def construct_omap(self, node): omap = [] for mapping in node.value: for key in mapping: omap.append((key, mapping[key])) return omap def construct_pairs(self, node): # Same as construct_omap. pairs = [] for mapping in node.value: for key in mapping: pairs.append((key, mapping[key])) return pairs def construct_set(self, node): return sets.Set(node.value) def parse(source): """Parses 'source' and returns the root of the 'Node' graph.""" loader = Loader(source) return loader.parse() def load(source): """Parses 'source' and returns the root object.""" loader = Loader(source) return loader.load() def parse_documents(source): """Iterates over 'source' and yields the root node of each document.""" loader = Loader(source) while True: node = loader.parse() if loader.eof: break yield node def load_documents(source): """Iterates over 'source' and yields the root object of each document.""" loader = Loader(source) while True: object = loader.load() if loader.eof: break yield object