Skip to content

toolr._registry

CommandGroup

Bases: Struct

A group of commands under a common namespace.

full_name property

full_name: str

Get the full dot-notation name of this command group.

command

command(name: F) -> F
command(name: str) -> Callable[[F], F]
command(name: str | F) -> Callable[[F], F] | F

Register a new command.

Parameters:

Name Type Description Default
name str | F

Name of the command. If not passed, the function name will be used.

required

Returns:

Type Description
Callable[[F], F] | F

A decorator function that registers the command

Source code in python/toolr/_registry.py
def command(self, name: str | F) -> Callable[[F], F] | F:
    """Register a new command.

    Args:
        name: Name of the command. If not passed, the function name will be used.

    Returns:
        A decorator function that registers the command
    """
    if isinstance(name, FunctionType):
        # If we were not passed a name in the decorator call, we're being called with a function
        # and we need to use the function name as the command name
        return self.command(name.__name__.replace("_", "-"))(name)

    if TYPE_CHECKING:
        assert isinstance(name, str)

    def decorator(func: F) -> F:
        if name in self.__commands:
            log.debug("Command '%s' already exists in group '%s', overriding", name, self.full_name)
        self.__commands[name] = func
        return func

    return decorator

command_group

command_group(
    name: str,
    title: str,
    description: str | None = None,
    long_description: str | None = None,
    docstring: str | None = None,
) -> CommandGroup

Create a nested command group within this group.

This is a wrapper around the command_group function that sets the parent to this group's full name.

Returns:

Type Description
CommandGroup

A CommandGroup instance

Source code in python/toolr/_registry.py
def command_group(
    self,
    name: str,
    title: str,
    description: str | None = None,
    long_description: str | None = None,
    docstring: str | None = None,
) -> CommandGroup:
    """Create a nested command group within this group.

    This is a wrapper around the [command_group][toolr._registry.command_group] function
    that sets the parent to this group's full name.

    Returns:
        A CommandGroup instance
    """
    return command_group(
        name,
        title,
        description=description,
        parent=self.full_name,
        long_description=long_description,
        docstring=docstring,
    )

get_commands

get_commands() -> dict[str, Callable[..., Any]]

Get the commands in this group.

Source code in python/toolr/_registry.py
def get_commands(self) -> dict[str, Callable[..., Any]]:
    """Get the commands in this group."""
    return {name: self.__commands[name] for name in sorted(self.__commands)}

CommandRegistry

Bases: Struct

Registry for CLI commands and their subcommands.

parser property

parser: Parser

Get the parser for this registry.

discover_and_build

discover_and_build(parser: Parser | None = None) -> None

Discover all commands and build the parser hierarchy.

Source code in python/toolr/_registry.py
def discover_and_build(self, parser: Parser | None = None) -> None:
    """Discover all commands and build the parser hierarchy."""
    if parser is not None:
        self._set_parser(parser)
    self._discover_commands()
    self._build_parsers()

command_group

command_group(
    name: str,
    title: str,
    description: str | None = None,
    long_description: str | None = None,
    docstring: str | None = None,
    parent: str | None = None,
) -> CommandGroup

Register a new command group.

If you pass docstring, you won't be allowed to pass description or long_description. Those will be parsed by docstring-parser. The first line of the docstring will be used as the description, the rest will be used as the long description.

Parameters:

Name Type Description Default
name str

Name of the command group

required
title str

Title for the command group

required
description str | None

Description for the command group

None
long_description str | None

Long description for the command group

None
docstring str | None

Docstring for the command group

None
parent str | None

Optional parent command path using dot notation (e.g. "tools.docker.build")

None

Returns:

Type Description
CommandGroup

A CommandGroup instance

Source code in python/toolr/_registry.py
def command_group(
    name: str,
    title: str,
    description: str | None = None,
    long_description: str | None = None,
    docstring: str | None = None,
    parent: str | None = None,
) -> CommandGroup:
    """Register a new command group.

    If you pass ``docstring``, you won't be allowed to pass ``description`` or ``long_description``.
    Those will be parsed by [docstring-parser](https://pypi.org/project/docstring-parser/).
    The first line of the docstring will be used as the description, the rest will be used as the long description.

    Args:
        name: Name of the command group
        title: Title for the command group
        description: Description for the command group
        long_description: Long description for the command group
        docstring: Docstring for the command group
        parent: Optional parent command path using dot notation (e.g. "tools.docker.build")

    Returns:
        A CommandGroup instance

    """
    if parent is None:
        parent = "tools"

    collector = _get_command_group_storage()

    group: CommandGroup | None = collector.get(f"{parent}.{name}")
    if group is not None:
        # In this case, we return the existing group
        log.debug("Command group '%s' already exists, returning existing group", f"{parent}.{name}")
        return group

    if docstring is not None:
        if description is not None or long_description is not None:
            err_msg = "You can't pass both docstring and description or long_description"
            raise ValueError(err_msg)
        parsed_docstring = parse_docstring(docstring)
        description = parsed_docstring.short_description
        long_description = parsed_docstring.long_description
    elif description is None:
        err_msg = "You must at least pass either the 'docstring' or 'description' argument"
        raise ValueError(err_msg)

    if TYPE_CHECKING:
        assert description is not None

    # Create the command group
    collector[f"{parent}.{name}"] = group = CommandGroup(
        name=name,
        title=title,
        description=description,
        parent=parent,
        long_description=long_description,
    )
    return group