From 4c90eef8ff46c6fdcb36d57e418bb24a81f4eec9 Mon Sep 17 00:00:00 2001 From: Maisam Arif Date: Fri, 13 Oct 2023 14:03:24 -0500 Subject: [PATCH] Added custom help formatters for subparsers Signed-off-by: Maisam Arif Change-Id: Ib7209ad7188733fa2492cde302f5c82c9c9bfa42 [ROCm/amdsmi commit: ddc63db14c49fe457d4b0d60970d65c853a1f098] --- projects/amdsmi/amdsmi_cli/amdsmi_parser.py | 103 +++++++++++--------- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/projects/amdsmi/amdsmi_cli/amdsmi_parser.py b/projects/amdsmi/amdsmi_cli/amdsmi_parser.py index 098fe2f629..679c8138b6 100644 --- a/projects/amdsmi/amdsmi_cli/amdsmi_parser.py +++ b/projects/amdsmi/amdsmi_cli/amdsmi_parser.py @@ -34,18 +34,28 @@ import amdsmi_cli_exceptions # Custom Help Formatter for increasing the action max length -class SubparserHelpFormatter(argparse.HelpFormatter): - def __init__(self, prog, - indent_increment=2, - max_help_position=24, - width=90): - super().__init__(prog, - indent_increment=indent_increment, - max_help_position=max_help_position, - width=width) +class AMDSMIParserHelpFormatter(argparse.HelpFormatter): + def __init__(self, prog): + super().__init__(prog=prog, + indent_increment=2, + max_help_position=24, + width=90) self._action_max_length = 20 +# Custom Help Formatter for not duplicating the metavar in the subparsers +class AMDSMISubparserHelpFormatter(argparse.RawTextHelpFormatter): + def __init__(self, prog): + super().__init__(prog, max_help_position=80, width=90) + + def _format_action_invocation(self, action): + if not action.option_strings or action.nargs == 0: + return super()._format_action_invocation(action) + default = self._get_default_metavar_for_optional(action) + args_string = self._format_args(action, default) + return ', '.join(action.option_strings) + ' ' + args_string + + class AMDSMIParser(argparse.ArgumentParser): """Unified Parser for AMDSMI CLI. This parser doesn't access amdsmi's lib directly,but via AMDSMIHelpers, @@ -69,32 +79,32 @@ class AMDSMIParser(argparse.ArgumentParser): # Adjust argument parser options super().__init__( - formatter_class= lambda prog: SubparserHelpFormatter(prog), + formatter_class= lambda prog: AMDSMIParserHelpFormatter(prog), description=f"AMD System Management Interface | {version_string} | {platform_string}", add_help=True, prog=program_name) # Setup subparsers - subparsers = self.add_subparsers( + self.subparsers = self.add_subparsers( title="AMD-SMI Commands", parser_class=argparse.ArgumentParser, help="Descriptions:", metavar='') # Add all subparsers - self._add_version_parser(subparsers, version) - self._add_list_parser(subparsers, list) - self._add_static_parser(subparsers, static) - self._add_firmware_parser(subparsers, firmware) - self._add_bad_pages_parser(subparsers, bad_pages) - self._add_metric_parser(subparsers, metric) - self._add_process_parser(subparsers, process) - self._add_profile_parser(subparsers, profile) - self._add_event_parser(subparsers, event) - self._add_topology_parser(subparsers, topology) - self._add_set_value_parser(subparsers, set_value) - self._add_reset_parser(subparsers, reset) - self._add_rocm_smi_parser(subparsers, rocmsmi) + self._add_version_parser(self.subparsers, version) + self._add_list_parser(self.subparsers, list) + self._add_static_parser(self.subparsers, static) + self._add_firmware_parser(self.subparsers, firmware) + self._add_bad_pages_parser(self.subparsers, bad_pages) + self._add_metric_parser(self.subparsers, metric) + self._add_process_parser(self.subparsers, process) + self._add_profile_parser(self.subparsers, profile) + self._add_event_parser(self.subparsers, event) + self._add_topology_parser(self.subparsers, topology) + self._add_set_value_parser(self.subparsers, set_value) + self._add_reset_parser(self.subparsers, reset) + self._add_rocm_smi_parser(self.subparsers, rocmsmi) def _positive_int(self, int_value): @@ -212,7 +222,8 @@ class AMDSMIParser(argparse.ArgumentParser): json_help = "Displays output in JSON format (human readable by default)." csv_help = "Displays output in CSV format (human readable by default)." file_help = "Saves output into a file on the provided path (stdout by default)." - loglevel_help = "Set the logging level for the parser commands (ERROR by default)." + loglevel_choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] + loglevel_help = f"Set the logging level from the possible choices:\n{loglevel_choices}" command_modifier_group = subcommand_parser.add_argument_group('Command Modifiers') @@ -223,22 +234,22 @@ class AMDSMIParser(argparse.ArgumentParser): command_modifier_group.add_argument('--file', action=self._check_output_file_path(), type=str, required=False, help=file_help) # Placing loglevel outside the subcommands so it can be used with any subcommand - command_modifier_group.add_argument('--loglevel', action='store', required=False, help=loglevel_help, default='ERROR', - choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]) + command_modifier_group.add_argument('--loglevel', action='store', required=False, help=loglevel_help, default='ERROR', metavar='LEVEL', + choices=loglevel_choices) def _add_watch_arguments(self, subcommand_parser): # Device arguments help text - watch_help = "Reprint the command in a loop of Interval seconds" - watch_time_help = "The total time to watch the given command" - iterations_help = "Total number of iterations to loop on the given command" + watch_help = "Reprint the command in a loop of INTERVAL seconds" + watch_time_help = "The total TIME to watch the given command" + iterations_help = "Total number of ITERATIONS to loop on the given command" # Mutually Exclusive Args within the subparser - subcommand_parser.add_argument('-w', '--watch', action='store', metavar='loop_time', + subcommand_parser.add_argument('-w', '--watch', action='store', metavar='INTERVAL', type=self._positive_int, required=False, help=watch_help) - subcommand_parser.add_argument('-W', '--watch_time', action=self._check_watch_selected(), metavar='total_loop_time', + subcommand_parser.add_argument('-W', '--watch_time', action=self._check_watch_selected(), metavar='TIME', type=self._positive_int, required=False, help=watch_time_help) - subcommand_parser.add_argument('-i', '--iterations', action=self._check_watch_selected(), metavar='number_of_iterations', + subcommand_parser.add_argument('-i', '--iterations', action=self._check_watch_selected(), metavar='ITERATIONS', type=self._positive_int, required=False, help=iterations_help) @@ -265,7 +276,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create version subparser version_parser = subparsers.add_parser('version', help=version_help, description=None) version_parser._optionals.title = None - version_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + version_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) version_parser.set_defaults(func=func) self._add_command_modifiers(version_parser) @@ -281,7 +292,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create list subparser list_parser = subparsers.add_parser('list', help=list_help, description=list_subcommand_help) - list_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + list_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) list_parser.set_defaults(func=func) # Add Command Modifiers @@ -321,7 +332,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create static subparser static_parser = subparsers.add_parser('static', help=static_help, description=static_subcommand_help) static_parser._optionals.title = static_optionals_title - static_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + static_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) static_parser.set_defaults(func=func) self._add_command_modifiers(static_parser) @@ -365,7 +376,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create firmware subparser firmware_parser = subparsers.add_parser('firmware', help=firmware_help, description=firmware_subcommand_help, aliases=['ucode']) firmware_parser._optionals.title = firmware_optionals_title - firmware_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + firmware_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) firmware_parser.set_defaults(func=func) self._add_command_modifiers(firmware_parser) @@ -398,7 +409,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create bad_pages subparser bad_pages_parser = subparsers.add_parser('bad-pages', help=bad_pages_help, description=bad_pages_subcommand_help) bad_pages_parser._optionals.title = bad_pages_optionals_title - bad_pages_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + bad_pages_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) bad_pages_parser.set_defaults(func=func) self._add_command_modifiers(bad_pages_parser) @@ -448,7 +459,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create metric subparser metric_parser = subparsers.add_parser('metric', help=metric_help, description=metric_subcommand_help) metric_parser._optionals.title = metric_optionals_title - metric_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + metric_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) metric_parser.set_defaults(func=func) self._add_command_modifiers(metric_parser) @@ -511,7 +522,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create process subparser process_parser = subparsers.add_parser('process', help=process_help, description=process_subcommand_help) process_parser._optionals.title = process_optionals_title - process_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + process_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) process_parser.set_defaults(func=func) self._add_command_modifiers(process_parser) @@ -541,7 +552,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create profile subparser profile_parser = subparsers.add_parser('profile', help=profile_help, description=profile_subcommand_help) profile_parser._optionals.title = profile_optionals_title - profile_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + profile_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) profile_parser.set_defaults(func=func) self._add_command_modifiers(profile_parser) @@ -562,7 +573,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create event subparser event_parser = subparsers.add_parser('event', help=event_help, description=event_subcommand_help) event_parser._optionals.title = event_optionals_title - event_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + event_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) event_parser.set_defaults(func=func) self._add_command_modifiers(event_parser) @@ -591,7 +602,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create topology subparser topology_parser = subparsers.add_parser('topology', help=topology_help, description=topology_subcommand_help) topology_parser._optionals.title = topology_optionals_title - topology_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + topology_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) topology_parser.set_defaults(func=func) self._add_command_modifiers(topology_parser) @@ -628,7 +639,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create set_value subparser set_value_parser = subparsers.add_parser('set', help=set_value_help, description=set_value_subcommand_help) set_value_parser._optionals.title = set_value_optionals_title - set_value_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + set_value_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) set_value_parser.set_defaults(func=func) self._add_command_modifiers(set_value_parser) @@ -761,7 +772,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create reset subparser reset_parser = subparsers.add_parser('reset', help=reset_help, description=reset_subcommand_help) reset_parser._optionals.title = reset_optionals_title - reset_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + reset_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) reset_parser.set_defaults(func=func) self._add_command_modifiers(reset_parser) @@ -802,7 +813,7 @@ class AMDSMIParser(argparse.ArgumentParser): # Create rocm_smi subparser rocm_smi_parser = subparsers.add_parser('rocm-smi', help=rocm_smi_help, description=rocm_smi_subcommand_help) rocm_smi_parser._optionals.title = rocm_smi_optionals_title - rocm_smi_parser.formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80, width=90) + rocm_smi_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) rocm_smi_parser.set_defaults(func=func) self._add_command_modifiers(rocm_smi_parser)