Skip to content

Cli

cli

Public CLI API for external command implementations.

CliCommand(**kwargs)

Bases: ABC

Abstract base class for CLI commands.

All CLI commands should inherit from this class and implement the run method. This design allows for easy composition of commands, particularly for batch operations.

Bind CLI kwargs to this command instance.

Parameters:

Name Type Description Default
**kwargs Any

Keyword arguments corresponding to the options declared by this command's options() classmethod.

{}
Source code in src/flepimop2/cli/_cli_command.py
def __init__(self, **kwargs: Any) -> None:
    """
    Bind CLI kwargs to this command instance.

    Args:
        **kwargs: Keyword arguments corresponding to the options declared
            by this command's `options()` classmethod.
    """
    self.bound_kwargs = dict(kwargs)

config property

Get the primary configuration path for this command, if any.

Commands that bind the shared config argument use this default implementation. Commands that use multiple configuration files or no configuration file should return None or override as needed.

target property

Get the resolved logical target for this command, if any.

Commands that do not operate on a named configuration target should use this default implementation. Target-aware commands should override this property and return the resolved configuration entry name.

__call__()

Execute this command using the kwargs bound at construction time.

Consumes 'verbosity' for logger setup. If 'verbosity' was auto-appended (not in _literal_options), it is removed from the kwargs passed to run(). The return value from run() is forwarded to sys.exit().

Source code in src/flepimop2/cli/_cli_command.py
def __call__(self) -> None:
    """
    Execute this command using the kwargs bound at construction time.

    Consumes 'verbosity' for logger setup. If 'verbosity' was
    auto-appended (not in `_literal_options`), it is removed from the
    kwargs passed to `run()`. The return value from `run()` is forwarded
    to `sys.exit()`.
    """
    kwargs = dict(self.bound_kwargs)
    verbosity = kwargs.pop("verbosity", 0)
    self.logger = get_script_logger(__name__, verbosity)
    longest_key = max((len(str(k)) for k in kwargs), default=0)
    self.debug("Given %u options/arguments:", len(kwargs))
    for key, value in kwargs.items():
        self.debug("%s = %s", key.ljust(longest_key, " "), self.format(value))
    if "verbosity" in self._literal_options():
        kwargs |= {"verbosity": verbosity}
    sys.exit(self.run(**kwargs))

__str__()

Render this command as a CLI invocation string.

Returns:

Type Description
str

The command rendered as a CLI invocation.

Source code in src/flepimop2/cli/_cli_command.py
def __str__(self) -> str:
    """Render this command as a CLI invocation string.

    Returns:
        The command rendered as a CLI invocation.
    """
    return " ".join(("flepimop2", self.command_name(), *self.to_argv()))

command_name() classmethod

Get the command name for CLI registration.

By default, converts the class name from CamelCase to kebab-case. For example, SimulateCommand -> simulate. Commands can override this method to provide a custom command name.

Returns:

Type Description
str

The command name to use in the CLI.

Source code in src/flepimop2/cli/_cli_command.py
@classmethod
def command_name(cls) -> str:
    """
    Get the command name for CLI registration.

    By default, converts the class name from CamelCase to kebab-case.
    For example, SimulateCommand -> simulate. Commands can override this
    method to provide a custom command name.

    Returns:
        The command name to use in the CLI.
    """
    return _COMMAND_NAME_REGEX.sub(
        "-", cls.__name__.removesuffix("Command")
    ).lower()

critical(*args, **kwargs)

Log a debug message.

Source code in src/flepimop2/cli/_cli_command.py
def critical(self, *args: Any, **kwargs: Any) -> None:
    """Log a debug message."""
    if self.logger is None:
        return
    self.logger.critical(*args, **kwargs)

debug(*args, **kwargs)

Log a debug message.

Source code in src/flepimop2/cli/_cli_command.py
def debug(self, *args: Any, **kwargs: Any) -> None:
    """Log a debug message."""
    if self.logger is None:
        return
    self.logger.debug(*args, **kwargs)

error(*args, **kwargs)

Log a debug message.

Source code in src/flepimop2/cli/_cli_command.py
def error(self, *args: Any, **kwargs: Any) -> None:
    """Log a debug message."""
    if self.logger is None:
        return
    self.logger.error(*args, **kwargs)

format(value) staticmethod

Format a value for logging output.

Parameters:

Name Type Description Default
value object

The value to format.

required

Returns:

Type Description
str

A string representation of the value.

Examples:

>>> from pathlib import Path
>>> from flepimop2.cli import CliCommand
>>> CliCommand.format("abc")
'abc'
>>> CliCommand.format(Path("/some/path"))
'/some/path'
>>> CliCommand.format(Path("relative/path"))
'/.../relative/path'
>>> CliCommand.format(1000000)
'1,000,000'
>>> CliCommand.format(1234.5678)
'1,234.5678'
Source code in src/flepimop2/cli/_cli_command.py
@staticmethod
def format(value: object) -> str:
    """
    Format a value for logging output.

    Args:
        value: The value to format.

    Returns:
        A string representation of the value.

    Examples:
        >>> from pathlib import Path
        >>> from flepimop2.cli import CliCommand
        >>> CliCommand.format("abc")
        'abc'
        >>> CliCommand.format(Path("/some/path"))
        '/some/path'
        >>> CliCommand.format(Path("relative/path"))
        '/.../relative/path'
        >>> CliCommand.format(1000000)
        '1,000,000'
        >>> CliCommand.format(1234.5678)
        '1,234.5678'
    """
    if isinstance(value, Path):
        return str(value.absolute())
    if isinstance(value, int | float):
        return f"{value:,}"
    return str(value)

help_text() classmethod

Get the help text for this command.

By default, extracts the help text from the class docstring. The first line becomes the short help (shown in command list), and the full docstring becomes the long help (shown in command --help).

Commands can override this method to provide custom help text.

Returns:

Type Description
str

The help text for the command.

Source code in src/flepimop2/cli/_cli_command.py
@classmethod
def help_text(cls) -> str:
    """
    Get the help text for this command.

    By default, extracts the help text from the class docstring.
    The first line becomes the short help (shown in command list),
    and the full docstring becomes the long help (shown in command --help).

    Commands can override this method to provide custom help text.

    Returns:
        The help text for the command.
    """
    return inspect.cleandoc(cls.__doc__ or "No description available.")

info(*args, **kwargs)

Log a debug message.

Source code in src/flepimop2/cli/_cli_command.py
def info(self, *args: Any, **kwargs: Any) -> None:
    """Log a debug message."""
    if self.logger is None:
        return
    self.logger.info(*args, **kwargs)

log(level, *args, **kwargs)

Log a message at the specified level.

Source code in src/flepimop2/cli/_cli_command.py
def log(self, level: int, *args: Any, **kwargs: Any) -> None:
    """Log a message at the specified level."""
    if self.logger is None:
        return
    self.logger.log(level, *args, **kwargs)

options() classmethod

Get the list of common CLI options/arguments this command uses.

By default, this method uses _literal_options() to get the keyword-only parameters from the run method. If 'verbosity' is not present and auto_append_verbosity is True, it will be automatically appended.

Commands can override this method to specify custom options that differ from the run method's parameters, or when more complex logic is needed.

The options will be applied in the order specified, with arguments typically appearing before options in the list for proper Click behavior.

Returns:

Type Description
list[str]

List of option names to request from COMMON_OPTIONS.

Examples:

>>> from flepimop2.typing import ExitCode
>>> class MyCommand(CliCommand):
...     def run(self, *, config: Path, dry_run: bool) -> ExitCode:
...         return ExitCode.OKAY
>>> MyCommand.options()
['config', 'dry_run', 'verbosity']
>>> class MyCommandWithVerbosity(CliCommand):
...     def run(
...         self, *, config: Path, verbosity: int, dry_run: bool
...     ) -> ExitCode:
...         return ExitCode.OKAY
>>> MyCommandWithVerbosity.options()
['config', 'verbosity', 'dry_run']
Source code in src/flepimop2/cli/_cli_command.py
@classmethod
def options(cls) -> list[str]:
    """
    Get the list of common CLI options/arguments this command uses.

    By default, this method uses _literal_options() to get the keyword-only
    parameters from the `run` method. If 'verbosity' is not present and
    `auto_append_verbosity` is True, it will be automatically appended.

    Commands can override this method to specify custom options that differ
    from the `run` method's parameters, or when more complex logic is needed.

    The options will be applied in the order specified, with arguments
    typically appearing before options in the list for proper Click behavior.

    Returns:
        List of option names to request from `COMMON_OPTIONS`.

    Examples:
        >>> from flepimop2.typing import ExitCode
        >>> class MyCommand(CliCommand):
        ...     def run(self, *, config: Path, dry_run: bool) -> ExitCode:
        ...         return ExitCode.OKAY
        >>> MyCommand.options()
        ['config', 'dry_run', 'verbosity']

        >>> class MyCommandWithVerbosity(CliCommand):
        ...     def run(
        ...         self, *, config: Path, verbosity: int, dry_run: bool
        ...     ) -> ExitCode:
        ...         return ExitCode.OKAY
        >>> MyCommandWithVerbosity.options()
        ['config', 'verbosity', 'dry_run']
    """
    options = cls._literal_options()
    if cls.auto_append_verbosity and "verbosity" not in options:
        options.append("verbosity")
    return options

run(**kwargs) abstractmethod

Execute the command.

Parameters:

Name Type Description Default
**kwargs Any

Command-specific arguments passed from Click options/arguments.

{}
Source code in src/flepimop2/cli/_cli_command.py
@abstractmethod
def run(self, **kwargs: Any) -> ExitCode:
    """
    Execute the command.

    Args:
        **kwargs: Command-specific arguments passed from Click options/arguments.
    """
    raise NotImplementedError

to_argv()

Render this instance's bound kwargs back into argv tokens.

Walks cls.options() in declaration order and converts each bound value to its CLI representation:

  • click.Argument: bare positional string (skipped if None).
  • click.Option with is_flag=True: long flag name when truthy, omitted when falsy.
  • click.Option with count=True: repeated short flag (e.g. -vvv for verbosity=3).
  • click.Option otherwise: --name value pair.

Path values are rendered as their absolute string form so the resulting argv replays correctly on a remote with a shared filesystem.

Returns:

Type Description
list[str]

A list of string tokens suitable for passing to subprocess.

Source code in src/flepimop2/cli/_cli_command.py
def to_argv(self) -> list[str]:
    """Render this instance's bound kwargs back into argv tokens.

    Walks `cls.options()` in declaration order and converts each bound
    value to its CLI representation:

    - `click.Argument`: bare positional string (skipped if `None`).
    - `click.Option` with `is_flag=True`: long flag name when truthy, omitted when
        falsy.
    - `click.Option` with `count=True`: repeated short flag
        (e.g. `-vvv` for `verbosity=3`).
    - `click.Option` otherwise: `--name value` pair.

    `Path` values are rendered as their absolute string form so the
    resulting argv replays correctly on a remote with a shared filesystem.

    Returns:
        A list of string tokens suitable for passing to `subprocess`.
    """
    tokens: list[str] = []
    for name in type(self).options():
        entry = COMMON_OPTIONS.get(name)
        if entry is None:
            continue
        param = _click_param_for_option(entry[0])
        if param is None:
            continue
        tokens.extend(_render_param(param, self.bound_kwargs.get(name)))
    return tokens

warning(*args, **kwargs)

Log a debug message.

Source code in src/flepimop2/cli/_cli_command.py
def warning(self, *args: Any, **kwargs: Any) -> None:
    """Log a debug message."""
    if self.logger is None:
        return
    self.logger.warning(*args, **kwargs)