Added handling of command line interface parameter mapping
Luis de la Garza
7 years ago
13 | 13 | |
14 | 14 | from argparse import ArgumentParser |
15 | 15 | from argparse import RawDescriptionHelpFormatter |
16 | from CTDopts.CTDopts import CTDModel, _InFile, _OutFile, ParameterGroup, _Choices, _NumericRange, \ | |
17 | _FileFormat, ModelError | |
18 | 16 | from collections import OrderedDict |
19 | 17 | from string import strip |
20 | 18 | from lxml import etree |
21 | 19 | from lxml.etree import SubElement, Element, ElementTree, ParseError, parse |
20 | ||
21 | from CTDopts.CTDopts import CTDModel, _InFile, _OutFile, ParameterGroup, _Choices, _NumericRange, _FileFormat, \ | |
22 | ModelError, _Null | |
22 | 23 | |
23 | 24 | __all__ = [] |
24 | 25 | __version__ = 1.0 |
307 | 308 | parser.add_argument("-p", "--hardcoded-parameters", dest="hardcoded_parameters", default=None, required=False, |
308 | 309 | help="File containing hardcoded values for the given parameters. Run with '-h' or '--help' " |
309 | 310 | "to see a brief example on the format of this file.") |
311 | ||
310 | 312 | # TODO: add verbosity, maybe? |
311 | 313 | parser.add_argument("-V", "--version", action='version', version=program_version_message) |
312 | 314 | |
317 | 319 | validate_and_prepare_args(args) |
318 | 320 | |
319 | 321 | # extract the names of the macros and check that we have found the ones we need |
320 | macros_file_names = args.macros_files | |
321 | macros_to_expand = parse_macros_files(macros_file_names) | |
322 | macros_to_expand = parse_macros_files(args.macros_files) | |
322 | 323 | |
323 | 324 | # parse the given supported file-formats file |
324 | 325 | supported_file_formats = parse_file_formats(args.formats_file) |
340 | 341 | blacklisted_parameters=args.blacklisted_parameters, |
341 | 342 | required_tools=required_tools, |
342 | 343 | skip_tools=skip_tools, |
343 | macros_file_names=macros_file_names, | |
344 | macros_file_names=args.macros_files, | |
344 | 345 | macros_to_expand=macros_to_expand, |
345 | 346 | parameter_hardcoder=parameter_hardcoder) |
346 | 347 | |
391 | 392 | |
392 | 393 | def parse_macros_files(macros_file_names): |
393 | 394 | macros_to_expand = set() |
394 | ||
395 | if not macros_file_names: | |
396 | # list is empty, provide the default value | |
397 | warning("Using default macros from macros.xml", 0) | |
398 | macros_file_names = ["macros.xml"] | |
399 | 395 | |
400 | 396 | for macros_file_name in macros_file_names: |
401 | 397 | try: |
551 | 547 | if file_name is not None and os.path.isdir(file_name): |
552 | 548 | raise ApplicationException("The provided output file name (%s) points to a directory." % file_name) |
553 | 549 | |
550 | if not args.macros_files: | |
551 | # list is empty, provide the default value | |
552 | warning("Using default macros from macros.xml", 0) | |
553 | args.macros_files = ["macros.xml"] | |
554 | ||
554 | 555 | |
555 | 556 | def convert(input_files, output_destination, **kwargs): |
556 | 557 | # first, generate a model |
679 | 680 | description.text = model.opt_attribs["description"] |
680 | 681 | |
681 | 682 | |
683 | def get_param_cli_name(param, model): | |
684 | # we generate parameters with colons for subgroups, but not for the topmost parents (OpenMS legacy) | |
685 | if type(param.parent) == ParameterGroup and param.parent.parent != None: | |
686 | if model.cli: | |
687 | warning("Using nested parameter sections (NODE elements) is not compatible with <cli>", py1) | |
688 | return get_param_name(param.parent) + ":" + resolve_param_mapping(param, model) | |
689 | else: | |
690 | return resolve_param_mapping(param, model) | |
691 | ||
692 | ||
682 | 693 | def get_param_name(param): |
683 | 694 | # we generate parameters with colons for subgroups, but not for the topmost parents (OpenMS legacy) |
684 | 695 | if type(param.parent) == ParameterGroup and param.parent.parent != None: |
685 | return get_param_name(param.parent) + ":" + resolve_param_mapping(param) | |
696 | return get_param_name(param.parent) + ":" + param.name | |
686 | 697 | else: |
687 | return resolve_param_mapping(param) | |
698 | return param.name | |
688 | 699 | |
689 | 700 | |
690 | 701 | # some parameters are mapped to command line options, this method helps resolve those mappings, if any |
691 | # TODO: implement mapping of parameters!!! | |
692 | def resolve_param_mapping(param): | |
693 | return param.name | |
694 | ||
702 | def resolve_param_mapping(param, model): | |
703 | # go through all mappings and find if the given param appears as a reference name in a mapping element | |
704 | param_mapping = None | |
705 | for cli_element in model.cli: | |
706 | for mapping_element in cli_element.mappings: | |
707 | if mapping_element.reference_name == param.name: | |
708 | if param_mapping is not None: | |
709 | warning("The parameter %s has more than one mapping in the <cli> section. " | |
710 | "The first found mapping, %s, will be used." % (param.name, param_mapping), 1) | |
711 | else: | |
712 | param_mapping = cli_element.option_identifier | |
713 | ||
714 | return param_mapping if param_mapping is not None else param.name | |
695 | 715 | |
696 | 716 | def create_command(tool, model, **kwargs): |
697 | 717 | final_command = get_tool_executable_path(model, kwargs["default_executable_path"]) + '\n' |
707 | 727 | found_output_parameter = True |
708 | 728 | command = '' |
709 | 729 | param_name = get_param_name(param) |
730 | param_cli_name = get_param_cli_name(param, model) | |
731 | if param_name == param_cli_name: | |
732 | # there was no mapping, so for the cli name we will use a '-' in the prefix | |
733 | param_cli_name = '-' + param_name | |
710 | 734 | |
711 | 735 | if param.name in kwargs["blacklisted_parameters"]: |
712 | 736 | continue |
713 | 737 | |
714 | 738 | hardcoded_value = parameter_hardcoder.get_hardcoded_value(param_name, model.name) |
715 | 739 | if hardcoded_value: |
716 | command += '-%s %s\n' % (param_name, hardcoded_value) | |
740 | command += '%s %s\n' % (param_cli_name, hardcoded_value) | |
717 | 741 | else: |
718 | 742 | # parameter is neither blacklisted nor hardcoded... |
719 | 743 | galaxy_parameter_name = get_galaxy_parameter_name(param) |
722 | 746 | # logic for ITEMLISTs |
723 | 747 | if param.is_list: |
724 | 748 | if param.type is _InFile: |
725 | command += "-" + str(param_name) + "\n" | |
749 | command += param_cli_name + "\n" | |
726 | 750 | command += " #for token in $" + galaxy_parameter_name + ":\n" |
727 | 751 | command += " $token\n" |
728 | 752 | command += " #end for\n" |
729 | 753 | else: |
730 | 754 | command += "\n#if $" + repeat_galaxy_parameter_name + ":\n" |
731 | command += "-" + str(param_name) + "\n" | |
755 | command += param_cli_name + "\n" | |
732 | 756 | command += " #for token in $" + repeat_galaxy_parameter_name + ":\n" |
733 | 757 | command += " #if \" \" in str(token):\n" |
734 | 758 | command += " \"$token." + galaxy_parameter_name + "\"\n" |
752 | 776 | |
753 | 777 | if not is_boolean_parameter(param) and type(param.restrictions) is _Choices : |
754 | 778 | command += "#if " + actual_parameter + ":\n" |
755 | command += ' -%s\n' % param_name | |
779 | command += ' %s\n' % param_cli_name | |
756 | 780 | command += " #if \" \" in str(" + actual_parameter + "):\n" |
757 | 781 | command += " \"" + actual_parameter + "\"\n" |
758 | 782 | command += " #else\n" |
761 | 785 | command += "#end if\n" |
762 | 786 | elif is_boolean_parameter(param): |
763 | 787 | command += "#if " + actual_parameter + ":\n" |
764 | command += ' -%s\n' % param_name | |
788 | command += ' %s\n' % param_cli_name | |
765 | 789 | command += "#end if\n" |
766 | 790 | elif TYPE_TO_GALAXY_TYPE[param.type] is 'text': |
767 | 791 | command += "#if " + actual_parameter + ":\n" |
768 | command += " -%s " % param_name | |
792 | command += " %s " % param_cli_name | |
769 | 793 | command += " \"" + actual_parameter + "\"\n" |
770 | 794 | command += "#end if\n" |
771 | 795 | else: |
772 | 796 | command += "#if " + actual_parameter + ":\n" |
773 | command += ' -%s ' % param_name | |
797 | command += ' %s ' % param_cli_name | |
774 | 798 | command += actual_parameter + "\n" |
775 | 799 | command += "#end if\n" |
776 | 800 | |
1000 | 1024 | add_child_node(valid_node, "remove", OrderedDict([("value", '"')])) |
1001 | 1025 | |
1002 | 1026 | # check for default value |
1003 | if param.default is not None: | |
1027 | if param.default is not None and param.default is not _Null: | |
1004 | 1028 | if type(param.default) is list: |
1005 | 1029 | # we ASSUME that a list of parameters looks like: |
1006 | 1030 | # $ tool -ignore He Ar Xe |
1008 | 1032 | param_node.attrib["value"] = ' '.join(map(str, param.default)) |
1009 | 1033 | |
1010 | 1034 | elif param_type != "boolean": |
1011 | # boolean parameters handle default values by using the "checked" attribute | |
1012 | # there isn't much we can do... just stringify the value | |
1013 | 1035 | param_node.attrib["value"] = str(param.default) |
1036 | ||
1037 | else: | |
1038 | # simple boolean with a default | |
1039 | if param.default is True: | |
1040 | param_node.attrib["checked"] = "true" | |
1014 | 1041 | else: |
1015 | 1042 | if param.type is int or param.type is float: |
1016 | 1043 | # galaxy requires "value" to be included for int/float |
1122 | 1149 | |
1123 | 1150 | # determines if the given choices are boolean (basically, if the possible values are yes/no, true/false) |
1124 | 1151 | def is_boolean_parameter(param): |
1125 | is_choices = False | |
1126 | if type(param.restrictions) is _Choices: | |
1127 | # for a true boolean experience, we need 2 values | |
1128 | # and also that those two values are either yes/no or true/false | |
1129 | if len(param.restrictions.choices) == 2: | |
1130 | choices = get_lowercase_list(param.restrictions.choices) | |
1131 | if ("yes" in choices and "no" in choices) or ("true" in choices and "false" in choices): | |
1132 | is_choices = True | |
1133 | return is_choices | |
1152 | return param.type is bool | |
1134 | 1153 | |
1135 | 1154 | |
1136 | 1155 | # determines if there are choices for the parameter |