from collections import OrderedDict from jwutils.log import * def quote(s): if is_quoted(s): return s s = s.strip() if len(s) > 0: if s[0] == '"': return "'" + s + "'" return '"' + s + '"' def is_quoted(s): if isinstance(s, StringTree): return False s = s.strip() if len(s) < 2: return False d = s[0] if d == s[-1] and d in [ '"', "'" ]: return True return False def cleanup_string(s): if isinstance(s, StringTree): return s s = s.strip() if is_quoted(s): return s[1:-1] return s class StringTree: # export def __init__(self, path, content): slog(DEBUG, "ctor, path =", path, "content =", content) self.children = OrderedDict() self.content = None self.__set(path, content) assert(hasattr(self, "content")) #assert self.content is not None # root (content = [ symbols ]) # symbols (content = [ regex ]) # regex ( content ='[ \n\t\r]+' ) # root (content = root, children = [ symbols ]) # symbols (content = symbols, children = [ regex ]) # regex ( content = regex, children = [ '[ \n\t\r]+' ] ) # '[ \n\t\r]+)' ( content = '\n\t\r]+)', children = [] ) def __set(self, path_, content): logcontent = "not-yet" if hasattr(self, "content"): logcontent = self.content slog(DEBUG, "+ setting", content, "at path \"" + str(path_) + "\" to", logcontent) if content is not None: content = cleanup_string(content) if path_ is None: self.content = content return self path = cleanup_string(path_) components = path.split('.') l = len(components) if len(path) == 0 or l == 0: assert self.content is None self.content = content #self.children[content] = StringTree(None, content) return self assert self.content is not None nibble = components[0] rest = '.'.join(components[1:]) if nibble not in self.children: self.children[nibble] = StringTree('', content=nibble) if l > 1: assert len(rest) > 0 return self.children[nibble].__set(rest, content=content) if content is not None: self.children[nibble].children[content] = StringTree('', content=content) return self.children[nibble] def __getitem__(self, path): r = self.get(path) if r is None: raise KeyError(path) return r def __setitem__(self, key, value): return self.__set(key, value) def __dump(self, prio, indent=0, caller=None, *args): if caller is None: caller = get_caller_pos(1) slog(prio, (' ' * indent) + str(self.content), caller=caller) indent += 2 for name, child in self.children.iteritems(): child.__dump(prio, indent=indent, caller=caller) def keys(self): return self.children.keys() def iteritems(self): return self.children.iteritems() def set_content(self, content): if content is None: raise Exception("Tried to set none content") content = cleanup_string(content) if len(content) == 0: raise Exception("Tried to set empty content") self.content = content def add(self, path, content = None): slog(DEBUG, "adding", content, "at", path, "to", self.content) return self.__set(path, content) def get(self, path_): slog(DEBUG, "looking for", path_, "in", self.content) path = cleanup_string(path_) if len(path) == 0: slog(DEBUG, "returning myself") return self if is_quoted(path_): if not path in self.children.keys(): return None return self.children[path] components = path.split('.') if len(components) == 0: return self name = cleanup_string(components[0]) if not hasattr(self, "children"): return None if not name in self.children.keys(): slog(DEBUG, "Name \"" + name + "\" is not in children of", self.content) for child in self.children: slog(DEBUG, "child = ", child) return None relpath = '.'.join(components[1:]) return self.children[name].get(relpath) def value(self): if len(self.children) == 0: return None return next(reversed(self.children)) def dump(self, prio, caller=None, *args): if caller is None: caller = get_caller_pos(1) self.__dump(prio, indent=0, caller=caller)