summaryrefslogtreecommitdiff
path: root/reconfigure/nodes.py
diff options
context:
space:
mode:
authorAndrew Shadura <andrew@shadura.me>2015-08-20 15:58:26 +0200
committerAndrew Shadura <andrew@shadura.me>2015-08-20 15:58:26 +0200
commitff1408420159488a106492ccd11dd234967029b6 (patch)
tree473420cee1c5229a427ec4cafead1aa6c0a26800 /reconfigure/nodes.py
Imported Upstream version 0.1.29
Diffstat (limited to 'reconfigure/nodes.py')
-rw-r--r--reconfigure/nodes.py184
1 files changed, 184 insertions, 0 deletions
diff --git a/reconfigure/nodes.py b/reconfigure/nodes.py
new file mode 100644
index 0000000..3335ad5
--- /dev/null
+++ b/reconfigure/nodes.py
@@ -0,0 +1,184 @@
+class Node (object):
+ """
+ A base node class for the Node Tree.
+ This class represents a named container node.
+ """
+
+ def __init__(self, name=None, *args, **kwargs):
+ """
+ :param name: Node name
+ :param *args: Children
+ :param comment: Node comment string
+ :param origin: Node's source location (usually path to the file)
+ """
+ self.name = name
+ self.origin = None
+ self.children = []
+ for node in list(args) + kwargs.pop('children', []):
+ self.append(node)
+ self.comment = kwargs.pop('comment', None)
+ self.__dict__.update(kwargs)
+
+ def __str__(self):
+ s = '(%s)' % self.name
+ if self.comment:
+ s += ' (%s)' % self.comment
+ s += '\n'
+ for child in self.children:
+ s += '\n'.join('\t' + x for x in str(child).splitlines()) + '\n'
+ return s
+
+ def __hash__(self):
+ return sum(hash(x) for x in [self.name, self.origin, self.comment] + self.children)
+
+ def __eq__(self, other):
+ if other is None:
+ return False
+
+ return \
+ self.name == other.name and \
+ self.comment == other.comment and \
+ self.origin == other.origin and \
+ set(self.children) == set(other.children)
+
+ def __iter__(self):
+ return iter(self.children)
+
+ def __len__(self):
+ return len(self.children)
+
+ def __nonzero__(self):
+ return True
+
+ def __getitem__(self, key):
+ if type(key) in (int, slice):
+ return self.children[key]
+ return self.get(key)
+
+ def __setitem__(self, key, value):
+ if type(key) is int:
+ self.children[key] = value
+ self.set_property(key, value)
+
+ def __contains__(self, item):
+ return item in self.children
+
+ def indexof(self, node):
+ """
+ :returns: index of the node in the children array or ``None`` if it's not a child
+ """
+ if node in self.children:
+ return self.children.index(node)
+ else:
+ return None
+
+ def get(self, name, default=None):
+ """
+ :returns: a child node by its name or ``default``
+ """
+ for child in self.children:
+ if child.name == name:
+ return child
+ if default:
+ self.append(default)
+ return default
+
+ def get_all(self, name):
+ """
+ :returns: list of child nodes with supplied ``name``
+ """
+ return [n for n in self.children if n.name == name]
+
+ def append(self, node):
+ if not node.origin:
+ node.origin = self.origin
+ self.children.append(node)
+ node.parent = self
+
+ def remove(self, node):
+ self.children.remove(node)
+
+ def replace(self, name, node=None):
+ """
+ Replaces the child nodes by ``name``
+
+ :param node: replacement node or list of nodes
+
+ ::
+
+ n.append(Node('a'))
+ n.append(Node('a'))
+ n.replace('a', None)
+ assert(len(n.get_all('a')) == 0)
+
+ """
+ if name:
+ self.children = [c for c in self.children if c.name != name]
+ if node is not None:
+ if type(node) == list:
+ for n in node:
+ self.children.append(n)
+ else:
+ self.children.append(node)
+
+ def set_property(self, name, value):
+ """
+ Creates or replaces a child :class:`PropertyNode` by name.
+ """
+ node = self.get(name)
+ if not node:
+ node = PropertyNode(name, value)
+ self.append(node)
+ node.value = value
+ return self
+
+
+class RootNode (Node):
+ """
+ A special node class that indicates tree root
+ """
+
+
+class PropertyNode (Node):
+ """
+ A node that serves as a property of its parent node.
+ """
+
+ def __init__(self, name, value, comment=None):
+ """
+ :param name: Property name
+ :param value: Property value
+ """
+ Node.__init__(self, name, comment=comment)
+ self.value = value
+
+ def __eq__(self, other):
+ if other is None:
+ return False
+
+ return \
+ Node.__eq__(self, other) and \
+ self.value == other.value
+
+ def __str__(self):
+ s = '%s = %s' % (self.name, self.value)
+ if self.comment:
+ s += ' (%s)' % self.comment
+ return s
+
+
+class IncludeNode (Node):
+ """
+ A node that indicates a junction point between two config files
+ """
+
+ def __init__(self, files):
+ """
+ :param files: an includer-dependent config location specifier
+ """
+ Node.__init__(self)
+ self.name = '<include>'
+ self.files = files
+
+ def __str__(self):
+ return '<include> %s' % self.files