class _BaseLoader(Loader): """ YAML loader with additional features related to mux """ Loader.add_constructor(u'!include', lambda loader, node: mux.Control(YAML_INCLUDE)) Loader.add_constructor(u'!using', lambda loader, node: mux.Control(YAML_USING)) Loader.add_constructor(u'!remove_node', lambda loader, node: mux.Control(YAML_REMOVE_NODE)) Loader.add_constructor(u'!remove_value', lambda loader, node: mux.Control(YAML_REMOVE_VALUE))
def mux_loader(loader, obj): """ Special !mux loader which allows to tag node as 'multiplex = True'. """ if not isinstance(obj, yaml.ScalarNode): objects = mapping_to_tree_loader(loader, obj) else: # This means it's empty node. Don't call mapping_to_tree_loader objects = ListOfNodeObjects() objects.append((mux.Control(YAML_MUX), None)) return objects
def test_tree_mux_node(self): """ Check the extension of fingerprint in MuxTreeNode """ node1 = tree.TreeNode("node1", {"foo": "bar"}) node1m = mux.MuxTreeNode("node1", {"foo": "bar"}) node1m_fingerprint = node1m.fingerprint() self.assertNotEqual(node1.fingerprint(), node1m_fingerprint) node1mduplicate = mux.MuxTreeNode("node1", {"foo": "bar"}) self.assertEqual(node1m_fingerprint, node1mduplicate.fingerprint()) node1mb_ctrl = mux.MuxTreeNode("node1", {"foo": "bar"}) node1mb_ctrl.ctrl = [mux.Control(0, 0)] self.assertNotEqual(node1m_fingerprint, node1mb_ctrl.fingerprint())
class _BaseLoader(Loader): """ YAML loader with additional features related to mux """ Loader.add_constructor(u'!include', lambda *_: mux.Control(YAML_INCLUDE)) Loader.add_constructor(u'!using', lambda *_: mux.Control(YAML_USING)) Loader.add_constructor(u'!remove_node', lambda *_: mux.Control(YAML_REMOVE_NODE)) Loader.add_constructor(u'!remove_value', lambda *_: mux.Control(YAML_REMOVE_VALUE)) Loader.add_constructor(u'!filter-only', lambda *_: mux.Control(YAML_FILTER_ONLY)) Loader.add_constructor(u'!filter-out', lambda *_: mux.Control(YAML_FILTER_OUT))
def _create_from_yaml(path, cls_node=mux.MuxTreeNode): """ Create tree structure from yaml stream """ def tree_node_from_values(name, values): """ Create `name` node and add values """ node = cls_node(str(name)) using = '' for value in values: if isinstance(value, cls_node): node.add_child(value) elif isinstance(value[0], mux.Control): if value[0].code == YAML_INCLUDE: # Include file ypath = value[1] if not os.path.isabs(ypath): ypath = os.path.join(os.path.dirname(path), ypath) if not os.path.exists(ypath): raise ValueError("File '%s' included from '%s' does not " "exist." % (ypath, path)) node.merge(_create_from_yaml('/:' + ypath, cls_node)) elif value[0].code == YAML_USING: if using: raise ValueError("!using can be used only once per " "node! (%s:%s)" % (path, name)) using = value[1] if using[0] == '/': using = using[1:] if using[-1] == '/': using = using[:-1] elif value[0].code == YAML_REMOVE_NODE: value[0].value = value[1] # set the name node.ctrl.append(value[0]) # add "blue pill" of death elif value[0].code == YAML_REMOVE_VALUE: value[0].value = value[1] # set the name node.ctrl.append(value[0]) elif value[0].code == YAML_MUX: node.multiplex = True else: node.value[value[0]] = value[1] if using: if name is not '': for name in using.split('/')[::-1]: node = cls_node(name, children=[node]) else: using = using.split('/')[::-1] node.name = using.pop() while True: if not using: break name = using.pop() # 'using' is list pylint: disable=E1101 node = cls_node(name, children=[node]) node = cls_node('', children=[node]) return node def mapping_to_tree_loader(loader, node): """ Maps yaml mapping tag to TreeNode structure """ _value = [] for key_node, value_node in node.value: if key_node.tag.startswith('!'): # reflect tags everywhere key = loader.construct_object(key_node) else: key = loader.construct_python_str(key_node) value = loader.construct_object(value_node) _value.append((key, value)) objects = ListOfNodeObjects() for name, values in _value: if isinstance(values, ListOfNodeObjects): # New node from list objects.append(tree_node_from_values(name, values)) elif values is None: # Empty node objects.append(cls_node(str(name))) else: # Values objects.append(Value((name, values))) return objects def mux_loader(loader, obj): """ Special !mux loader which allows to tag node as 'multiplex = True'. """ if not isinstance(obj, yaml.ScalarNode): objects = mapping_to_tree_loader(loader, obj) else: # This means it's empty node. Don't call mapping_to_tree_loader objects = ListOfNodeObjects() objects.append((mux.Control(YAML_MUX), None)) return objects Loader.add_constructor(u'!include', lambda loader, node: mux.Control(YAML_INCLUDE)) Loader.add_constructor(u'!using', lambda loader, node: mux.Control(YAML_USING)) Loader.add_constructor(u'!remove_node', lambda loader, node: mux.Control(YAML_REMOVE_NODE)) Loader.add_constructor(u'!remove_value', lambda loader, node: mux.Control(YAML_REMOVE_VALUE)) Loader.add_constructor(u'!mux', mux_loader) Loader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, mapping_to_tree_loader) # Parse file name ([$using:]$path) path = __RE_FILE_SPLIT.split(path, 1) if len(path) == 1: path = __RE_FILE_SUBS.sub(':', path[0]) using = ["run"] else: nodes = __RE_FILE_SUBS.sub(':', path[0]).strip('/').split('/') using = [node for node in nodes if node] if not path[0].startswith('/'): # relative path, put into /run using.insert(0, 'run') path = __RE_FILE_SUBS.sub(':', path[1]) # Load the tree with open(path) as stream: loaded_tree = yaml.load(stream, Loader) if loaded_tree is None: return loaded_tree = tree_node_from_values('', loaded_tree) # Add prefix if using: loaded_tree.name = using.pop() while True: if not using: break loaded_tree = cls_node(using.pop(), children=[loaded_tree]) loaded_tree = cls_node('', children=[loaded_tree]) return loaded_tree