Source code for utms.cli.commands.core.hierarchy

"""Module for managing command hierarchy and handling in the UTMS CLI system.

This module defines the `CommandHierarchy` class, which is responsible for organizing
commands and subcommands, managing their argument parsers, handling associated functions,
and establishing default behaviors for commands. It allows the UTMS CLI system to parse
and execute commands and subcommands effectively.

Imports:
    - `argparse`: Standard library for command-line argument parsing.
    - `Any`, `Callable`, `Dict`, `Optional`: Typing annotations for type hints.

Exports:
    - `CommandHierarchy`: Class that handles the management of commands, subcommands,
      parsers, and handlers in the CLI system.

Usage:
    The `CommandHierarchy` class is used to define the structure and behavior of commands
    and subcommands in the UTMS CLI, including associating them with specific parsers and handlers.
"""

import argparse
from typing import Any, Callable, Dict, Optional


[docs] class CommandHierarchy: """Manages the hierarchy of commands and subcommands for the UTMS CLI system. The `CommandHierarchy` class is responsible for organizing commands and their subcommands, associating them with argument parsers, and mapping them to their respective handler functions. It also allows for the definition of default subcommands for specific commands. Attributes: parent_parsers (Dict[str, argparse.ArgumentParser]): A dictionary mapping top-level commands to their parsers. child_parsers (Dict[str, Dict[str, argparse.ArgumentParser]]): A dictionary mapping commands to their subcommand parsers. subparsers_actions (Dict[str, argparse._SubParsersAction[Any]]): A dictionary storing subparsers actions for commands. default_subcommands (Dict[str, str]): A dictionary mapping commands to their default subcommands. handlers (Dict[str, Dict[Optional[str], Callable[[argparse.Namespace], None]]]): A dictionary mapping commands and subcommands to their handler functions. Methods: __init__() -> None: Initializes the command hierarchy. add_parent_parser(command: str, parser: argparse.ArgumentParser) -> None: Adds a top-level command and its corresponding parser. add_subcommand(command: str, subcommand: str, parser: argparse.ArgumentParser) -> None: Adds a subcommand and its associated parser. add_handler(handler: Callable[[argparse.Namespace], None], command: str, subcommand: Optional[str] = None) -> None: Adds a handler function for a command or subcommand. add_subparsers_actions(command: str, actions: argparse._SubParsersAction[Any]) -> None: Adds subparser actions for a command. set_default_subcommand(command: str, subcommand: str) -> None: Sets the default subcommand for a given command. get_handler(command: Optional[str], subcommand: Optional[str] = None) -> Optional[Callable[[argparse.Namespace], None]]: Retrieves the handler function for a command or subcommand. get_parser(command: str, subcommand: Optional[str] = None) -> Optional[argparse.ArgumentParser]: Retrieves the parser for a given command and subcommand. get_action(command: str) -> argparse._SubParsersAction[Any]: Retrieves the subparser action for a command. root_actions() -> argparse._SubParsersAction[Any]: Property that retrieves the root subparser actions for the CLI. """
[docs] def __init__(self) -> None: """Initializes the command hierarchy, setting up containers for parent parsers, child parsers, subparser actions, default subcommands, and handler functions. This constructor sets up empty dictionaries for organizing and storing command-related data that will be populated through various methods. Args: None """ self.parent_parsers: Dict[str, argparse.ArgumentParser] = {} self.child_parsers: Dict[str, Dict[str, argparse.ArgumentParser]] = {} self.subparsers_actions: Dict[str, "argparse._SubParsersAction[Any]"] = {} self.default_subcommands: Dict[str, str] = {} self.handlers: Dict[str, Dict[Optional[str], Callable[[argparse.Namespace], None]]] = {}
[docs] def add_parent_parser(self, command: str, parser: argparse.ArgumentParser) -> None: """Adds a top-level command and its corresponding parser to the hierarchy. This method stores the parser for a top-level command (parent command) in the `parent_parsers` dictionary for later use. Args: command (str): The name of the command (e.g., 'config', 'anchor'). parser (argparse.ArgumentParser): The parser for the command. """ self.parent_parsers[command] = parser
[docs] def add_subcommand( self, command: str, subcommand: str, parser: argparse.ArgumentParser ) -> None: """Adds a subcommand and its associated parser to the hierarchy. This method stores the parser for a subcommand under the relevant command in the `child_parsers` dictionary for later use. Args: command (str): The name of the parent command (e.g., 'config'). subcommand (str): The name of the subcommand (e.g., 'get'). parser (argparse.ArgumentParser): The parser for the subcommand. """ if command not in self.child_parsers: self.child_parsers[command] = {} self.child_parsers[command][subcommand] = parser
[docs] def add_handler( self, handler: Callable[[argparse.Namespace], None], command: str, subcommand: Optional[str] = None, ) -> None: """Adds a handler function for a command or subcommand. This method stores the handler function for a given command and, if applicable, its subcommand, in the `handlers` dictionary. Args: handler (Callable[[argparse.Namespace], None]): The function that handles the command or subcommand. command (str): The name of the command (e.g., 'config'). subcommand (Optional[str]): The name of the subcommand (e.g., 'get'). If None, it is for the parent command. """ if command not in self.handlers: self.handlers[command] = {} self.handlers[command][subcommand] = handler
[docs] def add_subparsers_actions( self, command: str, actions: "argparse._SubParsersAction[Any]" ) -> None: """Adds subparser actions for a command. This method associates a command with its subparser actions, enabling the command to have subcommands that can be handled properly. Args: command (str): The name of the command. actions (argparse._SubParsersAction[Any]): The subparser actions to add for the command. """ self.subparsers_actions[command] = actions
[docs] def set_default_subcommand(self, command: str, subcommand: str) -> None: """Sets the default subcommand for a given command. This method allows for specifying a default subcommand that should be invoked if no subcommand is provided when invoking a command. Args: command (str): The name of the command (e.g., 'config'). subcommand (str): The name of the default subcommand (e.g., 'list'). """ self.default_subcommands[command] = subcommand
[docs] def get_handler( self, command: Optional[str], subcommand: Optional[str] = None ) -> Optional[Callable[[argparse.Namespace], None]]: """Retrieves the handler function for a command or subcommand. This method looks up the appropriate handler function based on the provided command and, if applicable, subcommand. Args: command (Optional[str]): The name of the command (e.g., 'config'). subcommand (Optional[str]): The name of the subcommand (e.g., 'get'). If None, it will fetch the handler for the command itself. Returns: Optional[Callable[[argparse.Namespace], None]]: The handler function, or None if not found. """ if command: return self.handlers[command][subcommand] return None
[docs] def get_parser( self, command: str, subcommand: Optional[str] = None ) -> Optional[argparse.ArgumentParser]: """Retrieves the parser for a given command and subcommand. This method looks up the parser for the specified command and subcommand. If no subcommand is given, the method returns the parser for the command itself. Args: command (str): The name of the command (e.g., 'config'). subcommand (Optional[str]): The name of the subcommand (e.g., 'get'). If None, the command's parser is returned. Returns: Optional[argparse.ArgumentParser]: The associated argument parser, or None if not found. """ if command in self.parent_parsers: if subcommand is None: # Return the top-level parser if no subcommand is given return self.parent_parsers[command] if subcommand in self.child_parsers.get(command, {}): # Return the subcommand parser if it exists return self.child_parsers[command][subcommand] return None
[docs] def get_action(self, command: str) -> "argparse._SubParsersAction[Any]": """Retrieves the subparser action for a command. This method returns the subparser action object that manages the subcommands for the specified command. Args: command (str): The name of the command. Returns: argparse._SubParsersAction[Any]: The subparser action associated with the command. """ return self.subparsers_actions[command]
@property def root_actions(self) -> "argparse._SubParsersAction[Any]": """Retrieves the root subparser actions for the CLI. This property returns the subparser action for the root command, which is used to manage top-level commands and subcommands. Returns: argparse._SubParsersAction[Any]: The root subparser action for the CLI. """ return self.subparsers_actions["__root__"]