Source code for gfw.common.cli.option

"""CLI option wrapper for argparse.

This module provides a convenient wrapper around argparse to define command-line interface
options using the :class:`Option` class. It supports automatic argument registration,
default values, and custom types, including boolean flags.
"""

import argparse

from functools import cached_property
from typing import Any, Callable


[docs] class Option: """Represents a CLI option. Provides a declarative interface to define command-line options that can be added to an :class:`argparse.ArgumentParser` instance via its :meth:`~argparse.ArgumentParser.add_argument` method. Args: *flags: One or more command-line flag strings for this option. These are passed directly to argparse's :meth:`~argparse.ArgumentParser.add_argument`. The first long flag (if any) is used to derive the internal name, which is also used as the destination (:meth:`dest`) when parsing. Three examples: .. code-block:: python Option("-c", "--config-file", ...) # Short and long form Option("--verbose", ...) # Long form only Option("-v", ...) # Short form only type: A callable that converts the command-line string to the desired Python type. Typically, a built-in type like ``str``, ``int``, ``float``, or ``bool``. default: The default value to use if the option is not provided. This should match the specified type, although no enforcement is currently done. required: We capture the required flag so we can validate it not only against command-line parameters but also against the provided config file. **kwargs: Additional keyword arguments passed directly to :meth:`~argparse.ArgumentParser.add_argument`. """ def __init__( self, *flags: str, type: Callable[..., Any], default: Any = None, required: bool = False, **kwargs: Any, ) -> None: """Initializes an Option instance.""" self.flags = flags self.type = type self.default = default self.required = required self.kwargs = kwargs if required and default is not None: raise argparse.ArgumentTypeError( f"You cannot set a default in a required argument: {self.dest}" ) @cached_property def dest(self) -> str: """Returns the internal variable name used by argparse for this option. Uses the last long flag (e.g., ``--config-file``) if present, or the first flag as a fallback. Dashes are converted to underscores for compatibility with argparse's variable naming. """ first_flag = next(iter(self.flags)).lstrip("-") last_long_flag = None for f in self.flags: if f.startswith("--"): last_long_flag = f.lstrip("-") return (last_long_flag or first_flag).replace("-", "_")