From fba7ff2beae9ec492d61b31fd69873e7c66ac738 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 21 Jun 2024 13:49:45 -0700 Subject: [PATCH 01/21] Fixes imports --- CIME/scripts/query_config.py | 44 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 88d2151d1c1..9f156ddea91 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -6,22 +6,24 @@ information will be listed for each. """ -from CIME.Tools.standard_script_setup import * +import os +import sys import re -from CIME.utils import expect, get_cime_default_driver, deprecate_action +import logging +from argparse import RawTextHelpFormatter + +from CIME.Tools.standard_script_setup import * +from CIME import utils from CIME.XML.files import Files from CIME.XML.component import Component from CIME.XML.compsets import Compsets from CIME.XML.grids import Grids from CIME.config import Config - -# from CIME.XML.machines import Machines import CIME.XML.machines -from argparse import RawTextHelpFormatter logger = logging.getLogger(__name__) -customize_path = os.path.join(CIME.utils.get_src_root(), "cime_config", "customize") +customize_path = os.path.join(utils.get_src_root(), "cime_config", "customize") config = Config.load(customize_path) @@ -33,7 +35,7 @@ def query_grids(files, long_output, xml=False): query all grids. """ config_file = files.get_value("GRIDS_SPEC_FILE") - expect( + utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) @@ -52,7 +54,7 @@ def query_machines(files, machine_name="all", xml=False): query machines. Defaule: all """ config_file = files.get_value("MACHINES_SPEC_FILE") - expect( + utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) @@ -90,7 +92,7 @@ def query_compsets(files, name, xml=False): break # If name is not a valid argument - exit with error - expect( + utils.expect( match_found is not None, "Invalid input argument {}, valid input arguments are {}".format( name, components @@ -115,13 +117,13 @@ def print_compset(name, files, all_components=False, xml=False): config_file = files.get_value("COMPSETS_SPEC_FILE", attribute={"component": name}) # only error out if we aren't printing all otherwise exit quitely if not all_components: - expect( + utils.expect( (config_file), "Cannot find any config_component.xml file for {}".format(name), ) # Check that file exists on disk - expect( + utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) @@ -193,12 +195,14 @@ def query_component(name, files, all_components=False, xml=False): break if not all_components and not config_exists: - expect(config_exists, "Cannot find config_file {} on disk".format(config_file)) + utils.expect( + config_exists, "Cannot find config_file {} on disk".format(config_file) + ) elif all_components and not config_exists: print("WARNING: Couldn't find config_file {} on disk".format(config_file)) return # If name is not a valid argument - exit with error - expect( + utils.expect( match_found, "Invalid input argument {}, valid input arguments are {}".format( name, valid_components @@ -206,7 +210,7 @@ def query_component(name, files, all_components=False, xml=False): ) # Check that file exists on disk, if not exit with error - expect( + utils.expect( (config_file), "Cannot find any config_component.xml file for {}".format(name) ) @@ -222,13 +226,13 @@ def parse_command_line(args, description): """ parse command line arguments """ - cime_model = CIME.utils.get_model() + cime_model = utils.get_model() parser = ArgumentParser( description=description, formatter_class=RawTextHelpFormatter ) - CIME.utils.setup_standard_logging_options(parser) + utils.setup_standard_logging_options(parser) valid_components = ["all"] @@ -288,7 +292,7 @@ def parse_command_line(args, description): ) # same for all comp_interfaces config_file = files["mct"].get_value("MACHINES_SPEC_FILE") - expect( + utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) @@ -316,18 +320,18 @@ def parse_command_line(args, description): "--comp_interface", choices=supported_comp_interfaces, # same as config.driver_choices default="mct", - action=deprecate_action(", use --driver argument"), + action=utils.deprecate_action(", use --driver argument"), help="DEPRECATED: Use --driver argument", ) parser.add_argument( "--driver", choices=config.driver_choices, - default=get_cime_default_driver(), + default=utils.get_cime_default_driver(), help="Coupler/Driver interface", ) - args = CIME.utils.parse_args_and_handle_standard_logging_options(args, parser) + args = utils.parse_args_and_handle_standard_logging_options(args, parser) # make sure at least one argument has been passed if not (args.grids or args.compsets or args.components or args.machines): From 5fe5e5ce1af6610ac40789b98ced6711fa9d7c2e Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 21 Jun 2024 15:56:48 -0700 Subject: [PATCH 02/21] Replaces ArgumentParser with default --- CIME/scripts/query_config.py | 47 +++--------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 9f156ddea91..5929a7d116c 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -10,7 +10,7 @@ import sys import re import logging -from argparse import RawTextHelpFormatter +import argparse from CIME.Tools.standard_script_setup import * from CIME import utils @@ -228,8 +228,8 @@ def parse_command_line(args, description): """ cime_model = utils.get_model() - parser = ArgumentParser( - description=description, formatter_class=RawTextHelpFormatter + parser = argparse.ArgumentParser( + description=description, formatter_class=argparse.RawTextHelpFormatter ) utils.setup_standard_logging_options(parser) @@ -365,47 +365,6 @@ def get_components(files): return config_drv.get_valid_model_components() -class ArgumentParser(argparse.ArgumentParser): - """ - we override the error message from ArgumentParser to have a more helpful - message in the case of missing arguments - """ - - def error(self, message): - self.print_usage(sys.stderr) - # missing argument - # TODO: assumes comp_interface='mct' - if "expected one argument" in message: - if "compset" in message: - components = get_compsets(Files(comp_interface="mct")) - self.exit( - 2, - "{}: error: {}\nValid input arguments are {}\n".format( - self.prog, message, components - ), - ) - elif "component" in message: - files = Files(comp_interface="mct") - components = get_components(files) - # Loop through the elements for each component class (in config_files.xml) - valid_components = [] - for comp in components: - string = "CONFIG_{}_FILE".format(comp) - - # determine all components in string - components = files.get_components(string) - for item in components: - valid_components.append(item) - self.exit( - 2, - "{}: error: {}\nValid input arguments are {}\n".format( - self.prog, message, valid_components - ), - ) - # for all other errors - self.exit(2, "{}: error: {}\n".format(self.prog, message)) - - class Machines(CIME.XML.machines.Machines): """ we overide print_values from Machines to add current in machine description From 11edc0253e075b48ed7471f0391855fbeebaefd4 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 21 Jun 2024 16:14:03 -0700 Subject: [PATCH 03/21] Fixes components --- CIME/scripts/query_config.py | 66 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 5929a7d116c..3c7771ff666 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -27,8 +27,6 @@ config = Config.load(customize_path) -supported_comp_interfaces = list(config.driver_choices) - def query_grids(files, long_output, xml=False): """ @@ -221,6 +219,8 @@ def query_component(name, files, all_components=False, xml=False): else: component.print_values() + valid_components + def parse_command_line(args, description): """ @@ -234,51 +234,32 @@ def parse_command_line(args, description): utils.setup_standard_logging_options(parser) - valid_components = ["all"] - parser.add_argument("--xml", action="store_true", help="Output in xml format.") - files = {} - for comp_interface in supported_comp_interfaces: - files[comp_interface] = Files(comp_interface=comp_interface) - components = files[comp_interface].get_components("COMPSETS_SPEC_FILE") - for item in components: - valid_components.append(item) + files = {x: Files(x) for x in list(config.driver_choices)} + + compset_components = get_compset_components(files) + compset_components.extend(["all"]) parser.add_argument( "--compsets", nargs="?", const="all", - choices=valid_components, + choices=sorted(set(compset_components)), help="Query compsets corresponding to the target component for the {} model." " If no component is given, lists compsets defined by all components".format( cime_model ), ) - # Loop through the elements for each component class (in config_files.xml) - valid_components = ["all"] - tmp_comp_interfaces = supported_comp_interfaces - for comp_interface in tmp_comp_interfaces: - try: - components = get_components(files[comp_interface]) - except Exception: - supported_comp_interfaces.remove(comp_interface) - - for comp in components: - string = config.xml_component_key.format(comp) - - # determine all components in string - components = files[comp_interface].get_components(string) - if components: - for item in components: - valid_components.append(item) + components = get_component_components(files) + components.extend(["all"]) parser.add_argument( "--components", nargs="?", const="all", - choices=valid_components, + choices=sorted(set(components)), help="Query component settings corresponding to the target component for {} model." "\nIf the option is empty, then the lists settings defined by all components is output".format( cime_model @@ -318,7 +299,7 @@ def parse_command_line(args, description): parser.add_argument( "--comp_interface", - choices=supported_comp_interfaces, # same as config.driver_choices + choices=config.driver_choices, default="mct", action=utils.deprecate_action(", use --driver argument"), help="DEPRECATED: Use --driver argument", @@ -348,6 +329,31 @@ def parse_command_line(args, description): ) +def get_compset_components(files): + values = [] + + for file in files.values(): + components = file.get_components("COMPSETS_SPEC_FILE") + + values.extend([x for x in components if x is not None]) + + return values + + +def get_component_components(files): + values = [] + + for file in files.values(): + components = get_components(file) + + for comp in components: + components = file.get_components(f"COMP_ROOT_DIR_{comp}") + + values.extend([x for x in components if x is not None]) + + return values + + def get_compsets(files): """ Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE From 8d6aab035c1d64951c26cca7208e64c7ea213101 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 21 Jun 2024 16:42:58 -0700 Subject: [PATCH 04/21] Updates argument parsing --- CIME/scripts/query_config.py | 87 +++++++++++++++++------------------- CIME/utils.py | 2 +- 2 files changed, 41 insertions(+), 48 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 3c7771ff666..6fe5088dc9d 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -28,7 +28,7 @@ config = Config.load(customize_path) -def query_grids(files, long_output, xml=False): +def query_grids(files, long, xml=False, **_): """ query all grids. """ @@ -41,13 +41,13 @@ def query_grids(files, long_output, xml=False): grids = Grids(config_file) if xml: print("{}".format(grids.get_raw_record().decode("UTF-8"))) - elif long_output: - grids.print_values(long_output=long_output) + elif long: + grids.print_values(long_output=long) else: grids.print_values() -def query_machines(files, machine_name="all", xml=False): +def query_machines(files, machines, xml=False, **_): """ query machines. Defaule: all """ @@ -57,22 +57,24 @@ def query_machines(files, machine_name="all", xml=False): "Cannot find config_file {} on disk".format(config_file), ) # Provide a special machine name indicating no need for a machine name - machines = Machines(config_file, machine="Query") + xml_machines = Machines(config_file, machine="Query") if xml: - if machine_name == "all": + if machines == "all": print("{}".format(machines.get_raw_record().decode("UTF-8"))) else: - machines.set_machine(machine_name) + xml_machines.set_machine(machines) print( "{}".format( - machines.get_raw_record(root=machines.machine_node).decode("UTF-8") + xml_machines.get_raw_record(root=machines.machine_node).decode( + "UTF-8" + ) ) ) else: - machines.print_values(machine_name=machine_name) + xml_machines.print_values(machine_name=machines) -def query_compsets(files, name, xml=False): +def query_compsets(files, compsets, xml=False, **_): """ query compset definition give a compset name """ @@ -80,20 +82,20 @@ def query_compsets(files, name, xml=False): components = get_compsets(files) match_found = None all_components = False - if re.search("^all$", name): # print all compsets - match_found = name + if re.search("^all$", compsets): # print all compsets + match_found = compsets all_components = True else: for component in components: - if component == name: - match_found = name + if component == compsets: + match_found = compsets break # If name is not a valid argument - exit with error utils.expect( match_found is not None, "Invalid input argument {}, valid input arguments are {}".format( - name, components + compsets, components ), ) @@ -102,7 +104,7 @@ def query_compsets(files, name, xml=False): # the all_components flag will only print available components print_compset(component, files, all_components=all_components, xml=xml) else: - print_compset(name, files, xml=xml) + print_compset(compsets, files, xml=xml) def print_compset(name, files, all_components=False, xml=False): @@ -142,7 +144,7 @@ def print_compset(name, files, all_components=False, xml=False): compsets.print_values(arg_help=False) -def query_all_components(files, xml=False): +def query_all_components(files, xml=False, **_): """ query all components """ @@ -157,7 +159,7 @@ def query_all_components(files, xml=False): query_component(item, files, all_components=True, xml=xml) -def query_component(name, files, all_components=False, xml=False): +def query_component(name, files, all_components=False, xml=False, **_): """ query a component by name """ @@ -232,8 +234,6 @@ def parse_command_line(args, description): description=description, formatter_class=argparse.RawTextHelpFormatter ) - utils.setup_standard_logging_options(parser) - parser.add_argument("--xml", action="store_true", help="Output in xml format.") files = {x: Files(x) for x in list(config.driver_choices)} @@ -312,21 +312,19 @@ def parse_command_line(args, description): help="Coupler/Driver interface", ) - args = utils.parse_args_and_handle_standard_logging_options(args, parser) + utils.setup_standard_logging_options(parser) + + kwargs = vars(parser.parse_args()) + + utils.configure_logging(**kwargs) # make sure at least one argument has been passed - if not (args.grids or args.compsets or args.components or args.machines): + if not any([kwargs[x] for x in ["grids", "compsets", "components", "machines"]]): parser.print_help(sys.stderr) - return ( - args.grids, - args.compsets, - args.components, - args.machines, - args.long, - args.xml, - files[args.driver], - ) + kwargs["files"] = files[kwargs["driver"]] + + return kwargs def get_compset_components(files): @@ -438,27 +436,22 @@ def print_values(self, machine_name="all"): # pylint: disable=arguments-differ def _main_func(description=None): - """ - main function - """ - grids, compsets, components, machines, long_output, xml, files = parse_command_line( - sys.argv, description - ) + kwargs = parse_command_line(sys.argv, description) - if grids: - query_grids(files, long_output, xml=xml) + if kwargs["grids"]: + query_grids(**kwargs) - if compsets is not None: - query_compsets(files, name=compsets, xml=xml) + if kwargs["compsets"] is not None: + query_compsets(**kwargs) - if components is not None: - if re.search("^all$", components): # print all compsets - query_all_components(files, xml=xml) + if kwargs["components"] is not None: + if re.search("^all$", kwargs["components"]): # print all compsets + query_all_components(**kwargs) else: - query_component(components, files, xml=xml) + query_component(**kwargs) - if machines is not None: - query_machines(files, machine_name=machines, xml=xml) + if kwargs["machines"] is not None: + query_machines(**kwargs) # main entry point diff --git a/CIME/utils.py b/CIME/utils.py index 2949508dbe3..96faa2f22a9 100644 --- a/CIME/utils.py +++ b/CIME/utils.py @@ -1666,7 +1666,7 @@ def filter(self, record): return 1 if record.levelno < self.max_level else 0 -def configure_logging(verbose, debug, silent): +def configure_logging(verbose, debug, silent, **_): root_logger = logging.getLogger() verbose_formatter = logging.Formatter( From e3c348221fd2afdfc8c9a29b66ee767ea670c635 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 21 Jun 2024 16:51:58 -0700 Subject: [PATCH 05/21] Replaces inherited Machine with just a function --- CIME/scripts/query_config.py | 125 +++++++++++++++++------------------ 1 file changed, 60 insertions(+), 65 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 6fe5088dc9d..dc11514c61c 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -18,8 +18,8 @@ from CIME.XML.component import Component from CIME.XML.compsets import Compsets from CIME.XML.grids import Grids +from CIME.XML.machines import Machines from CIME.config import Config -import CIME.XML.machines logger = logging.getLogger(__name__) @@ -71,7 +71,7 @@ def query_machines(files, machines, xml=False, **_): ) ) else: - xml_machines.print_values(machine_name=machines) + print_machine_values(xml_machines, machines) def query_compsets(files, compsets, xml=False, **_): @@ -369,70 +369,65 @@ def get_components(files): return config_drv.get_valid_model_components() -class Machines(CIME.XML.machines.Machines): - """ - we overide print_values from Machines to add current in machine description - """ - - def print_values(self, machine_name="all"): # pylint: disable=arguments-differ - # set flag to look for single machine - if "all" not in machine_name: - single_machine = True - if machine_name == "current": - machine_name = self.probe_machine_name(warn=False) +def print_machine_values( + machine, machine_name="all" +): # pylint: disable=arguments-differ + # set flag to look for single machine + if "all" not in machine_name: + single_machine = True + if machine_name == "current": + machine_name = machine.probe_machine_name(warn=False) + else: + single_machine = False + + # if we can't find the specified machine + if single_machine and machine_name is None: + files = Files() + config_file = files.get_value("MACHINES_SPEC_FILE") + print("Machine is not listed in config file: {}".format(config_file)) + else: # write out machines + if single_machine: + machine_names = [machine_name] else: - single_machine = False - - # if we can't find the specified machine - if single_machine and machine_name is None: - files = Files() - config_file = files.get_value("MACHINES_SPEC_FILE") - print("Machine is not listed in config file: {}".format(config_file)) - else: # write out machines - if single_machine: - machine_names = [machine_name] - else: - machine_names = self.list_available_machines() - print("Machine(s)\n") - for name in machine_names: - self.set_machine(name) - desc = self.text(self.get_child("DESC")) - os_ = self.text(self.get_child("OS")) - compilers = self.text(self.get_child("COMPILERS")) - mpilibnodes = self.get_children("MPILIBS", root=self.machine_node) - mpilibs = [] - for node in mpilibnodes: - mpilibs.extend(self.text(node).split(",")) - # This does not include the possible depedancy of mpilib on compiler - # it simply provides a list of mpilibs available on the machine - mpilibs = list(set(mpilibs)) - max_tasks_per_node = self.text(self.get_child("MAX_TASKS_PER_NODE")) - mpitasks_node = self.get_optional_child( - "MAX_MPITASKS_PER_NODE", root=self.machine_node - ) - max_mpitasks_per_node = ( - self.text(mpitasks_node) if mpitasks_node else max_tasks_per_node - ) - max_gpus_node = self.get_optional_child( - "MAX_GPUS_PER_NODE", root=self.machine_node - ) - max_gpus_per_node = self.text(max_gpus_node) if max_gpus_node else 0 - - current_machine = self.probe_machine_name(warn=False) - name += ( - " (current)" if current_machine and current_machine in name else "" - ) - print(" {} : {} ".format(name, desc)) - print(" os ", os_) - print(" compilers ", compilers) - print(" mpilibs ", mpilibs) - if max_mpitasks_per_node is not None: - print(" pes/node ", max_mpitasks_per_node) - if max_tasks_per_node is not None: - print(" max_tasks/node ", max_tasks_per_node) - if max_gpus_per_node is not None: - print(" max_gpus/node ", max_gpus_per_node) - print("") + machine_names = machine.list_available_machines() + print("Machine(s)\n") + for name in machine_names: + machine.set_machine(name) + desc = machine.text(machine.get_child("DESC")) + os_ = machine.text(machine.get_child("OS")) + compilers = machine.text(machine.get_child("COMPILERS")) + mpilibnodes = machine.get_children("MPILIBS", root=machine.machine_node) + mpilibs = [] + for node in mpilibnodes: + mpilibs.extend(machine.text(node).split(",")) + # This does not include the possible depedancy of mpilib on compiler + # it simply provides a list of mpilibs available on the machine + mpilibs = list(set(mpilibs)) + max_tasks_per_node = machine.text(machine.get_child("MAX_TASKS_PER_NODE")) + mpitasks_node = machine.get_optional_child( + "MAX_MPITASKS_PER_NODE", root=machine.machine_node + ) + max_mpitasks_per_node = ( + machine.text(mpitasks_node) if mpitasks_node else max_tasks_per_node + ) + max_gpus_node = machine.get_optional_child( + "MAX_GPUS_PER_NODE", root=machine.machine_node + ) + max_gpus_per_node = machine.text(max_gpus_node) if max_gpus_node else 0 + + current_machine = machine.probe_machine_name(warn=False) + name += " (current)" if current_machine and current_machine in name else "" + print(" {} : {} ".format(name, desc)) + print(" os ", os_) + print(" compilers ", compilers) + print(" mpilibs ", mpilibs) + if max_mpitasks_per_node is not None: + print(" pes/node ", max_mpitasks_per_node) + if max_tasks_per_node is not None: + print(" max_tasks/node ", max_tasks_per_node) + if max_gpus_per_node is not None: + print(" max_gpus/node ", max_gpus_per_node) + print("") def _main_func(description=None): From 9127b705ce5ad966d79172f831be485bf5cc0cbe Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 21 Jun 2024 16:56:54 -0700 Subject: [PATCH 06/21] Fixes description --- CIME/scripts/query_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index dc11514c61c..fa69ccbda22 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -231,7 +231,7 @@ def parse_command_line(args, description): cime_model = utils.get_model() parser = argparse.ArgumentParser( - description=description, formatter_class=argparse.RawTextHelpFormatter + description=description, formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument("--xml", action="store_true", help="Output in xml format.") @@ -430,7 +430,7 @@ def print_machine_values( print("") -def _main_func(description=None): +def _main_func(description=__doc__): kwargs = parse_command_line(sys.argv, description) if kwargs["grids"]: From 4fbb552ab510c93fbb9a5c9eb03a28e246d03c37 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Tue, 25 Jun 2024 13:51:07 -0700 Subject: [PATCH 07/21] Fixes reading order --- CIME/scripts/query_config.py | 367 +++++++++++++++++------------------ 1 file changed, 183 insertions(+), 184 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index fa69ccbda22..14adcf0ee1e 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -28,50 +28,180 @@ config = Config.load(customize_path) -def query_grids(files, long, xml=False, **_): +def _main_func(description=__doc__): + kwargs = parse_command_line(sys.argv, description) + + if kwargs["grids"]: + query_grids(**kwargs) + + if kwargs["compsets"] is not None: + query_compsets(**kwargs) + + if kwargs["components"] is not None: + if re.search("^all$", kwargs["components"]): # print all compsets + query_all_components(**kwargs) + else: + query_component(**kwargs) + + if kwargs["machines"] is not None: + query_machines(**kwargs) + + +def parse_command_line(args, description): """ - query all grids. + parse command line arguments """ - config_file = files.get_value("GRIDS_SPEC_FILE") + cime_model = utils.get_model() + + parser = argparse.ArgumentParser( + description=description, formatter_class=argparse.RawDescriptionHelpFormatter + ) + + parser.add_argument("--xml", action="store_true", help="Output in xml format.") + + files = {x: Files(x) for x in list(config.driver_choices)} + + compset_components = get_compset_components(files) + compset_components.extend(["all"]) + + parser.add_argument( + "--compsets", + nargs="?", + const="all", + choices=sorted(set(compset_components)), + help="Query compsets corresponding to the target component for the {} model." + " If no component is given, lists compsets defined by all components".format( + cime_model + ), + ) + + components = get_component_components(files) + components.extend(["all"]) + + parser.add_argument( + "--components", + nargs="?", + const="all", + choices=sorted(set(components)), + help="Query component settings corresponding to the target component for {} model." + "\nIf the option is empty, then the lists settings defined by all components is output".format( + cime_model + ), + ) + + parser.add_argument( + "--grids", + action="store_true", + help="Query supported model grids for {} model.".format(cime_model), + ) + # same for all comp_interfaces + config_file = files["mct"].get_value("MACHINES_SPEC_FILE") utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) + machines = Machines(config_file, machine="Query") + machine_names = ["all", "current"] + machine_names.extend(machines.list_available_machines()) - grids = Grids(config_file) - if xml: - print("{}".format(grids.get_raw_record().decode("UTF-8"))) - elif long: - grids.print_values(long_output=long) - else: - grids.print_values() + parser.add_argument( + "--machines", + nargs="?", + const="all", + choices=machine_names, + help="Query supported machines for {} model." + "\nIf option is left empty then all machines are listed," + "\nIf the option is 'current' then only the current machine details are listed.".format( + cime_model + ), + ) + parser.add_argument( + "--long", action="store_true", help="Provide long output for queries" + ) -def query_machines(files, machines, xml=False, **_): + parser.add_argument( + "--comp_interface", + choices=config.driver_choices, + default="mct", + action=utils.deprecate_action(", use --driver argument"), + help="DEPRECATED: Use --driver argument", + ) + + parser.add_argument( + "--driver", + choices=config.driver_choices, + default=utils.get_cime_default_driver(), + help="Coupler/Driver interface", + ) + + utils.setup_standard_logging_options(parser) + + kwargs = vars(parser.parse_args()) + + utils.configure_logging(**kwargs) + + # make sure at least one argument has been passed + if not any([kwargs[x] for x in ["grids", "compsets", "components", "machines"]]): + parser.print_help(sys.stderr) + + kwargs["files"] = files[kwargs["driver"]] + + return kwargs + + +def get_compset_components(files): + values = [] + + for file in files.values(): + components = file.get_components("COMPSETS_SPEC_FILE") + + values.extend([x for x in components if x is not None]) + + return values + + +def get_component_components(files): + values = [] + + for file in files.values(): + components = get_components(file) + + for comp in components: + components = file.get_components(f"COMP_ROOT_DIR_{comp}") + + values.extend([x for x in components if x is not None]) + + return values + + +def get_components(files): """ - query machines. Defaule: all + Determine the valid component classes (e.g. atm) for the driver/cpl + These are then stored in comps_array """ - config_file = files.get_value("MACHINES_SPEC_FILE") + infile = files.get_value("CONFIG_CPL_FILE") + config_drv = Component(infile, "CPL") + return config_drv.get_valid_model_components() + + +def query_grids(files, long, xml=False, **_): + """ + query all grids. + """ + config_file = files.get_value("GRIDS_SPEC_FILE") utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) - # Provide a special machine name indicating no need for a machine name - xml_machines = Machines(config_file, machine="Query") + + grids = Grids(config_file) if xml: - if machines == "all": - print("{}".format(machines.get_raw_record().decode("UTF-8"))) - else: - xml_machines.set_machine(machines) - print( - "{}".format( - xml_machines.get_raw_record(root=machines.machine_node).decode( - "UTF-8" - ) - ) - ) + print("{}".format(grids.get_raw_record().decode("UTF-8"))) + elif long: + grids.print_values(long_output=long) else: - print_machine_values(xml_machines, machines) + grids.print_values() def query_compsets(files, compsets, xml=False, **_): @@ -107,6 +237,13 @@ def query_compsets(files, compsets, xml=False, **_): print_compset(compsets, files, xml=xml) +def get_compsets(files): + """ + Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE + """ + return files.get_components("COMPSETS_SPEC_FILE") + + def print_compset(name, files, all_components=False, xml=False): """ print compsets associated with the component name, but if all_components is true only @@ -224,149 +361,31 @@ def query_component(name, files, all_components=False, xml=False, **_): valid_components -def parse_command_line(args, description): +def query_machines(files, machines, xml=False, **_): """ - parse command line arguments + query machines. Defaule: all """ - cime_model = utils.get_model() - - parser = argparse.ArgumentParser( - description=description, formatter_class=argparse.RawDescriptionHelpFormatter - ) - - parser.add_argument("--xml", action="store_true", help="Output in xml format.") - - files = {x: Files(x) for x in list(config.driver_choices)} - - compset_components = get_compset_components(files) - compset_components.extend(["all"]) - - parser.add_argument( - "--compsets", - nargs="?", - const="all", - choices=sorted(set(compset_components)), - help="Query compsets corresponding to the target component for the {} model." - " If no component is given, lists compsets defined by all components".format( - cime_model - ), - ) - - components = get_component_components(files) - components.extend(["all"]) - - parser.add_argument( - "--components", - nargs="?", - const="all", - choices=sorted(set(components)), - help="Query component settings corresponding to the target component for {} model." - "\nIf the option is empty, then the lists settings defined by all components is output".format( - cime_model - ), - ) - - parser.add_argument( - "--grids", - action="store_true", - help="Query supported model grids for {} model.".format(cime_model), - ) - # same for all comp_interfaces - config_file = files["mct"].get_value("MACHINES_SPEC_FILE") + config_file = files.get_value("MACHINES_SPEC_FILE") utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) - machines = Machines(config_file, machine="Query") - machine_names = ["all", "current"] - machine_names.extend(machines.list_available_machines()) - - parser.add_argument( - "--machines", - nargs="?", - const="all", - choices=machine_names, - help="Query supported machines for {} model." - "\nIf option is left empty then all machines are listed," - "\nIf the option is 'current' then only the current machine details are listed.".format( - cime_model - ), - ) - - parser.add_argument( - "--long", action="store_true", help="Provide long output for queries" - ) - - parser.add_argument( - "--comp_interface", - choices=config.driver_choices, - default="mct", - action=utils.deprecate_action(", use --driver argument"), - help="DEPRECATED: Use --driver argument", - ) - - parser.add_argument( - "--driver", - choices=config.driver_choices, - default=utils.get_cime_default_driver(), - help="Coupler/Driver interface", - ) - - utils.setup_standard_logging_options(parser) - - kwargs = vars(parser.parse_args()) - - utils.configure_logging(**kwargs) - - # make sure at least one argument has been passed - if not any([kwargs[x] for x in ["grids", "compsets", "components", "machines"]]): - parser.print_help(sys.stderr) - - kwargs["files"] = files[kwargs["driver"]] - - return kwargs - - -def get_compset_components(files): - values = [] - - for file in files.values(): - components = file.get_components("COMPSETS_SPEC_FILE") - - values.extend([x for x in components if x is not None]) - - return values - - -def get_component_components(files): - values = [] - - for file in files.values(): - components = get_components(file) - - for comp in components: - components = file.get_components(f"COMP_ROOT_DIR_{comp}") - - values.extend([x for x in components if x is not None]) - - return values - - -def get_compsets(files): - """ - Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE - """ - return files.get_components("COMPSETS_SPEC_FILE") - - -def get_components(files): - """ - Determine the valid component classes (e.g. atm) for the driver/cpl - These are then stored in comps_array - """ - infile = files.get_value("CONFIG_CPL_FILE") - config_drv = Component(infile, "CPL") - return config_drv.get_valid_model_components() + # Provide a special machine name indicating no need for a machine name + xml_machines = Machines(config_file, machine="Query") + if xml: + if machines == "all": + print("{}".format(machines.get_raw_record().decode("UTF-8"))) + else: + xml_machines.set_machine(machines) + print( + "{}".format( + xml_machines.get_raw_record(root=machines.machine_node).decode( + "UTF-8" + ) + ) + ) + else: + print_machine_values(xml_machines, machines) def print_machine_values( @@ -430,25 +449,5 @@ def print_machine_values( print("") -def _main_func(description=__doc__): - kwargs = parse_command_line(sys.argv, description) - - if kwargs["grids"]: - query_grids(**kwargs) - - if kwargs["compsets"] is not None: - query_compsets(**kwargs) - - if kwargs["components"] is not None: - if re.search("^all$", kwargs["components"]): # print all compsets - query_all_components(**kwargs) - else: - query_component(**kwargs) - - if kwargs["machines"] is not None: - query_machines(**kwargs) - - -# main entry point if __name__ == "__main__": _main_func(__doc__) From aa24ab9f512917fdc55ee31a4103b6711e20637c Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Tue, 25 Jun 2024 13:54:37 -0700 Subject: [PATCH 08/21] Fixes black formatting --- CIME/scripts/query_config.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 14adcf0ee1e..17dc19ef050 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -29,7 +29,7 @@ def _main_func(description=__doc__): - kwargs = parse_command_line(sys.argv, description) + kwargs = parse_command_line(description) if kwargs["grids"]: query_grids(**kwargs) @@ -47,7 +47,7 @@ def _main_func(description=__doc__): query_machines(**kwargs) -def parse_command_line(args, description): +def parse_command_line(description): """ parse command line arguments """ @@ -358,8 +358,6 @@ def query_component(name, files, all_components=False, xml=False, **_): else: component.print_values() - valid_components - def query_machines(files, machines, xml=False, **_): """ From 7440bbb7981723bfc896cb5a4d5a0f751805f2c5 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Thu, 27 Jun 2024 22:02:42 -0700 Subject: [PATCH 09/21] Adds longname to grid print_values --- CIME/XML/grids.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/CIME/XML/grids.py b/CIME/XML/grids.py index 7b274587323..d5df45035dd 100644 --- a/CIME/XML/grids.py +++ b/CIME/XML/grids.py @@ -121,7 +121,7 @@ def _valid_lname(self, name): break return valid - def _read_config_grids(self, name, compset, atmnlev, lndnlev): + def _read_config_grids(self, name, compset=None, atmnlev=None, lndnlev=None): """ read config_grids.xml with version 2.0 schema @@ -136,10 +136,13 @@ def _read_config_grids(self, name, compset, atmnlev, lndnlev): grid_defaults_node = self.get_child("model_grid_defaults", root=grids_node) for grid_node in self.get_children("grid", root=grid_defaults_node): name_attrib = self.get(grid_node, "name") - compset_attrib = self.get(grid_node, "compset") - compset_match = re.search(compset_attrib, compset) - if compset_match is not None: - model_grid[name_attrib] = self.text(grid_node) + if compset is None: + model_grid[name_attrib] = "null" + else: + compset_attrib = self.get(grid_node, "compset") + compset_match = re.search(compset_attrib, compset) + if compset_match is not None: + model_grid[name_attrib] = self.text(grid_node) # (2)loop over all of the "model grid" nodes and determine is there an alias match with the # input grid name - if there is an alias match determine if the "compset" and "not_compset" @@ -616,6 +619,8 @@ def print_values(self, long_output=None): grid_nodes = self.get_children("grid", root=model_grid_node) grids = "" gridnames = [] + lname = self._read_config_grids(alias, compset) + logger.info("\n{:<7}longname: {}".format(" ", lname)) for grid_node in grid_nodes: gridnames.append(self.text(grid_node)) grids += self.get(grid_node, "name") + ":" + self.text(grid_node) + " " @@ -627,7 +632,14 @@ def print_values(self, long_output=None): gridnames = set(gridnames) for gridname in gridnames: if gridname != "null": - logger.info(" {}".format(domains[gridname])) + try: + logger.info(" {}".format(domains[gridname])) + except KeyError: + logger.info( + " Could not provide domains for gridname {!r}".format( + gridname + ) + ) # ------------------------------------------------------------------------ From 014dac79e51498fec8e9ef1bab3fb3527afcee07 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Thu, 27 Jun 2024 22:42:03 -0700 Subject: [PATCH 10/21] Fixes query single component --- CIME/scripts/query_config.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 17dc19ef050..5a87d3744cf 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -296,35 +296,35 @@ def query_all_components(files, xml=False, **_): query_component(item, files, all_components=True, xml=xml) -def query_component(name, files, all_components=False, xml=False, **_): +def query_component(components, files, all_components=False, xml=False, **_): """ query a component by name """ # Determine the valid component classes (e.g. atm) for the driver/cpl # These are then stored in comps_array - components = get_components(files) + classes = get_components(files) # Loop through the elements for each component class (in config_files.xml) # and see if there is a match for the the target component in the component attribute match_found = False valid_components = [] config_exists = False - for comp in components: + for comp in classes: string = "CONFIG_{}_FILE".format(comp) config_file = None # determine all components in string root_dir_node_name = "COMP_ROOT_DIR_{}".format(comp) - components = files.get_components(root_dir_node_name) - if components is None: - components = files.get_components(string) - for item in components: + classes = files.get_components(root_dir_node_name) + if classes is None: + classes = files.get_components(string) + for item in classes: valid_components.append(item) logger.debug("{}: valid_components {}".format(comp, valid_components)) # determine if config_file is on disk - if name is None: + if components is None: config_file = files.get_value(string) - elif name in valid_components: - config_file = files.get_value(string, attribute={"component": name}) + elif components in valid_components: + config_file = files.get_value(string, attribute={"component": components}) logger.debug("query {}".format(config_file)) if config_file is not None: match_found = True @@ -342,13 +342,14 @@ def query_component(name, files, all_components=False, xml=False, **_): utils.expect( match_found, "Invalid input argument {}, valid input arguments are {}".format( - name, valid_components + components, valid_components ), ) # Check that file exists on disk, if not exit with error utils.expect( - (config_file), "Cannot find any config_component.xml file for {}".format(name) + (config_file), + "Cannot find any config_component.xml file for {}".format(components), ) # determine component xml content From 001f9fa604d04964e2ef2c7e764df715652ec606 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Thu, 27 Jun 2024 22:50:31 -0700 Subject: [PATCH 11/21] Fixes description text --- CIME/XML/component.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/XML/component.py b/CIME/XML/component.py index b3834a17c91..abd09c86fd0 100644 --- a/CIME/XML/component.py +++ b/CIME/XML/component.py @@ -327,7 +327,7 @@ def print_values(self): for entry in entries: name = self.get(entry, "id") text = self.text(self.get_child("desc", root=entry)) - logger.info(" {:20s} : {}".format(name, text.encode("utf-8"))) + logger.info(" {:20s} : {}".format(name, text)) def return_values(self): """ From 11e75f2ebe1a8c6d43672a48b334315d34b1b47e Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 11:13:12 -0700 Subject: [PATCH 12/21] Adds argument grouping --- CIME/scripts/query_config.py | 69 ++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 5a87d3744cf..ad236dac390 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -53,18 +53,31 @@ def parse_command_line(description): """ cime_model = utils.get_model() - parser = argparse.ArgumentParser( - description=description, formatter_class=argparse.RawDescriptionHelpFormatter - ) - - parser.add_argument("--xml", action="store_true", help="Output in xml format.") - files = {x: Files(x) for x in list(config.driver_choices)} compset_components = get_compset_components(files) compset_components.extend(["all"]) - parser.add_argument( + components = get_component_components(files) + components.extend(["all"]) + + # same for all comp_interfaces + config_file = files["mct"].get_value("MACHINES_SPEC_FILE") + utils.expect( + os.path.isfile(config_file), + "Cannot find config_file {} on disk".format(config_file), + ) + machines = Machines(config_file, machine="Query") + machine_names = ["all", "current"] + machine_names.extend(machines.list_available_machines()) + + parser = argparse.ArgumentParser( + description=description, formatter_class=argparse.RawDescriptionHelpFormatter + ) + + config_group = parser.add_argument_group("Config options") + + config_group.add_argument( "--compsets", nargs="?", const="all", @@ -75,10 +88,7 @@ def parse_command_line(description): ), ) - components = get_component_components(files) - components.extend(["all"]) - - parser.add_argument( + config_group.add_argument( "--components", nargs="?", const="all", @@ -89,22 +99,13 @@ def parse_command_line(description): ), ) - parser.add_argument( + config_group.add_argument( "--grids", action="store_true", help="Query supported model grids for {} model.".format(cime_model), ) - # same for all comp_interfaces - config_file = files["mct"].get_value("MACHINES_SPEC_FILE") - utils.expect( - os.path.isfile(config_file), - "Cannot find config_file {} on disk".format(config_file), - ) - machines = Machines(config_file, machine="Query") - machine_names = ["all", "current"] - machine_names.extend(machines.list_available_machines()) - parser.add_argument( + config_group.add_argument( "--machines", nargs="?", const="all", @@ -116,25 +117,33 @@ def parse_command_line(description): ), ) - parser.add_argument( + output_group = parser.add_argument_group("Output options") + + output_group.add_argument( "--long", action="store_true", help="Provide long output for queries" ) - parser.add_argument( - "--comp_interface", - choices=config.driver_choices, - default="mct", - action=utils.deprecate_action(", use --driver argument"), - help="DEPRECATED: Use --driver argument", + output_group.add_argument( + "--xml", action="store_true", help="Output in xml format." ) - parser.add_argument( + filter_group = parser.add_argument_group("Filter options") + + filter_group.add_argument( "--driver", choices=config.driver_choices, default=utils.get_cime_default_driver(), help="Coupler/Driver interface", ) + filter_group.add_argument( + "--comp_interface", + choices=config.driver_choices, + default="mct", + action=utils.deprecate_action(", use --driver argument"), + help="DEPRECATED: Use --driver argument", + ) + utils.setup_standard_logging_options(parser) kwargs = vars(parser.parse_args()) From 78bb61c3106ba03cab5bc37049c2dd355bebb701 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 11:58:31 -0700 Subject: [PATCH 13/21] Updates help text --- CIME/scripts/query_config.py | 46 +++++++++--------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index ad236dac390..47082f20bff 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -48,11 +48,6 @@ def _main_func(description=__doc__): def parse_command_line(description): - """ - parse command line arguments - """ - cime_model = utils.get_model() - files = {x: Files(x) for x in list(config.driver_choices)} compset_components = get_compset_components(files) @@ -82,10 +77,7 @@ def parse_command_line(description): nargs="?", const="all", choices=sorted(set(compset_components)), - help="Query compsets corresponding to the target component for the {} model." - " If no component is given, lists compsets defined by all components".format( - cime_model - ), + help="Query compsets for active component. If no value is passed, compsets for all active components will be printed.", ) config_group.add_argument( @@ -93,16 +85,11 @@ def parse_command_line(description): nargs="?", const="all", choices=sorted(set(components)), - help="Query component settings corresponding to the target component for {} model." - "\nIf the option is empty, then the lists settings defined by all components is output".format( - cime_model - ), + help="Query settings for component. If not value is passed, settings for all components will be printed.", ) config_group.add_argument( - "--grids", - action="store_true", - help="Query supported model grids for {} model.".format(cime_model), + "--grids", action="store_true", help="Query grids for model." ) config_group.add_argument( @@ -110,30 +97,26 @@ def parse_command_line(description): nargs="?", const="all", choices=machine_names, - help="Query supported machines for {} model." - "\nIf option is left empty then all machines are listed," - "\nIf the option is 'current' then only the current machine details are listed.".format( - cime_model - ), + help="Query machines for model. If not value is passed, all machines will be printed.", ) output_group = parser.add_argument_group("Output options") output_group.add_argument( - "--long", action="store_true", help="Provide long output for queries" + "--long", action="store_true", help="Print extended output for queries." ) - output_group.add_argument( - "--xml", action="store_true", help="Output in xml format." - ) + output_group.add_argument("--xml", action="store_true", help="Print output in xml.") filter_group = parser.add_argument_group("Filter options") + default_driver = config.driver_default + filter_group.add_argument( "--driver", choices=config.driver_choices, - default=utils.get_cime_default_driver(), - help="Coupler/Driver interface", + default=default_driver, + help=f"Filter by driver, defaults to {default_driver!r}.", ) filter_group.add_argument( @@ -218,7 +201,7 @@ def query_compsets(files, compsets, xml=False, **_): query compset definition give a compset name """ # Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE - components = get_compsets(files) + components = files.get_components("COMPSETS_SPEC_FILE") match_found = None all_components = False if re.search("^all$", compsets): # print all compsets @@ -246,13 +229,6 @@ def query_compsets(files, compsets, xml=False, **_): print_compset(compsets, files, xml=xml) -def get_compsets(files): - """ - Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE - """ - return files.get_components("COMPSETS_SPEC_FILE") - - def print_compset(name, files, all_components=False, xml=False): """ print compsets associated with the component name, but if all_components is true only From 525c83452e37287e3c70e3bed3710cb389122300 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 12:04:05 -0700 Subject: [PATCH 14/21] Removes useless docstrings --- CIME/scripts/query_config.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 47082f20bff..aa15692535a 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -178,9 +178,6 @@ def get_components(files): def query_grids(files, long, xml=False, **_): - """ - query all grids. - """ config_file = files.get_value("GRIDS_SPEC_FILE") utils.expect( os.path.isfile(config_file), @@ -197,9 +194,6 @@ def query_grids(files, long, xml=False, **_): def query_compsets(files, compsets, xml=False, **_): - """ - query compset definition give a compset name - """ # Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE components = files.get_components("COMPSETS_SPEC_FILE") match_found = None @@ -267,9 +261,6 @@ def print_compset(name, files, all_components=False, xml=False): def query_all_components(files, xml=False, **_): - """ - query all components - """ components = get_components(files) # Loop through the elements for each component class (in config_files.xml) for comp in components: @@ -282,9 +273,6 @@ def query_all_components(files, xml=False, **_): def query_component(components, files, all_components=False, xml=False, **_): - """ - query a component by name - """ # Determine the valid component classes (e.g. atm) for the driver/cpl # These are then stored in comps_array classes = get_components(files) @@ -346,9 +334,6 @@ def query_component(components, files, all_components=False, xml=False, **_): def query_machines(files, machines, xml=False, **_): - """ - query machines. Defaule: all - """ config_file = files.get_value("MACHINES_SPEC_FILE") utils.expect( os.path.isfile(config_file), From 85f8a4a3b9dc3e3ee2af75560f56792bebf5a51f Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 18:57:20 -0700 Subject: [PATCH 15/21] Adds tests for Grids --- CIME/tests/test_unit_xml_grids.py | 141 ++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 CIME/tests/test_unit_xml_grids.py diff --git a/CIME/tests/test_unit_xml_grids.py b/CIME/tests/test_unit_xml_grids.py new file mode 100644 index 00000000000..90379ca3147 --- /dev/null +++ b/CIME/tests/test_unit_xml_grids.py @@ -0,0 +1,141 @@ +import os +import io +import unittest +import tempfile +from contextlib import contextmanager +from pathlib import Path +from unittest import mock + +from CIME.utils import CIMEError +from CIME.XML.grids import Grids + + +TEST_CONFIG = """ + + + null + null + null + null + rx1 + r05 + r05 + rx1 + r05 + r05 + null + null + null + null + null + + + + T62 + T62 + gx3v7 + rx1 + null + null + gx3v7 + + + 0.47x0.63 + 0.47x0.63 + gx1v6 + r05 + null + null + gx1v6 + + + 0.23x0.31 + 0.23x0.31 + gx1v6 + r05 + null + null + gx1v6 + + + T31 + T31 + gx3v7 + rx1 + null + null + gx3v7 + + + 0.9x1.25 + 0.9x1.25 + gx1v6 + r05 + null + null + gx1v6 + + + 1.9x2.5 + 1.9x2.5 + gx1v6 + r05 + null + null + + +""" + + +def write_config_grids(tempdir, config): + config_grids_path = os.path.join(tempdir, "config_grids.xml") + + with open(config_grids_path, "w") as fd: + fd.write(TEST_CONFIG) + + return config_grids_path + + +class TestXMLGrids(unittest.TestCase): + def test_read_config_grids(self): + with tempfile.TemporaryDirectory() as tempdir: + config_grids_path = write_config_grids(tempdir, TEST_CONFIG) + + grids = Grids(config_grids_path) + + lname = grids._read_config_grids("T62_g37", "DATM") + + assert lname == "a%T62_l%T62_oi%gx3v7_r%rx1_g%null_w%null_z%null_m%gx3v7" + + with self.assertRaisesRegex(CIMEError, "ERROR: grid alias T62_g37 not valid for compset SCREAM"): + grids._read_config_grids("T62_g37", "SCREAM") + + lname = grids._read_config_grids("f02_g16", "DATM") + + assert lname == "a%0.23x0.31_l%0.23x0.31_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + + lname = grids._read_config_grids("f05_g16", "SCREAM") + + assert lname == "a%0.47x0.63_l%0.47x0.63_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + + with self.assertRaisesRegex(CIMEError, "ERROR: grid alias f05_g16 not valid for compset DATM"): + grids._read_config_grids("f05_g16", "DATM") + + lname = grids._read_config_grids("T31_g37_rx1", "_DROF") + + assert lname == "a%T31_l%T31_oi%gx3v7_r%rx1_g%null_w%null_z%null_m%gx3v7" + + lname = grids._read_config_grids("f09_g16", "DATM3TEST") + + assert lname == "a%0.9x1.25_l%0.9x1.25_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + + with self.assertRaisesRegex(CIMEError, "ERROR: grid alias f09_g16 not valid for compset DATM2TEST"): + grids._read_config_grids("f09_g16", "DATM2TEST") + + lname = grids._read_config_grids("f19_g16", "DATM") + + assert lname == "a%1.9x2.5_l%1.9x2.5_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + + lname = grids._read_config_grids("f19_g16", "DATM", atmnlev="2", lndnlev="4") + + assert lname == "a%1.9x2.5z2_l%1.9x2.5z4_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" From 5bead12e496877b33530c1c83602afe5cf134666 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 18:57:59 -0700 Subject: [PATCH 16/21] Refactors method to get grid longname from xml nodes --- CIME/XML/grids.py | 56 +++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/CIME/XML/grids.py b/CIME/XML/grids.py index d5df45035dd..d91ba1796d9 100644 --- a/CIME/XML/grids.py +++ b/CIME/XML/grids.py @@ -121,28 +121,13 @@ def _valid_lname(self, name): break return valid - def _read_config_grids(self, name, compset=None, atmnlev=None, lndnlev=None): + def _read_config_grids(self, name, compset, atmnlev=None, lndnlev=None): """ read config_grids.xml with version 2.0 schema Returns a grid long name given the alias ('name' argument) """ - model_grid = {} - for comp_gridname in self._comp_gridnames: - model_grid[comp_gridname] = None - - # (1) set array of component grid defaults that match current compset grids_node = self.get_child("grids") - grid_defaults_node = self.get_child("model_grid_defaults", root=grids_node) - for grid_node in self.get_children("grid", root=grid_defaults_node): - name_attrib = self.get(grid_node, "name") - if compset is None: - model_grid[name_attrib] = "null" - else: - compset_attrib = self.get(grid_node, "compset") - compset_match = re.search(compset_attrib, compset) - if compset_match is not None: - model_grid[name_attrib] = self.text(grid_node) # (2)loop over all of the "model grid" nodes and determine is there an alias match with the # input grid name - if there is an alias match determine if the "compset" and "not_compset" @@ -203,37 +188,65 @@ def _read_config_grids(self, name, compset=None, atmnlev=None, lndnlev=None): foundcompset, "grid alias {} not valid for compset {}".format(name, compset) ) - # for the match - find all of the component grid settings + return self.get_grid_longname( + grids_node, model_gridnode, compset, atmnlev, lndnlev + ) + + def get_grid_longname( + self, grids_node, model_gridnode, compset=None, atmnlev=None, lndnlev=None + ): + model_grid = {} + + for comp_gridname in self._comp_gridnames: + model_grid[comp_gridname] = None + + if compset is not None: + grid_defaults_node = self.get_child("model_grid_defaults", root=grids_node) + + for grid_node in self.get_children("grid", root=grid_defaults_node): + name_attrib = self.get(grid_node, "name") + compset_attrib = self.get(grid_node, "compset") + compset_match = re.search(compset_attrib, compset) + + if compset_match is not None: + model_grid[name_attrib] = self.text(grid_node) + grid_nodes = self.get_children("grid", root=model_gridnode) + for grid_node in grid_nodes: name = self.get(grid_node, "name") value = self.text(grid_node) + if model_grid[name] != "null": model_grid[name] = value + mask_node = self.get_optional_child("mask", root=model_gridnode) + if mask_node is not None: model_grid["mask"] = self.text(mask_node) else: model_grid["mask"] = model_grid["ocnice"] lname = "" + for component_gridname in self._comp_gridnames: if lname: lname = lname + "_" + grid_prefix[component_gridname] else: lname = grid_prefix[component_gridname] + if model_grid[component_gridname] is not None: lname += model_grid[component_gridname] + if component_gridname == "atm" and atmnlev is not None: if not ("a{:n}ull" in lname): lname += "z" + atmnlev - elif component_gridname == "lnd" and lndnlev is not None: if not ("l{:n}ull" in lname): lname += "z" + lndnlev - else: lname += "null" + return lname def _get_domains(self, component_grids, atmlevregex, lndlevregex, driver): @@ -602,7 +615,8 @@ def print_values(self, long_output=None): desc, files ) - model_grid_nodes = self.get_children("model_grid", root=self.get_child("grids")) + grids_node = self.get_child("grids") + model_grid_nodes = self.get_children("model_grid", root=grids_node) for model_grid_node in model_grid_nodes: alias = self.get(model_grid_node, "alias") compset = self.get(model_grid_node, "compset") @@ -619,7 +633,7 @@ def print_values(self, long_output=None): grid_nodes = self.get_children("grid", root=model_grid_node) grids = "" gridnames = [] - lname = self._read_config_grids(alias, compset) + lname = self.get_grid_longname(grids_node, model_grid_node) logger.info("\n{:<7}longname: {}".format(" ", lname)) for grid_node in grid_nodes: gridnames.append(self.text(grid_node)) From b37e524c6603fd60c21f775ff9aa7870dc76f6db Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 19:26:55 -0700 Subject: [PATCH 17/21] Refactors query_all_components --- CIME/scripts/query_config.py | 64 +++++++++++++++---------------- CIME/tests/test_unit_xml_grids.py | 41 +++++++++++++++----- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index aa15692535a..0e4b02d9efb 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -38,10 +38,7 @@ def _main_func(description=__doc__): query_compsets(**kwargs) if kwargs["components"] is not None: - if re.search("^all$", kwargs["components"]): # print all compsets - query_all_components(**kwargs) - else: - query_component(**kwargs) + query_component_settings(**kwargs) if kwargs["machines"] is not None: query_machines(**kwargs) @@ -157,23 +154,21 @@ def get_component_components(files): values = [] for file in files.values(): - components = get_components(file) + classes = get_component_classes(file) - for comp in components: - components = file.get_components(f"COMP_ROOT_DIR_{comp}") + for c in classes: + components = file.get_components(f"COMP_ROOT_DIR_{c}") values.extend([x for x in components if x is not None]) return values -def get_components(files): - """ - Determine the valid component classes (e.g. atm) for the driver/cpl - These are then stored in comps_array - """ +def get_component_classes(files): infile = files.get_value("CONFIG_CPL_FILE") + config_drv = Component(infile, "CPL") + return config_drv.get_valid_model_components() @@ -260,22 +255,27 @@ def print_compset(name, files, all_components=False, xml=False): compsets.print_values(arg_help=False) -def query_all_components(files, xml=False, **_): - components = get_components(files) - # Loop through the elements for each component class (in config_files.xml) - for comp in components: - string = "CONFIG_{}_FILE".format(comp) +def query_component_settings(components, files, xml=False, **_): + classes = get_component_classes(files) - # determine all components in string - components = files.get_components(string) - for item in components: - query_component(item, files, all_components=True, xml=xml) + if components == "all": + # Loop through the elements for each component class (in config_files.xml) + for comp in classes: + string = "CONFIG_{}_FILE".format(comp) + + # determine all components in string + components = files.get_components(string) + + for item in components: + _query_component_settings(item, files, all_components=True, xml=xml) + else: + _query_component_settings(components, files, xml=xml) -def query_component(components, files, all_components=False, xml=False, **_): +def _query_component_settings(component, files, all_components=False, xml=False, **_): # Determine the valid component classes (e.g. atm) for the driver/cpl # These are then stored in comps_array - classes = get_components(files) + classes = get_component_classes(files) # Loop through the elements for each component class (in config_files.xml) # and see if there is a match for the the target component in the component attribute @@ -287,17 +287,17 @@ def query_component(components, files, all_components=False, xml=False, **_): config_file = None # determine all components in string root_dir_node_name = "COMP_ROOT_DIR_{}".format(comp) - classes = files.get_components(root_dir_node_name) - if classes is None: - classes = files.get_components(string) - for item in classes: + _components = files.get_components(root_dir_node_name) + if _components is None: + _components = files.get_components(string) + for item in _components: valid_components.append(item) logger.debug("{}: valid_components {}".format(comp, valid_components)) # determine if config_file is on disk - if components is None: + if component is None: config_file = files.get_value(string) - elif components in valid_components: - config_file = files.get_value(string, attribute={"component": components}) + elif component in valid_components: + config_file = files.get_value(string, attribute={"component": component}) logger.debug("query {}".format(config_file)) if config_file is not None: match_found = True @@ -315,14 +315,14 @@ def query_component(components, files, all_components=False, xml=False, **_): utils.expect( match_found, "Invalid input argument {}, valid input arguments are {}".format( - components, valid_components + component, valid_components ), ) # Check that file exists on disk, if not exit with error utils.expect( (config_file), - "Cannot find any config_component.xml file for {}".format(components), + "Cannot find any config_component.xml file for {}".format(component), ) # determine component xml content diff --git a/CIME/tests/test_unit_xml_grids.py b/CIME/tests/test_unit_xml_grids.py index 90379ca3147..77619e5f78c 100644 --- a/CIME/tests/test_unit_xml_grids.py +++ b/CIME/tests/test_unit_xml_grids.py @@ -107,18 +107,28 @@ def test_read_config_grids(self): assert lname == "a%T62_l%T62_oi%gx3v7_r%rx1_g%null_w%null_z%null_m%gx3v7" - with self.assertRaisesRegex(CIMEError, "ERROR: grid alias T62_g37 not valid for compset SCREAM"): + with self.assertRaisesRegex( + CIMEError, "ERROR: grid alias T62_g37 not valid for compset SCREAM" + ): grids._read_config_grids("T62_g37", "SCREAM") lname = grids._read_config_grids("f02_g16", "DATM") - assert lname == "a%0.23x0.31_l%0.23x0.31_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + assert ( + lname + == "a%0.23x0.31_l%0.23x0.31_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + ) lname = grids._read_config_grids("f05_g16", "SCREAM") - assert lname == "a%0.47x0.63_l%0.47x0.63_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + assert ( + lname + == "a%0.47x0.63_l%0.47x0.63_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + ) - with self.assertRaisesRegex(CIMEError, "ERROR: grid alias f05_g16 not valid for compset DATM"): + with self.assertRaisesRegex( + CIMEError, "ERROR: grid alias f05_g16 not valid for compset DATM" + ): grids._read_config_grids("f05_g16", "DATM") lname = grids._read_config_grids("T31_g37_rx1", "_DROF") @@ -127,15 +137,28 @@ def test_read_config_grids(self): lname = grids._read_config_grids("f09_g16", "DATM3TEST") - assert lname == "a%0.9x1.25_l%0.9x1.25_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + assert ( + lname + == "a%0.9x1.25_l%0.9x1.25_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + ) - with self.assertRaisesRegex(CIMEError, "ERROR: grid alias f09_g16 not valid for compset DATM2TEST"): + with self.assertRaisesRegex( + CIMEError, "ERROR: grid alias f09_g16 not valid for compset DATM2TEST" + ): grids._read_config_grids("f09_g16", "DATM2TEST") lname = grids._read_config_grids("f19_g16", "DATM") - assert lname == "a%1.9x2.5_l%1.9x2.5_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + assert ( + lname + == "a%1.9x2.5_l%1.9x2.5_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + ) - lname = grids._read_config_grids("f19_g16", "DATM", atmnlev="2", lndnlev="4") + lname = grids._read_config_grids( + "f19_g16", "DATM", atmnlev="2", lndnlev="4" + ) - assert lname == "a%1.9x2.5z2_l%1.9x2.5z4_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + assert ( + lname + == "a%1.9x2.5z2_l%1.9x2.5z4_oi%gx1v6_r%r05_g%null_w%null_z%null_m%gx1v6" + ) From aa1061ee9c240222271ca6523b166159b229f93f Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 19:30:56 -0700 Subject: [PATCH 18/21] Fixes using models default driver to query machine spec file --- CIME/scripts/query_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 0e4b02d9efb..e122d8007a1 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -53,8 +53,8 @@ def parse_command_line(description): components = get_component_components(files) components.extend(["all"]) - # same for all comp_interfaces - config_file = files["mct"].get_value("MACHINES_SPEC_FILE") + default_driver = config.driver_default + config_file = files[default_driver].get_value("MACHINES_SPEC_FILE") utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), From 93ae9a68fb416588bd5bb13e42b726a1ad70c92f Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 19:51:18 -0700 Subject: [PATCH 19/21] Fixes function names --- CIME/scripts/query_config.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index e122d8007a1..67dc3b68020 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -47,10 +47,10 @@ def _main_func(description=__doc__): def parse_command_line(description): files = {x: Files(x) for x in list(config.driver_choices)} - compset_components = get_compset_components(files) - compset_components.extend(["all"]) + compset_active_components = get_compset_active_components(files) + compset_active_components.extend(["all"]) - components = get_component_components(files) + components = get_components(files) components.extend(["all"]) default_driver = config.driver_default @@ -73,7 +73,7 @@ def parse_command_line(description): "--compsets", nargs="?", const="all", - choices=sorted(set(compset_components)), + choices=sorted(set(compset_active_components)), help="Query compsets for active component. If no value is passed, compsets for all active components will be printed.", ) @@ -139,18 +139,18 @@ def parse_command_line(description): return kwargs -def get_compset_components(files): +def get_compset_active_components(files): values = [] for file in files.values(): - components = file.get_components("COMPSETS_SPEC_FILE") + active_components = file.get_components("COMPSETS_SPEC_FILE") - values.extend([x for x in components if x is not None]) + values.extend([x for x in active_components if x is not None]) return values -def get_component_components(files): +def get_components(files): values = [] for file in files.values(): From 7cf47b411fef19347e9e6c211860092c357cbabf Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 20:00:18 -0700 Subject: [PATCH 20/21] Cleans up arguments --- CIME/XML/grids.py | 6 +++--- CIME/scripts/query_config.py | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CIME/XML/grids.py b/CIME/XML/grids.py index d91ba1796d9..60bc1ff3d02 100644 --- a/CIME/XML/grids.py +++ b/CIME/XML/grids.py @@ -555,7 +555,7 @@ def _get_gridmaps_for_one_grid_pair( for name, value in these_gridmaps.items(): _add_grid_info(gridmaps, name, value) - def print_values(self, long_output=None): + def print_values(self, long=False): # write out help message helptext = self.get_element_text("help") logger.info("{} ".format(helptext)) @@ -589,7 +589,7 @@ def print_values(self, long_output=None): ) domains = {} - if long_output is not None: + if long: domain_nodes = self.get_children("domain", root=self.get_child("domains")) for domain_node in domain_nodes: name = self.get(domain_node, "name") @@ -642,7 +642,7 @@ def print_values(self, long_output=None): mask_nodes = self.get_children("mask", root=model_grid_node) for mask_node in mask_nodes: logger.info(" mask is: {}".format(self.text(mask_node))) - if long_output is not None: + if long: gridnames = set(gridnames) for gridname in gridnames: if gridname != "null": diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index 67dc3b68020..e1e5b0fe722 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -172,23 +172,23 @@ def get_component_classes(files): return config_drv.get_valid_model_components() -def query_grids(files, long, xml=False, **_): +def query_grids(files, long, xml, **_): config_file = files.get_value("GRIDS_SPEC_FILE") + utils.expect( os.path.isfile(config_file), "Cannot find config_file {} on disk".format(config_file), ) grids = Grids(config_file) + if xml: print("{}".format(grids.get_raw_record().decode("UTF-8"))) - elif long: - grids.print_values(long_output=long) else: - grids.print_values() + grids.print_values(long=long) -def query_compsets(files, compsets, xml=False, **_): +def query_compsets(files, compsets, **kwargs): # Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE components = files.get_components("COMPSETS_SPEC_FILE") match_found = None @@ -213,12 +213,12 @@ def query_compsets(files, compsets, xml=False, **_): if all_components: # print all compsets for component in components: # the all_components flag will only print available components - print_compset(component, files, all_components=all_components, xml=xml) + print_compset(all_components=all_components, **kwargs) else: - print_compset(compsets, files, xml=xml) + print_compset(**kwargs) -def print_compset(name, files, all_components=False, xml=False): +def print_compset(name, files, xml=False, all_components=False, **_): """ print compsets associated with the component name, but if all_components is true only print the details if the associated component is available @@ -255,7 +255,7 @@ def print_compset(name, files, all_components=False, xml=False): compsets.print_values(arg_help=False) -def query_component_settings(components, files, xml=False, **_): +def query_component_settings(components, files, **kwargs): classes = get_component_classes(files) if components == "all": @@ -267,12 +267,12 @@ def query_component_settings(components, files, xml=False, **_): components = files.get_components(string) for item in components: - _query_component_settings(item, files, all_components=True, xml=xml) + _query_component_settings(item, files, all_components=True, **kwargs) else: - _query_component_settings(components, files, xml=xml) + _query_component_settings(components, files, **kwargs) -def _query_component_settings(component, files, all_components=False, xml=False, **_): +def _query_component_settings(component, files, xml=False, all_components=False, **_): # Determine the valid component classes (e.g. atm) for the driver/cpl # These are then stored in comps_array classes = get_component_classes(files) @@ -333,7 +333,7 @@ def _query_component_settings(component, files, all_components=False, xml=False, component.print_values() -def query_machines(files, machines, xml=False, **_): +def query_machines(files, machines, xml, **_): config_file = files.get_value("MACHINES_SPEC_FILE") utils.expect( os.path.isfile(config_file), From 314e4e4620b74dd7a54145527aafcc1ae95c72f3 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 28 Jun 2024 20:58:33 -0700 Subject: [PATCH 21/21] Fixes missing arguments --- CIME/scripts/query_config.py | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/CIME/scripts/query_config.py b/CIME/scripts/query_config.py index e1e5b0fe722..7f4240c668c 100755 --- a/CIME/scripts/query_config.py +++ b/CIME/scripts/query_config.py @@ -8,7 +8,6 @@ import os import sys -import re import logging import argparse @@ -189,33 +188,14 @@ def query_grids(files, long, xml, **_): def query_compsets(files, compsets, **kwargs): - # Determine valid component values by checking the value attributes for COMPSETS_SPEC_FILE - components = files.get_components("COMPSETS_SPEC_FILE") - match_found = None - all_components = False - if re.search("^all$", compsets): # print all compsets - match_found = compsets - all_components = True - else: - for component in components: - if component == compsets: - match_found = compsets - break - - # If name is not a valid argument - exit with error - utils.expect( - match_found is not None, - "Invalid input argument {}, valid input arguments are {}".format( - compsets, components - ), - ) + if compsets == "all": + active_components = files.get_components("COMPSETS_SPEC_FILE") - if all_components: # print all compsets - for component in components: + for component in active_components: # the all_components flag will only print available components - print_compset(all_components=all_components, **kwargs) + print_compset(component, files, all_components=True, **kwargs) else: - print_compset(**kwargs) + print_compset(compsets, files, **kwargs) def print_compset(name, files, xml=False, all_components=False, **_):