def moose_docs_app_syntax(location, hide=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. Inputs: location[str]: The folder to locate Moose executable. hide[dict]: Items to consider "hidden". """ exe = mooseutils.find_moose_executable(location) raw = mooseutils.runExe(exe, '--json') raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = json.loads(raw, object_pairs_hook=collections.OrderedDict) root = SyntaxNode('') for key, value in tree['blocks'].iteritems(): node = SyntaxNode(key, parent=root) syntax_tree_helper(value, node) if hide is not None: for group, hidden in hide.iteritems(): for h in hidden: filter_ = lambda n, hide=h, grp=group: (n.full_name.startswith(hide)) and \ (grp == 'all' or grp in n.groups.keys()) for node in root.findall(filter_=filter_): node.hidden = True return root
def __init__(self, *args, **kwargs): command.CommandExtension.__init__(self, *args, **kwargs) self._app_type = None self._app_syntax = None if not self['disable'] and self['executable'] is not None: LOG.info("Reading MOOSE application syntax.") exe = mooseutils.eval_path(self['executable']) exe = mooseutils.find_moose_executable(exe, show_error=False) if exe is None: LOG.error("Failed to locate a valid executable in %s.", self['executable']) else: try: self._app_syntax = app_syntax( exe, alias=self['alias'], remove=self['remove'], hide=self['hide'], allow_test_objects=self['allow-test-objects']) out = mooseutils.runExe(exe, ['--type']) match = re.search(r'^MooseApp Type:\s+(?P<type>.*?)$', out, flags=re.MULTILINE) if match: self._app_type = match.group("type") else: msg = "Failed to determine application type by running the following:\n" msg += " {} --type".format(exe) LOG.error(msg) except Exception as e: #pylint: disable=broad-except msg = "Failed to load application executable from '%s', " \ "application syntax is being disabled:\n%s" LOG.error(msg, self['executable'], e.message) LOG.info("Building MOOSE class database.") self._database = common.build_class_database(self['includes'], self['inputs']) # Cache the syntax entries, search the tree is very slow if self._app_syntax: self._cache = dict() self._object_cache = dict() self._syntax_cache = dict() for node in anytree.PreOrderIter(self._app_syntax): if not node.removed: self._cache[node.fullpath] = node if node.alias: self._cache[node.alias] = node if isinstance(node, syntax.ObjectNode): self._object_cache[node.fullpath] = node if node.alias: self._object_cache[node.alias] = node elif isinstance(node, syntax.SyntaxNode): self._syntax_cache[node.fullpath] = node if node.alias: self._syntax_cache[node.alias] = node
def __initApplicationSyntax(self): """Initialize the application syntax.""" start = time.time() LOG.info("Reading MOOSE application syntax...") exe = mooseutils.eval_path(self['executable']) exe = mooseutils.find_moose_executable(exe, name=self['app_name'], show_error=False) if exe is None: LOG.error("Failed to locate a valid executable in %s.", self['executable']) else: try: self._app_syntax = app_syntax(exe, alias=self['alias'], remove=self['remove'], hide=self['hide'], allow_test_objects=self['allow-test-objects']) out = mooseutils.runExe(exe, ['--type']) match = re.search(r'^MooseApp Type:\s+(?P<type>.*?)$', out, flags=re.MULTILINE) if match: self._app_type = match.group("type") else: msg = "Failed to determine application type by running the following:\n" msg += " {} --type".format(exe) LOG.error(msg) except Exception as e: msg = "Failed to load application executable from '%s', " \ "application syntax is being disabled:\n%s" self.setActive(False) LOG.error(msg, exe, e) LOG.info("MOOSE application syntax complete [%s sec.]", time.time() - start)
def check(config_file=None, locations=None, generate=None): """ Performs checks and optionally generates stub pages for missing documentation. """ # Read the configuration app_ext = 'MooseDocs.extensions.app_syntax' config = MooseDocs.load_config(config_file) if app_ext not in config: mooseutils.MooseException("The 'check' utility requires the 'app_syntax' extension.") ext_config = config[app_ext] # Run the executable exe = MooseDocs.abspath(ext_config['executable']) if not os.path.exists(exe): raise IOError('The executable does not exist: {}'.format(exe)) else: LOG.debug("Executing %s to extract syntax.", exe) raw = mooseutils.runExe(exe, '--yaml') yaml = mooseutils.MooseYaml(raw) # Populate the syntax for loc in ext_config['locations']: for key, value in loc.iteritems(): if (locations is None) or (key in locations): value['group'] = key syntax = common.MooseApplicationSyntax(yaml, generate=generate, install=ext_config['install'], **value) LOG.info("Checking documentation for '%s'.", key) syntax.check() return None
def execute(self): """ Execute the supplied MOOSE application and return the YAML. """ cache = os.path.join(MooseDocs.TEMP_DIR, 'moosedocs.yaml') exe = self.getConfig('executable') if os.path.exists(cache) and (os.path.getmtime(cache) >= os.path.getmtime(exe)): with open(cache, 'r') as fid: LOG.debug('Reading MooseYaml Pickle: ' + cache) return mooseutils.MooseYaml(pickle.load(fid)) elif not (exe or os.path.exists(exe)): LOG.critical('The executable does not exist: %s', exe) raise Exception('Critical Error') else: LOG.debug("Executing %s to extract syntax.", exe) try: raw = mooseutils.runExe(exe, '--yaml') with open(cache, 'w') as fid: LOG.debug('Writing MooseYaml Pickle: ' + cache) pickle.dump(raw, fid) return mooseutils.MooseYaml(raw) except: LOG.critical('Failed to read YAML file, MOOSE and modules are likely not compiled' ' correctly.') raise
def __initApplicationSyntax(self): """Initialize the application syntax.""" start = time.time() LOG.info("Reading MOOSE application syntax...") exe = mooseutils.eval_path(self['executable']) exe = mooseutils.find_moose_executable(exe, show_error=False) if exe is None: LOG.error("Failed to locate a valid executable in %s.", self['executable']) else: try: self._app_syntax = app_syntax(exe, alias=self['alias'], remove=self['remove'], hide=self['hide'], allow_test_objects=self['allow-test-objects']) out = mooseutils.runExe(exe, ['--type']) match = re.search(r'^MooseApp Type:\s+(?P<type>.*?)$', out, flags=re.MULTILINE) if match: self._app_type = match.group("type") else: msg = "Failed to determine application type by running the following:\n" msg += " {} --type".format(exe) LOG.error(msg) except Exception as e: #pylint: disable=broad-except msg = "Failed to load application executable from '%s', " \ "application syntax is being disabled:\n%s" self.setActive(False) LOG.error(msg, self.get('executable'), e.message) LOG.info("MOOSE application syntax complete [%s sec.]", time.time() - start)
def setUpClass(cls): location = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', 'test')) exe = mooseutils.find_moose_executable(location) raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] cls.json = mooseutils.json_parse(raw)
def app_syntax(exe, remove=None, allow_test_objects=False, hide=None, alias=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. """ try: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = mooseutils.json_parse(raw) except Exception as e: LOG.error("Failed to execute the MOOSE executable '%s':\n%s", exe, e) sys.exit(1) root = SyntaxNode('', None) for key, value in tree['blocks'].items(): node = SyntaxNode(key, root) __syntax_tree_helper(node, value) hidden = set() if isinstance(hide, dict): for value in hide.values(): hidden.update(value) elif isinstance(hide, (list, set)): hidden.update(hide) if hidden: for node in moosetree.iterate(root): if node.fullpath in hidden: node.hidden = True # Remove # TODO: There is multiple iterations over the tree, there should be just none or one removed = set() if isinstance(remove, dict): for value in remove.values(): removed.update(value) elif isinstance(remove, (list, set)): removed.update(remove) if removed: for node in moosetree.iterate(root): if any(n.fullpath == prefix for n in node.path for prefix in removed): node.removed = True if not allow_test_objects: for node in moosetree.iterate(root): if node.groups and all([group.endswith('TestApp') for group in node.groups]): node.removed = True # Alias if alias: for node in moosetree.iterate(root): for k, v in alias.items(): if node.fullpath == k: node.alias = str(v) return root
def __initApplicationSyntax(self): """Initialize the application syntax.""" start = time.time() LOG.info("Reading MOOSE application syntax...") exe = mooseutils.eval_path(self['executable']) exe = mooseutils.find_moose_executable(exe, name=self['app_name'], show_error=False) self._app_exe = exe if exe is None: LOG.error("Failed to locate a valid executable in %s.", self['executable']) else: try: self._app_syntax = moosesyntax.get_moose_syntax_tree( exe, remove=self['remove'], alias=self['alias'], unregister=self['unregister']) out = mooseutils.runExe(exe, ['--type']) match = re.search(r'^MooseApp Type:\s+(?P<type>.*?)$', out, flags=re.MULTILINE) if match: self._app_type = match.group("type") else: msg = "Failed to determine application type by running the following:\n" msg += " {} --type".format(exe) LOG.error(msg) except Exception as e: msg = "Failed to load application executable from '{}' with the following error; " \ "application syntax is being disabled.\n".format(exe) msg += '\n{}\n'.format( mooseutils.colorText(traceback.format_exc(), 'GREY')) msg += "This typically indicates that the application is not producing JSON output " \ "correctly, try running the following:\n" \ " {} --json --allow-test-objects\n".format(exe) self.setActive(False) LOG.error(msg) # Enable test objects by removing the test flag (i.e., don't consider them test objects) if self['allow-test-objects'] and (self._app_syntax is not None): for node in moosetree.iterate(self._app_syntax): node.test = False LOG.info("MOOSE application syntax complete [%s sec.]", time.time() - start)
def __init__(self, *args, **kwargs): command.CommandExtension.__init__(self, *args, **kwargs) self._app_type = None self._app_syntax = None if not self['disable'] and self['executable'] is not None: LOG.info("Reading MOOSE application syntax.") exe = mooseutils.eval_path(self['executable']) exe = mooseutils.find_moose_executable(exe, show_error=False) if exe is None: LOG.error("Failed to locate a valid executable in %s.", self['executable']) else: try: self._app_syntax = app_syntax(exe, alias=self['alias'], remove=self['remove'], hide=self['hide'], allow_test_objects=self['allow-test-objects']) self._app_type = mooseutils.runExe(exe, ['--type']).strip(' \n') except Exception as e: #pylint: disable=broad-except msg = "Failed to load application executable from '%s', " \ "application syntax is being disabled:\n%s" LOG.error(msg, self['executable'], e.message) LOG.info("Building MOOSE class database.") self._database = common.build_class_database(self['includes'], self['inputs']) # Cache the syntax entries, search the tree is very slow if self._app_syntax: self._cache = dict() self._object_cache = dict() self._syntax_cache = dict() for node in anytree.PreOrderIter(self._app_syntax): if not node.removed: self._cache[node.fullpath] = node if node.alias: self._cache[node.alias] = node if isinstance(node, syntax.ObjectNode): self._object_cache[node.fullpath] = node if node.alias: self._object_cache[node.alias] = node elif isinstance(node, syntax.SyntaxNode): self._syntax_cache[node.fullpath] = node if node.alias: self._syntax_cache[node.alias] = node
def setUpClass(cls): # Read the configuration config = MooseDocs.load_config( os.path.join(MooseDocs.MOOSE_DIR, 'docs', 'website.yml')) options = config['MooseDocs.extensions.app_syntax'] # Extract the MOOSE YAML data exe = os.path.join(MooseDocs.MOOSE_DIR, 'modules', 'combined', 'combined-opt') raw = mooseutils.runExe(exe, '--yaml') cls._yaml = mooseutils.MooseYaml(raw) # Extract the 'framework' location options and build the syntax object framework = options['locations'][0]['framework'] framework['group'] = 'framework' framework['install'] = options['install'] framework['hide'] = ['/AuxKernels'] # use to test hide cls._syntax = MooseApplicationSyntax(cls._yaml, **framework)
def __init__(self, *args, **kwargs): command.CommandExtension.__init__(self, *args, **kwargs) self._app_type = None self._app_syntax = None if not self['disable'] and self['executable'] is not None: LOG.info("Reading MOOSE application syntax.") exe = mooseutils.eval_path(self['executable']) exe = mooseutils.find_moose_executable(exe, show_error=False) if exe is None: LOG.error("Failed to locate a valid executable in %s.", self['executable']) else: try: self._app_syntax = app_syntax(exe, alias=self['alias'], remove=self['remove'], hide=self['hide'], allow_test_objects=self['allow-test-objects']) self._app_type = mooseutils.runExe(exe, ['--type']).strip(' \n') except Exception as e: #pylint: disable=broad-except msg = "Failed to load application executable from '%s', " \ "application syntax is being disabled:\n%s" LOG.error(msg, self['executable'], e.message) LOG.info("Building MOOSE class database.") self._database = common.build_class_database(self['includes'], self['inputs']) # Cache the syntax entries, search the tree is very slow if self._app_syntax: self._cache = dict() self._object_cache = dict() self._syntax_cache = dict() for node in anytree.PreOrderIter(self._app_syntax): if not node.removed: self._cache[node.fullpath] = node if isinstance(node, syntax.ObjectNode): self._object_cache[node.fullpath] = node elif isinstance(node, syntax.SyntaxNode): self._syntax_cache[node.fullpath] = node
def execute(self): """ Execute the supplied MOOSE application and return the YAML. """ exe = self.getConfig('executable') if not (exe or os.path.exists(exe)): log.critical('The executable does not exist: {}'.format(exe)) raise Exception('Critical Error') else: log.debug("Executing {} to extract syntax.".format(exe)) try: raw = mooseutils.runExe(exe, '--yaml') return mooseutils.MooseYaml(raw) except: log.critical( 'Failed to read YAML file, MOOSE and modules are likely not compiled correctly.' ) raise Exception('Critical Error')
def generate(config_file='moosedocs.yml', generate=True, locations=None, **kwargs): """ Generates MOOSE system and object markdown files from the source code. Args: config_file[str]: (Default: 'moosedocs.yml') The MooseDocs project configuration file. """ # Read the configuration config = MooseDocs.load_config(config_file) _, ext_config = MooseDocs.get_markdown_extensions(config) ext_config = ext_config['MooseDocs.extensions.MooseMarkdown'] # Run the executable exe = MooseDocs.abspath(ext_config['executable']) if not os.path.exists(exe): raise IOError('The executable does not exist: {}'.format(exe)) else: log.debug("Executing {} to extract syntax.".format(exe)) raw = mooseutils.runExe(exe, '--yaml') yaml = mooseutils.MooseYaml(raw) # Populate the syntax for loc in ext_config['locations']: for key, value in loc.iteritems(): if (locations == None) or (key in locations): value['group'] = key syntax = MooseDocs.MooseApplicationSyntax( yaml, generate=generate, install=ext_config['install'], **value) log.info("Checking documentation for '{}'.".format(key)) syntax.check()
def moose_docs_app_syntax(location, hide=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. Inputs: location[str]: The folder to locate Moose executable. hide[dict]: Items to consider "hidden". """ exe = mooseutils.find_moose_executable(location) if isinstance(exe, int): LOG.error("Unable to locate an executable in the supplied location: %s", location) sys.exit(1) try: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = json.loads(raw, object_pairs_hook=collections.OrderedDict) except Exception: #pylint: disable=broad-except LOG.error("Failed to execute the MOOSE executable: %s", exe) sys.exit(1) root = SyntaxNode('') for key, value in tree['blocks'].iteritems(): node = SyntaxNode(key, parent=root) syntax_tree_helper(value, node) if hide is not None: for node in root.findall(): if ('all' in hide) and (node.full_name in hide['all']): node.hidden = True for group in node.groups: if (group in hide) and (node.full_name in hide[group]): node.hidden = True return root
def get_moose_syntax_tree(exe, remove=None, hide=None, alias=None, unregister=None, allow_test_objects=False): """ Creates a tree structure representing the MooseApp syntax for the given executable using --json. Inputs: ext[str|dict]: The executable to run or the parsed JSON tree structure remove[list|dict]: Syntax to mark as removed. The input data structure can be a single list or a dict of lists. hide[list|dict]: Syntax to mark as hidden. The input data structure can be a single list or a dict of lists. alias[dict]: A dict of alias information; the key is the actual syntax and the value is the alias to be applied (e.g., {'/Kernels/Diffusion':'/Physics/Diffusion'}). unregister[dict]: A dict of classes with duplicate registration information; the key is the "moose_base" name and the value is the syntax from which the object should be removed (e.g., {"Postprocessor":"UserObject/*"}). """ # Create the JSON tree, unless it is provided directly if isinstance(exe, dict): tree = exe else: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = mooseutils.json_parse(raw) # Build the complete syntax tree root = SyntaxNode(None, '') for key, value in tree['blocks'].items(): node = SyntaxNode(root, key) __syntax_tree_helper(node, value) # Build hide/remove sets hidden = __build_set_from_yaml(hide) removed = __build_set_from_yaml(remove) # Initialize dict if not provided alias = alias or dict() unregister = unregister or dict() for key in list(unregister.keys()): if isinstance(unregister[key], dict): unregister.update(unregister.pop(key)) # Apply remove/hide/alias/unregister restrictions for node in moosetree.iterate(root): # Hidden if node.fullpath() in hidden: node.hidden = True # Removed if (node.fullpath() in removed) or ((node.parent is not None) and node.parent.removed): node.removed = True # Remove 'Test' objects if not allowed if (not allow_test_objects) and all( grp.endswith('TestApp') for grp in node.groups()): node.removed = True # Remove unregistered items for base, parent_syntax in unregister.items(): if (node.name == base) and (node.get('action_path') == parent_syntax): node.removed = True if (node.get('moose_base') == base) and (node.get('parent_syntax') == parent_syntax): node.removed = True # Apply alias for name, alt in alias.items(): if node.fullpath() == name: node.alias = str(alt) return root
def app_syntax(exe, remove=None, allow_test_objects=False, hide=None, alias=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. """ common.check_type('exe', exe, str) common.check_type('remove', remove, (type(None), dict, list, set)) common.check_type('hide', hide, (type(None), dict, list, set)) common.check_type('allow_test_objects', allow_test_objects, bool) try: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = json.loads(raw, object_pairs_hook=collections.OrderedDict) raw = mooseutils.runExe(exe, ['--registry-hit']) raw = raw.split('### START REGISTRY DATA ###\n')[1] raw = raw.split('### END REGISTRY DATA ###')[0] reg = mooseutils.hit_load(raw) except Exception as e: #pylint: disable=broad-except LOG.error("Failed to execute the MOOSE executable '%s':\n%s", exe, e.message) sys.exit(1) root = SyntaxNode(None, '') for key, value in tree['blocks'].iteritems(): node = SyntaxNode(root, key) __syntax_tree_helper(node, value) hidden = set() if isinstance(hide, dict): for value in hide.itervalues(): hidden.update(value) elif isinstance(hide, (list, set)): hidden.update(hide) if hidden: for node in anytree.PreOrderIter(root): if node.fullpath in hidden: node.hidden = True #TODO: When the new registration methods are added to the --json dump, this will not be needed. # Add groups from --registry-hit output object_groups = collections.defaultdict(set) action_groups = collections.defaultdict(set) for node in reg.children[0].children[0]: object_groups[node['name']].add(node['label'].replace('App', '')) for node in reg.children[0].children[1]: action_groups[node['name']].add(node['label'].replace('App', '')) action_groups[node['class']].add(node['label'].replace('App', '')) for node in anytree.PreOrderIter(root): if isinstance(node, MooseObjectNode): node._groups.update(object_groups[node.name]) #pylint: disable=protected-access elif isinstance(node, ActionNode): node._groups.update(action_groups[node.name]) #pylint: disable=protected-access for task in node.tasks: node._groups.update(action_groups[task]) #pylint: disable=protected-access # Remove removed = set() if isinstance(remove, dict): for value in remove.itervalues(): removed.update(value) elif isinstance(remove, (list, set)): removed.update(remove) if removed: for node in anytree.PreOrderIter(root): if any(n.fullpath == prefix for n in node.path for prefix in removed): node.removed = True if not allow_test_objects: for node in anytree.PreOrderIter(root): if all([group.endswith('Test') for group in node.groups]): node.removed = True # Alias if alias: for node in anytree.PreOrderIter(root): for k, v in alias.iteritems(): if node.fullpath == k: node.alias = unicode(v) return root
def app_syntax(exe, remove=None, allow_test_objects=False, hide=None, alias=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. """ common.check_type('exe', exe, str) common.check_type('remove', remove, (type(None), dict, list, set)) common.check_type('hide', hide, (type(None), dict, list, set)) common.check_type('allow_test_objects', allow_test_objects, bool) try: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = json.loads(raw, object_pairs_hook=collections.OrderedDict) except Exception as e: #pylint: disable=broad-except LOG.error("Failed to execute the MOOSE executable '%s':\n%s", exe, e.message) sys.exit(1) root = SyntaxNode(None, '') for key, value in tree['blocks'].iteritems(): node = SyntaxNode(root, key) __syntax_tree_helper(node, value) hidden = set() if isinstance(hide, dict): for value in hide.itervalues(): hidden.update(value) elif isinstance(hide, (list, set)): hidden.update(hide) if hidden: for node in anytree.PreOrderIter(root): if node.fullpath in hidden: node.hidden = True # Remove removed = set() if isinstance(remove, dict): for value in remove.itervalues(): removed.update(value) elif isinstance(remove, (list, set)): removed.update(remove) if removed: for node in anytree.PreOrderIter(root): if any(n.fullpath == prefix for n in node.path for prefix in removed): node.removed = True if not allow_test_objects: for node in anytree.PreOrderIter(root): if node.groups and all( [group.endswith('TestApp') for group in node.groups]): node.removed = True # Alias if alias: for node in anytree.PreOrderIter(root): for k, v in alias.iteritems(): if node.fullpath == k: node.alias = unicode(v) return root
def app_syntax(exe, remove=None, allow_test_objects=False, hide=None, alias=None): """ Creates a tree structure representing the MooseApp syntax for the given executable. """ common.check_type('exe', exe, str) common.check_type('remove', remove, (type(None), dict, list, set)) common.check_type('hide', hide, (type(None), dict, list, set)) common.check_type('allow_test_objects', allow_test_objects, bool) try: raw = mooseutils.runExe(exe, ['--json', '--allow-test-objects']) raw = raw.split('**START JSON DATA**\n')[1] raw = raw.split('**END JSON DATA**')[0] tree = json.loads(raw, object_pairs_hook=collections.OrderedDict) except Exception as e: #pylint: disable=broad-except LOG.error("Failed to execute the MOOSE executable '%s':\n%s", exe, e.message) sys.exit(1) root = SyntaxNode('', None) for key, value in tree['blocks'].iteritems(): node = SyntaxNode(key, root) __syntax_tree_helper(node, value) hidden = set() if isinstance(hide, dict): for value in hide.itervalues(): hidden.update(value) elif isinstance(hide, (list, set)): hidden.update(hide) if hidden: for node in anytree.PreOrderIter(root): if node.fullpath in hidden: node.hidden = True # Remove removed = set() if isinstance(remove, dict): for value in remove.itervalues(): removed.update(value) elif isinstance(remove, (list, set)): removed.update(remove) if removed: for node in anytree.PreOrderIter(root): if any(n.fullpath == prefix for n in node.path for prefix in removed): node.removed = True if not allow_test_objects: for node in anytree.PreOrderIter(root): if node.groups and all([group.endswith('TestApp') for group in node.groups]): node.removed = True # Alias if alias: for node in anytree.PreOrderIter(root): for k, v in alias.iteritems(): if node.fullpath == k: node.alias = unicode(v) # Remove <RESIDUAL> for node in anytree.PreOrderIter(root): if node.name.endswith('<RESIDUAL>'): node.alias = node.fullpath node.name = node.name[:-10] return root