From 47fc50576e7040680c19e152592b2c5e5cc297f5 Mon Sep 17 00:00:00 2001 From: Ruomei Yan Date: Wed, 2 Nov 2022 16:47:56 +0000 Subject: MLIA-649 Strip mlia backend management into a new command * add entry point for mlia-backend in setup.cfg and main.py * add --force option for install from path: uninstall existing backend in ML Inference Advisor and install from given path * add uninstall and list program parameters: uninstall has backend_name as input arg, install has backend_name as a mandatory argument * add unit tests in test_cli_commands.py, test_cli_main.py, test_tools_metadata_common.py, test_tools_metadata_corstone.py * updated README.md * remove --download option for installing backend * add new lines for the display section when we do mlia-backen list * add case insensitive support for backend names in command line argument Change-Id: Icb89d8957fa6be4b767710e24fa074f26472674b --- src/mlia/cli/commands.py | 41 ++++++++++++------------ src/mlia/cli/common.py | 3 +- src/mlia/cli/main.py | 81 ++++++++++++++++++++++++++++++++++++------------ src/mlia/cli/options.py | 37 ++++++++++------------ 4 files changed, 102 insertions(+), 60 deletions(-) (limited to 'src/mlia/cli') diff --git a/src/mlia/cli/commands.py b/src/mlia/cli/commands.py index 72ae4bb..4be7f3e 100644 --- a/src/mlia/cli/commands.py +++ b/src/mlia/cli/commands.py @@ -29,7 +29,6 @@ from mlia.api import PathOrFileLike from mlia.cli.config import get_installation_manager from mlia.cli.options import parse_optimization_parameters from mlia.utils.console import create_section_header -from mlia.utils.types import only_one_selected logger = logging.getLogger(__name__) @@ -243,34 +242,36 @@ def optimization( ) -def backend( - backend_action: str, +def backend_install( + name: str, path: Path | None = None, - download: bool = False, - name: str | None = None, i_agree_to_the_contained_eula: bool = False, noninteractive: bool = False, + force: bool = False, ) -> None: - """Backends configuration.""" + """Install configuration.""" logger.info(CONFIG) manager = get_installation_manager(noninteractive) - if backend_action == "status": - manager.show_env_details() + install_from_path = path is not None - if backend_action == "install": - install_from_path = path is not None + if install_from_path: + manager.install_from(cast(Path, path), name, force) + else: + eula_agreement = not i_agree_to_the_contained_eula + manager.download_and_install(name, eula_agreement) - if not only_one_selected(install_from_path, download): - raise Exception( - "Please select only one action: download or " - "provide path to the backend installation" - ) - if install_from_path: - manager.install_from(cast(Path, path), name) +def backend_uninstall( + name: str, +) -> None: + """Uninstall backend(s).""" + manager = get_installation_manager(noninteractive=True) + manager.uninstall(name) + - if download: - eula_agreement = not i_agree_to_the_contained_eula - manager.download_and_install(name, eula_agreement) +def backend_list() -> None: + """List backend status.""" + manager = get_installation_manager(noninteractive=True) + manager.show_env_details() diff --git a/src/mlia/cli/common.py b/src/mlia/cli/common.py index 3f60668..077f456 100644 --- a/src/mlia/cli/common.py +++ b/src/mlia/cli/common.py @@ -16,11 +16,12 @@ class CommandInfo: aliases: list[str] opt_groups: list[Callable[[argparse.ArgumentParser], None]] is_default: bool = False + name: str | None = None @property def command_name(self) -> str: """Return command name.""" - return self.func.__name__ + return self.name or self.func.__name__ @property def command_name_and_aliases(self) -> list[str]: diff --git a/src/mlia/cli/main.py b/src/mlia/cli/main.py index d36d2d9..61b8f05 100644 --- a/src/mlia/cli/main.py +++ b/src/mlia/cli/main.py @@ -12,14 +12,17 @@ from pathlib import Path from mlia import __version__ from mlia.cli.commands import all_tests -from mlia.cli.commands import backend +from mlia.cli.commands import backend_install +from mlia.cli.commands import backend_list +from mlia.cli.commands import backend_uninstall from mlia.cli.commands import operators from mlia.cli.commands import optimization from mlia.cli.commands import performance from mlia.cli.common import CommandInfo from mlia.cli.helpers import CLIActionResolver from mlia.cli.logging import setup_logging -from mlia.cli.options import add_backend_options +from mlia.cli.options import add_backend_install_options +from mlia.cli.options import add_backend_uninstall_options from mlia.cli.options import add_custom_supported_operators_options from mlia.cli.options import add_debug_options from mlia.cli.options import add_evaluation_options @@ -99,42 +102,66 @@ def get_commands() -> list[CommandInfo]: add_evaluation_options, ], ), + ] + + +def backend_commands() -> list[CommandInfo]: + """Return commands configuration.""" + return [ + CommandInfo( + backend_install, + [], + [ + add_backend_install_options, + add_debug_options, + ], + name="install", + ), CommandInfo( - backend, + backend_uninstall, [], [ - add_backend_options, + add_backend_uninstall_options, add_debug_options, ], + name="uninstall", + ), + CommandInfo( + backend_list, + [], + [ + add_debug_options, + ], + name="list", ), ] -def get_default_command() -> str | None: +def get_default_command(commands: list[CommandInfo]) -> str | None: """Get name of the default command.""" - commands = get_commands() - marked_as_default = [cmd.command_name for cmd in commands if cmd.is_default] assert len(marked_as_default) <= 1, "Only one command could be marked as default" return next(iter(marked_as_default), None) -def get_possible_command_names() -> list[str]: +def get_possible_command_names(commands: list[CommandInfo]) -> list[str]: """Get all possible command names including aliases.""" return [ name_or_alias - for cmd in get_commands() + for cmd in commands for name_or_alias in cmd.command_name_and_aliases ] -def init_commands(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: +def init_commands( + parser: argparse.ArgumentParser, commands: list[CommandInfo] +) -> argparse.ArgumentParser: """Init cli subcommands.""" subparsers = parser.add_subparsers(title="Commands", dest="command") subparsers.required = True - for command in get_commands(): + for command in commands: command_parser = subparsers.add_parser( command.command_name, aliases=command.aliases, @@ -188,7 +215,6 @@ def run_command(args: argparse.Namespace) -> int: try: logger.info(INFO_MESSAGE) - args.func(**func_args) return 0 except KeyboardInterrupt: @@ -251,12 +277,14 @@ def init_subcommand_parser(parent: argparse.ArgumentParser) -> argparse.Argument return parser -def add_default_command_if_needed(args: list[str]) -> None: +def add_default_command_if_needed( + args: list[str], input_commands: list[CommandInfo] +) -> None: """Add default command to the list of the arguments if needed.""" - default_command = get_default_command() + default_command = get_default_command(input_commands) if default_command and len(args) > 0: - commands = get_possible_command_names() + commands = get_possible_command_names(input_commands) help_or_version = ["-h", "--help", "-v", "--version"] command_is_missing = args[0] not in [*commands, *help_or_version] @@ -264,16 +292,31 @@ def add_default_command_if_needed(args: list[str]) -> None: args.insert(0, default_command) -def main(argv: list[str] | None = None) -> int: - """Entry point of the application.""" +def generic_main( + commands: list[CommandInfo], argv: list[str] | None = None +) -> argparse.Namespace: + """Enable multiple entry points.""" common_parser = init_common_parser() subcommand_parser = init_subcommand_parser(common_parser) - init_commands(subcommand_parser) + init_commands(subcommand_parser, commands) common_args, subcommand_args = common_parser.parse_known_args(argv) - add_default_command_if_needed(subcommand_args) + + add_default_command_if_needed(subcommand_args, commands) args = subcommand_parser.parse_args(subcommand_args, common_args) + return args + + +def main(argv: list[str] | None = None) -> int: + """Entry point of the main application.""" + args = generic_main(get_commands(), argv) + return run_command(args) + + +def backend_main(argv: list[str] | None = None) -> int: + """Entry point of the backend application.""" + args = generic_main(backend_commands(), argv) return run_command(args) diff --git a/src/mlia/cli/options.py b/src/mlia/cli/options.py index f6dcf75..bf2f09b 100644 --- a/src/mlia/cli/options.py +++ b/src/mlia/cli/options.py @@ -131,7 +131,7 @@ def add_custom_supported_operators_options(parser: argparse.ArgumentParser) -> N ) -def add_backend_options(parser: argparse.ArgumentParser) -> None: +def add_backend_install_options(parser: argparse.ArgumentParser) -> None: """Add options for the backends configuration.""" def valid_directory(param: str) -> Path: @@ -141,42 +141,39 @@ def add_backend_options(parser: argparse.ArgumentParser) -> None: return dir_path - subparsers = parser.add_subparsers(title="Backend actions", dest="backend_action") - subparsers.required = True - - install_subparser = subparsers.add_parser( - "install", help="Install backend", allow_abbrev=False - ) - install_type_group = install_subparser.add_mutually_exclusive_group() - install_type_group.required = True - install_type_group.add_argument( + parser.add_argument( "--path", type=valid_directory, help="Path to the installed backend" ) - install_type_group.add_argument( - "--download", + parser.add_argument( + "--i-agree-to-the-contained-eula", default=False, action="store_true", - help="Download and install backend", + help=argparse.SUPPRESS, ) - install_subparser.add_argument( - "--i-agree-to-the-contained-eula", + parser.add_argument( + "--force", default=False, action="store_true", - help=argparse.SUPPRESS, + help="Force reinstall backend in the specified path", ) - install_subparser.add_argument( + parser.add_argument( "--noninteractive", default=False, action="store_true", help="Non interactive mode with automatic confirmation of every action", ) - install_subparser.add_argument( + parser.add_argument( "name", - nargs="?", help="Name of the backend to install", ) - subparsers.add_parser("status", help="Show backends status") + +def add_backend_uninstall_options(parser: argparse.ArgumentParser) -> None: + """Add options for the backends configuration.""" + parser.add_argument( + "name", + help="Name of the installed backend", + ) def add_evaluation_options(parser: argparse.ArgumentParser) -> None: -- cgit v1.2.1