Skip to content

ArgUtils

Module: terminaltexteffects.utils.argutils

Command line argument validators and METAVARs for consistent type parsing and help output.

This module includes a custom formatter for argparse, which combines the features of argparse.ArgumentDefaultsHelpFormatter and argparse.RawDescriptionHelpFormatter.

Classes:

Name Description
CustomFormatter

A custom formatter for argparse that combines the features of argparse.ArgumentDefaultsHelpFormatter and argparse.RawDescriptionHelpFormatter.

CharacterGroup

An enum specifying character groupings.

CharacterGroupArg

Argument type for character groupings.

CharacterSort

An enum specifying character sorts.

CharacterSortArg

Argument type for character sorts.

CharacterOrder

Unified spatial grouping and individual traversal options.

CharacterOrderArg

Argument type normalizing character orders and compatibility enums.

CharacterGroupOrSortArg

Argument type accepting character groups or sorts.

ColorSort

An enum specifying color sorts.

ColorSortArg

Argument type for color sorts.

TupleAction

Custom argparse action to convert a list of values into a tuple.

ParserSpec

Specification for a parser in the argument parser.

ArgSpec

Specification for a command-line argument and default value.

GradientDirection

Argument type for gradient directions.

ColorArg

Argument type for color values.

Symbol

Argument type for single ASCII/UTF-8 characters.

Ease

Argument type for easing functions.

PositiveInt

Argument type for positive integers.

NonNegativeInt

Argument type for nonnegative integers.

PositiveIntRange

Argument type for integer ranges.

PositiveFloat

Argument type for positive floats.

NonNegativeFloat

Argument type for nonnegative floats.

PositiveFloatRange

Argument type for float ranges.

TerminalDimension

Argument type for terminal dimensions.

CanvasDimension

Argument type for canvas dimensions.

NonNegativeRatio

Argument type for float values between zero and one.

PositiveRatio

Argument type for positive float values greater than zero and less than or equal to one.

EasingStep

Argument type for easing step size values.

Constants

EASING_EPILOG (str): A detailed description of the easing functions supported.

ArgSpec dataclass

Specification for a command-line argument and config default value.

Non-missing fields map directly to keyword arguments for argparse.ArgumentParser.add_argument(). The default value is also used by BaseConfig._build_config() when constructing configs without parsed CLI input.

The type callable is the normalization contract shared by CLI parsing and library configuration. Custom callables must accept both CLI strings and values that are already in their canonical library form.

default_formatter, when supplied, formats the canonical default for CLI help text only. It does not affect parsing or configuration construction.

Source code in terminaltexteffects/utils/argutils.py
@dataclass(frozen=True)
class ArgSpec:
    """Specification for a command-line argument and config default value.

    Non-missing fields map directly to keyword arguments for
    `argparse.ArgumentParser.add_argument()`. The `default` value is also used by
    `BaseConfig._build_config()` when constructing configs without parsed CLI input.

    The `type` callable is the normalization contract shared by CLI parsing and
    library configuration. Custom callables must accept both CLI strings and
    values that are already in their canonical library form.

    `default_formatter`, when supplied, formats the canonical default for CLI
    help text only. It does not affect parsing or configuration construction.
    """

    name: str
    default: typing.Any
    metavar: str = _MISSING  # type: ignore[arg-type]
    type: typing.Any = _MISSING  # type: ignore[arg-type]
    required: bool = _MISSING  # type: ignore[arg-type]
    help: str = _MISSING  # type: ignore[arg-type]
    action: str | type[argparse.Action] = _MISSING  # type: ignore[arg-type]
    choices: list[typing.Any] = _MISSING  # type: ignore[arg-type]
    nargs: str | int = _MISSING  # type: ignore[arg-type]
    default_formatter: typing.Callable[[typing.Any], str] = _MISSING  # type: ignore[assignment]

    def normalize(self, value: typing.Any) -> typing.Any:
        """Normalize and validate a configuration value described by this spec.

        Explicit sequences for a `TupleAction` with `nargs="+"` must contain
        at least one value. Scalar values remain valid for library callers.
        """
        if self.action == "store_true":
            if not isinstance(value, bool):
                msg = f"invalid value: '{value}' must be a boolean."
                raise argparse.ArgumentTypeError(msg)
            return value

        values = value if self.action is TupleAction and isinstance(value, (list, tuple)) else (value,)
        if self.action is TupleAction:
            if self.nargs == "+" and not values:
                msg = f"invalid value: '{value}' must contain at least one value."
                raise argparse.ArgumentTypeError(msg)
            return tuple(self._normalize_scalar(item) for item in values)
        return self._normalize_scalar(value)

    def _normalize_scalar(self, value: typing.Any) -> typing.Any:
        normalized = self.type(value) if self.type is not _MISSING else value
        if self.choices is not _MISSING and normalized not in self.choices:
            msg = f"invalid choice: '{normalized}' (choose from {', '.join(map(str, self.choices))})"
            raise argparse.ArgumentTypeError(msg)
        return normalized

normalize(value)

Normalize and validate a configuration value described by this spec.

Explicit sequences for a TupleAction with nargs="+" must contain at least one value. Scalar values remain valid for library callers.

Source code in terminaltexteffects/utils/argutils.py
def normalize(self, value: typing.Any) -> typing.Any:
    """Normalize and validate a configuration value described by this spec.

    Explicit sequences for a `TupleAction` with `nargs="+"` must contain
    at least one value. Scalar values remain valid for library callers.
    """
    if self.action == "store_true":
        if not isinstance(value, bool):
            msg = f"invalid value: '{value}' must be a boolean."
            raise argparse.ArgumentTypeError(msg)
        return value

    values = value if self.action is TupleAction and isinstance(value, (list, tuple)) else (value,)
    if self.action is TupleAction:
        if self.nargs == "+" and not values:
            msg = f"invalid value: '{value}' must contain at least one value."
            raise argparse.ArgumentTypeError(msg)
        return tuple(self._normalize_scalar(item) for item in values)
    return self._normalize_scalar(value)

CanvasDimension

Validate argument is a nonnegative integer or -1.

Raises:

Type Description
ArgumentTypeError

Value is not a valid canvas dimension.

Source code in terminaltexteffects/utils/argutils.py
class CanvasDimension:
    """Validate argument is a nonnegative integer or `-1`.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid canvas dimension.

    """

    METAVAR = "int >= -1"

    @staticmethod
    def type_parser(arg: str | int) -> int:
        """Validate argument is a nonnegative integer or `-1`.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not a valid canvas dimension.

        Returns:
            int: validated canvas dimension

        """
        if isinstance(arg, int) and not isinstance(arg, bool) and arg >= -1:
            return arg
        if isinstance(arg, str) and (arg.isdigit() or arg == "-1"):
            return int(arg)
        msg = f"invalid value '{arg}' is not a valid integer. Must be >= -1."
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a nonnegative integer or -1.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not a valid canvas dimension.

Returns:

Name Type Description
int int

validated canvas dimension

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | int) -> int:
    """Validate argument is a nonnegative integer or `-1`.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not a valid canvas dimension.

    Returns:
        int: validated canvas dimension

    """
    if isinstance(arg, int) and not isinstance(arg, bool) and arg >= -1:
        return arg
    if isinstance(arg, str) and (arg.isdigit() or arg == "-1"):
        return int(arg)
    msg = f"invalid value '{arg}' is not a valid integer. Must be >= -1."
    raise argparse.ArgumentTypeError(msg)

CharacterGroup

Bases: Enum

Specify character groupings based on immutable input coordinates.

DIAMONDS_CENTER_TO_OUTSIDE and DIAMONDS_OUTSIDE_TO_CENTER use Manhattan distance from the text's lower central cell. The CIRCLE_* options use one-column-wide radial bands around the text's geometric midpoint, accounting for terminal cell height. Retained for compatibility; use CharacterOrder for new ordering configurations.

Source code in terminaltexteffects/utils/argutils.py
class CharacterGroup(Enum):
    """Specify character groupings based on immutable input coordinates.

    `DIAMONDS_CENTER_TO_OUTSIDE` and `DIAMONDS_OUTSIDE_TO_CENTER` use Manhattan distance from the
    text's lower central cell. The `CIRCLE_*` options use one-column-wide radial
    bands around the text's geometric midpoint, accounting for terminal cell height.
    Retained for compatibility; use `CharacterOrder` for new ordering configurations.
    """

    COLUMN_LEFT_TO_RIGHT = auto()
    COLUMN_RIGHT_TO_LEFT = auto()
    ROW_TOP_TO_BOTTOM = auto()
    ROW_BOTTOM_TO_TOP = auto()
    DIAGONAL_TOP_LEFT_TO_BOTTOM_RIGHT = auto()
    DIAGONAL_BOTTOM_LEFT_TO_TOP_RIGHT = auto()
    DIAGONAL_TOP_RIGHT_TO_BOTTOM_LEFT = auto()
    DIAGONAL_BOTTOM_RIGHT_TO_TOP_LEFT = auto()
    DIAMONDS_CENTER_TO_OUTSIDE = auto()
    DIAMONDS_OUTSIDE_TO_CENTER = auto()
    CIRCLE_CENTER_TO_OUTSIDE = auto()
    CIRCLE_OUTSIDE_TO_CENTER = auto()

    # Preserve existing API names without advertising them as canonical CLI choices.
    CENTER_TO_OUTSIDE = DIAMONDS_CENTER_TO_OUTSIDE
    OUTSIDE_TO_CENTER = DIAMONDS_OUTSIDE_TO_CENTER

CharacterGroupArg

Validate argument is a valid CharacterGroup.

Raises:

Type Description
ArgumentTypeError

Value is not a valid CharacterGroup.

Source code in terminaltexteffects/utils/argutils.py
class CharacterGroupArg:
    """Validate argument is a valid CharacterGroup.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid CharacterGroup.

    """

    COMPLETION_CHOICES = tuple(n.lower() for n in CharacterGroup._member_names_)
    METAVAR = COMPLETION_CHOICES

    @staticmethod
    def type_parser(arg: str | CharacterGroup) -> CharacterGroup:
        """Validate argument is a valid CharacterGroup.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not a valid CharacterGroup.

        Returns:
            CharacterGroup: validated CharacterGroup

        """
        if isinstance(arg, CharacterGroup):
            return arg
        try:
            return CharacterGroup[arg.upper()]
        except (AttributeError, KeyError):
            msg = f"invalid CharacterGroup: '{arg}' is not a valid CharacterGroup."
            raise argparse.ArgumentTypeError(msg) from None

type_parser(arg) staticmethod

Validate argument is a valid CharacterGroup.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not a valid CharacterGroup.

Returns:

Name Type Description
CharacterGroup CharacterGroup

validated CharacterGroup

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | CharacterGroup) -> CharacterGroup:
    """Validate argument is a valid CharacterGroup.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not a valid CharacterGroup.

    Returns:
        CharacterGroup: validated CharacterGroup

    """
    if isinstance(arg, CharacterGroup):
        return arg
    try:
        return CharacterGroup[arg.upper()]
    except (AttributeError, KeyError):
        msg = f"invalid CharacterGroup: '{arg}' is not a valid CharacterGroup."
        raise argparse.ArgumentTypeError(msg) from None

CharacterGroupOrSortArg

Validate a CharacterGroup or CharacterSort ordering choice.

Source code in terminaltexteffects/utils/argutils.py
class CharacterGroupOrSortArg:
    """Validate a `CharacterGroup` or `CharacterSort` ordering choice."""

    COMPLETION_CHOICES = (*CharacterGroupArg.COMPLETION_CHOICES, *CharacterSortArg.COMPLETION_CHOICES)
    METAVAR = COMPLETION_CHOICES

    @staticmethod
    def type_parser(arg: str | CharacterGroup | CharacterSort) -> CharacterGroup | CharacterSort:
        """Accept case-insensitive CLI names or canonical group/sort enum values.

        Args:
            arg (str | CharacterGroup | CharacterSort): Ordering choice to normalize.

        Returns:
            CharacterGroup | CharacterSort: The selected grouping or sorting enum.

        Raises:
            argparse.ArgumentTypeError: If `arg` is not a valid group or sort.

        """
        if isinstance(arg, (CharacterGroup, CharacterSort)):
            return arg
        if isinstance(arg, str):
            name = arg.upper()
            for enum_type in (CharacterGroup, CharacterSort):
                member = enum_type.__members__.get(name)
                if member is not None:
                    return member
        msg = f"invalid character order: '{arg}' is not a valid CharacterGroup or CharacterSort."
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Accept case-insensitive CLI names or canonical group/sort enum values.

Parameters:

Name Type Description Default
arg str | CharacterGroup | CharacterSort

Ordering choice to normalize.

required

Returns:

Type Description
CharacterGroup | CharacterSort

CharacterGroup | CharacterSort: The selected grouping or sorting enum.

Raises:

Type Description
ArgumentTypeError

If arg is not a valid group or sort.

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | CharacterGroup | CharacterSort) -> CharacterGroup | CharacterSort:
    """Accept case-insensitive CLI names or canonical group/sort enum values.

    Args:
        arg (str | CharacterGroup | CharacterSort): Ordering choice to normalize.

    Returns:
        CharacterGroup | CharacterSort: The selected grouping or sorting enum.

    Raises:
        argparse.ArgumentTypeError: If `arg` is not a valid group or sort.

    """
    if isinstance(arg, (CharacterGroup, CharacterSort)):
        return arg
    if isinstance(arg, str):
        name = arg.upper()
        for enum_type in (CharacterGroup, CharacterSort):
            member = enum_type.__members__.get(name)
            if member is not None:
                return member
    msg = f"invalid character order: '{arg}' is not a valid CharacterGroup or CharacterSort."
    raise argparse.ArgumentTypeError(msg)

CharacterOrder

Bases: Enum

Specify ordered spatial groups or individual character traversal.

Spatial options retain their original group boundaries and internal ordering. Individual traversal options, including spirals and random order, produce singleton groups. Flattening either form yields its complete character traversal.

Source code in terminaltexteffects/utils/argutils.py
class CharacterOrder(Enum):
    """Specify ordered spatial groups or individual character traversal.

    Spatial options retain their original group boundaries and internal ordering.
    Individual traversal options, including spirals and random order, produce singleton
    groups. Flattening either form yields its complete character traversal.
    """

    COLUMN_LEFT_TO_RIGHT = auto()
    COLUMN_RIGHT_TO_LEFT = auto()
    ROW_TOP_TO_BOTTOM = auto()
    ROW_BOTTOM_TO_TOP = auto()
    DIAGONAL_TOP_LEFT_TO_BOTTOM_RIGHT = auto()
    DIAGONAL_BOTTOM_LEFT_TO_TOP_RIGHT = auto()
    DIAGONAL_TOP_RIGHT_TO_BOTTOM_LEFT = auto()
    DIAGONAL_BOTTOM_RIGHT_TO_TOP_LEFT = auto()
    DIAMONDS_CENTER_TO_OUTSIDE = auto()
    DIAMONDS_OUTSIDE_TO_CENTER = auto()
    CIRCLE_CENTER_TO_OUTSIDE = auto()
    CIRCLE_OUTSIDE_TO_CENTER = auto()
    RANDOM = auto()
    TOP_TO_BOTTOM_LEFT_TO_RIGHT = auto()
    TOP_TO_BOTTOM_RIGHT_TO_LEFT = auto()
    BOTTOM_TO_TOP_LEFT_TO_RIGHT = auto()
    BOTTOM_TO_TOP_RIGHT_TO_LEFT = auto()
    OUTSIDE_ROW_TO_MIDDLE = auto()
    MIDDLE_ROW_TO_OUTSIDE = auto()
    SPIRAL_CLOCKWISE = auto()
    SPIRAL_COUNTER_CLOCKWISE = auto()
    SPIRAL_CLOCKWISE_DOUBLE = auto()
    SPIRAL_COUNTER_CLOCKWISE_DOUBLE = auto()
    SPIRAL_CLOCKWISE_QUAD = auto()
    SPIRAL_COUNTER_CLOCKWISE_QUAD = auto()

    CENTER_TO_OUTSIDE = DIAMONDS_CENTER_TO_OUTSIDE
    OUTSIDE_TO_CENTER = DIAMONDS_OUTSIDE_TO_CENTER

    @property
    def is_grouped(self) -> bool:
        """Whether this order has spatial groups rather than singleton entries."""
        return self.name in CharacterGroup.__members__

is_grouped property

Whether this order has spatial groups rather than singleton entries.

CharacterOrderArg

Normalize character orders, including legacy group and sort values.

Source code in terminaltexteffects/utils/argutils.py
class CharacterOrderArg:
    """Normalize character orders, including legacy group and sort values."""

    COMPLETION_CHOICES = tuple(member.name.lower() for member in CharacterOrder)
    METAVAR = COMPLETION_CHOICES

    @staticmethod
    def type_parser(arg: str | CharacterOrder | CharacterGroup | CharacterSort) -> CharacterOrder:
        """Accept CLI names, `CharacterOrder`, and compatibility enum values.

        Args:
            arg (str | CharacterOrder | CharacterGroup | CharacterSort): Traversal choice.

        Returns:
            CharacterOrder: The canonical character order.

        Raises:
            argparse.ArgumentTypeError: If the value is not a valid character order.

        """
        if isinstance(arg, CharacterOrder):
            return arg
        if isinstance(arg, (CharacterGroup, CharacterSort)):
            return CharacterOrder[arg.name]
        if isinstance(arg, str):
            member = CharacterOrder.__members__.get(arg.upper())
            if member is not None:
                return member
        msg = f"invalid character order: '{arg}' is not a valid CharacterOrder."
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Accept CLI names, CharacterOrder, and compatibility enum values.

Parameters:

Name Type Description Default
arg str | CharacterOrder | CharacterGroup | CharacterSort

Traversal choice.

required

Returns:

Name Type Description
CharacterOrder CharacterOrder

The canonical character order.

Raises:

Type Description
ArgumentTypeError

If the value is not a valid character order.

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | CharacterOrder | CharacterGroup | CharacterSort) -> CharacterOrder:
    """Accept CLI names, `CharacterOrder`, and compatibility enum values.

    Args:
        arg (str | CharacterOrder | CharacterGroup | CharacterSort): Traversal choice.

    Returns:
        CharacterOrder: The canonical character order.

    Raises:
        argparse.ArgumentTypeError: If the value is not a valid character order.

    """
    if isinstance(arg, CharacterOrder):
        return arg
    if isinstance(arg, (CharacterGroup, CharacterSort)):
        return CharacterOrder[arg.name]
    if isinstance(arg, str):
        member = CharacterOrder.__members__.get(arg.upper())
        if member is not None:
            return member
    msg = f"invalid character order: '{arg}' is not a valid CharacterOrder."
    raise argparse.ArgumentTypeError(msg)

CharacterSort

Bases: Enum

Specify character ordering based on immutable input coordinates.

The outside/middle options order complete rows by distance from the selected rows' vertical midpoint, retain left-to-right order within a row, and place the top row first when two rows are equally distant from the midpoint.

Spiral options wind inward through rectangular rings of the selected input coordinates' bounding box. Single spirals start at top-left, double spirals at top-left and bottom-right, and quad spirals at all four corners. Multiple arms are interleaved by distance traveled around each ring. Retained for compatibility; use CharacterOrder for new ordering configurations.

Source code in terminaltexteffects/utils/argutils.py
class CharacterSort(Enum):
    """Specify character ordering based on immutable input coordinates.

    The outside/middle options order complete rows by distance from the selected
    rows' vertical midpoint, retain left-to-right order within a row, and place the
    top row first when two rows are equally distant from the midpoint.

    Spiral options wind inward through rectangular rings of the selected input
    coordinates' bounding box. Single spirals start at top-left, double spirals
    at top-left and bottom-right, and quad spirals at all four corners. Multiple
    arms are interleaved by distance traveled around each ring.
    Retained for compatibility; use `CharacterOrder` for new ordering configurations.
    """

    RANDOM = auto()
    TOP_TO_BOTTOM_LEFT_TO_RIGHT = auto()
    TOP_TO_BOTTOM_RIGHT_TO_LEFT = auto()
    BOTTOM_TO_TOP_LEFT_TO_RIGHT = auto()
    BOTTOM_TO_TOP_RIGHT_TO_LEFT = auto()
    OUTSIDE_ROW_TO_MIDDLE = auto()
    MIDDLE_ROW_TO_OUTSIDE = auto()
    SPIRAL_CLOCKWISE = auto()
    SPIRAL_COUNTER_CLOCKWISE = auto()
    SPIRAL_CLOCKWISE_DOUBLE = auto()
    SPIRAL_COUNTER_CLOCKWISE_DOUBLE = auto()
    SPIRAL_CLOCKWISE_QUAD = auto()
    SPIRAL_COUNTER_CLOCKWISE_QUAD = auto()

CharacterSortArg

Validate argument is a valid CharacterSort.

Raises:

Type Description
ArgumentTypeError

Value is not a valid CharacterSort.

Source code in terminaltexteffects/utils/argutils.py
class CharacterSortArg:
    """Validate argument is a valid CharacterSort.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid CharacterSort.

    """

    COMPLETION_CHOICES = tuple(n.lower() for n in CharacterSort._member_names_)
    METAVAR = COMPLETION_CHOICES

    @staticmethod
    def type_parser(arg: str | CharacterSort) -> CharacterSort:
        """Validate argument is a valid CharacterSort.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not a valid CharacterSort.

        Returns:
            CharacterSort: validated CharacterSort

        """
        if isinstance(arg, CharacterSort):
            return arg
        try:
            return CharacterSort[arg.upper()]
        except (AttributeError, KeyError):
            msg = f"invalid CharacterSort: '{arg}' is not a valid CharacterSort."
            raise argparse.ArgumentTypeError(msg) from None

type_parser(arg) staticmethod

Validate argument is a valid CharacterSort.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not a valid CharacterSort.

Returns:

Name Type Description
CharacterSort CharacterSort

validated CharacterSort

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | CharacterSort) -> CharacterSort:
    """Validate argument is a valid CharacterSort.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not a valid CharacterSort.

    Returns:
        CharacterSort: validated CharacterSort

    """
    if isinstance(arg, CharacterSort):
        return arg
    try:
        return CharacterSort[arg.upper()]
    except (AttributeError, KeyError):
        msg = f"invalid CharacterSort: '{arg}' is not a valid CharacterSort."
        raise argparse.ArgumentTypeError(msg) from None

ColorArg

Validate argument is a valid color value.

Color values can be either an XTerm color value (0-255) or an RGB hex value (000000-ffffff).

Raises:

Type Description
ArgumentTypeError

Value is not in range of valid XTerm colors or RGB hex colors.

Source code in terminaltexteffects/utils/argutils.py
class ColorArg:
    """Validate argument is a valid color value.

    Color values can be either an XTerm color value (0-255) or an RGB hex value (000000-ffffff).

    Raises:
        argparse.ArgumentTypeError: Value is not in range of valid XTerm colors or RGB hex colors.

    """

    METAVAR = "(XTerm [0-255] OR RGB Hex [000000-ffffff])"

    @staticmethod
    def type_parser(arg: str | int | Color) -> Color:
        """Validate argument is a valid color value.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Color value is not in range.

        Returns:
            Color : validated color value

        """
        if isinstance(arg, Color):
            return arg
        if isinstance(arg, bool) or not isinstance(arg, (str, int)):
            msg = (
                f"invalid color value: '{arg}' is not a valid XTerm or RGB color."
                " Must be in range 0-255 or 000000-FFFFFF."
            )
            raise argparse.ArgumentTypeError(msg)
        try:
            return Color(int(arg)) if isinstance(arg, int) or len(arg) <= 3 else Color(arg)
        except (TypeError, ValueError):
            msg = (
                f"invalid color value: '{arg}' is not a valid XTerm or RGB color."
                " Must be in range 0-255 or 000000-FFFFFF."
            )
            raise argparse.ArgumentTypeError(msg) from None

type_parser(arg) staticmethod

Validate argument is a valid color value.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Color value is not in range.

Returns:

Name Type Description
Color Color

validated color value

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | int | Color) -> Color:
    """Validate argument is a valid color value.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Color value is not in range.

    Returns:
        Color : validated color value

    """
    if isinstance(arg, Color):
        return arg
    if isinstance(arg, bool) or not isinstance(arg, (str, int)):
        msg = (
            f"invalid color value: '{arg}' is not a valid XTerm or RGB color."
            " Must be in range 0-255 or 000000-FFFFFF."
        )
        raise argparse.ArgumentTypeError(msg)
    try:
        return Color(int(arg)) if isinstance(arg, int) or len(arg) <= 3 else Color(arg)
    except (TypeError, ValueError):
        msg = (
            f"invalid color value: '{arg}' is not a valid XTerm or RGB color."
            " Must be in range 0-255 or 000000-FFFFFF."
        )
        raise argparse.ArgumentTypeError(msg) from None

ColorSort

Bases: Enum

An enum for specifying color sorts for the colors derived from the input text ansi sequences.

Source code in terminaltexteffects/utils/argutils.py
class ColorSort(Enum):
    """An enum for specifying color sorts for the colors derived from the input text ansi sequences."""

    LEAST_TO_MOST = auto()
    MOST_TO_LEAST = auto()
    RANDOM = auto()

ColorSortArg

Validate argument is a valid ColorSort.

Raises:

Type Description
ArgumentTypeError

Value is not a valid ColorSort.

Source code in terminaltexteffects/utils/argutils.py
class ColorSortArg:
    """Validate argument is a valid ColorSort.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid ColorSort.

    """

    COMPLETION_CHOICES = tuple(n.lower() for n in ColorSort._member_names_)
    METAVAR = COMPLETION_CHOICES

    @staticmethod
    def type_parser(arg: str | ColorSort) -> ColorSort:
        """Validate argument is a valid ColorSort.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not a valid ColorSort.

        Returns:
            ColorSort: validated ColorSort

        """
        if isinstance(arg, ColorSort):
            return arg
        try:
            return ColorSort[arg.upper()]
        except (AttributeError, KeyError):
            msg = f"invalid ColorSort: '{arg}' is not a valid ColorSort."
            raise argparse.ArgumentTypeError(msg) from None

type_parser(arg) staticmethod

Validate argument is a valid ColorSort.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not a valid ColorSort.

Returns:

Name Type Description
ColorSort ColorSort

validated ColorSort

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | ColorSort) -> ColorSort:
    """Validate argument is a valid ColorSort.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not a valid ColorSort.

    Returns:
        ColorSort: validated ColorSort

    """
    if isinstance(arg, ColorSort):
        return arg
    try:
        return ColorSort[arg.upper()]
    except (AttributeError, KeyError):
        msg = f"invalid ColorSort: '{arg}' is not a valid ColorSort."
        raise argparse.ArgumentTypeError(msg) from None

CustomFormatter

Bases: ArgumentDefaultsHelpFormatter, RawDescriptionHelpFormatter

Combine ArgumentDefaultsHelpFormatter and RawDescriptionHelpFormatter for argparse.

Source code in terminaltexteffects/utils/argutils.py
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
    """Combine ArgumentDefaultsHelpFormatter and RawDescriptionHelpFormatter for argparse."""

    def _get_help_string(self, action: argparse.Action) -> str:
        """Return help text with defaults rendered as command-line values."""
        help_string = super()._get_help_string(action) or ""
        default_formatter = getattr(action, "default_formatter", None)
        if default_formatter is None:
            default_value = format_cli_default(action.default, action.type)
        else:
            default_value = default_formatter(action.default)
        default_value = default_value.replace("%", "%%")
        return help_string.replace("%(default)s", default_value)

Ease

Validate argument is a valid easing function.

Easing functions are prefixed by "in", "out", or "in_out" and suffixed by a valid easing function.

Raises:

Type Description
ArgumentTypeError

Value is not a valid easing function.

Source code in terminaltexteffects/utils/argutils.py
class Ease:
    """Validate argument is a valid easing function.

    Easing functions are prefixed by "in", "out", or "in_out" and suffixed by a valid easing function.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid easing function.

    """

    METAVAR = "(Easing Function)"
    _FUNCTION_MAP: typing.ClassVar[dict[str, easing.EasingFunction]] = {
        "linear": easing.linear,
        "in_sine": easing.in_sine,
        "out_sine": easing.out_sine,
        "in_out_sine": easing.in_out_sine,
        "in_quad": easing.in_quad,
        "out_quad": easing.out_quad,
        "in_out_quad": easing.in_out_quad,
        "in_cubic": easing.in_cubic,
        "out_cubic": easing.out_cubic,
        "in_out_cubic": easing.in_out_cubic,
        "in_quart": easing.in_quart,
        "out_quart": easing.out_quart,
        "in_out_quart": easing.in_out_quart,
        "in_quint": easing.in_quint,
        "out_quint": easing.out_quint,
        "in_out_quint": easing.in_out_quint,
        "in_expo": easing.in_expo,
        "out_expo": easing.out_expo,
        "in_out_expo": easing.in_out_expo,
        "in_circ": easing.in_circ,
        "out_circ": easing.out_circ,
        "in_out_circ": easing.in_out_circ,
        "in_back": easing.in_back,
        "out_back": easing.out_back,
        "in_out_back": easing.in_out_back,
        "in_elastic": easing.in_elastic,
        "out_elastic": easing.out_elastic,
        "in_out_elastic": easing.in_out_elastic,
        "in_bounce": easing.in_bounce,
        "out_bounce": easing.out_bounce,
        "in_out_bounce": easing.in_out_bounce,
    }
    COMPLETION_CHOICES: typing.ClassVar[tuple[str, ...]] = tuple(_FUNCTION_MAP)

    @staticmethod
    def type_parser(arg: str | typing.Callable) -> typing.Callable:
        """Validate argument is a valid easing function.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Ease value is not a valid easing function.

        Returns:
            typing.Callable: The validated easing function.

        """
        if callable(arg):
            return arg
        try:
            return Ease._FUNCTION_MAP[arg.lower()]
        except (AttributeError, KeyError):
            msg = f"invalid ease value: '{arg}' is not a valid ease."
            raise argparse.ArgumentTypeError(msg) from None

type_parser(arg) staticmethod

Validate argument is a valid easing function.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Ease value is not a valid easing function.

Returns:

Type Description
Callable

typing.Callable: The validated easing function.

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | typing.Callable) -> typing.Callable:
    """Validate argument is a valid easing function.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Ease value is not a valid easing function.

    Returns:
        typing.Callable: The validated easing function.

    """
    if callable(arg):
        return arg
    try:
        return Ease._FUNCTION_MAP[arg.lower()]
    except (AttributeError, KeyError):
        msg = f"invalid ease value: '{arg}' is not a valid ease."
        raise argparse.ArgumentTypeError(msg) from None

EasingStep

Validate argument is a valid easing step size value.

Raises:

Type Description
ArgumentTypeError

Value is not a valid easing step size.

Source code in terminaltexteffects/utils/argutils.py
class EasingStep:
    """Validate argument is a valid easing step size value.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid easing step size.

    """

    METAVAR = "0 < float(n) <= 1"

    @staticmethod
    def type_parser(arg: str | float) -> float:
        """Validate argument is a valid easing step size value.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not a valid easing step size.

        Returns:
            float: validated easing step size value

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
            msg = f"invalid value: '{arg}' is not a valid float."
            raise argparse.ArgumentTypeError(msg)
        try:
            f = float(arg)
        except ValueError:
            msg = f"invalid value: '{arg}' is not a valid float."
            raise argparse.ArgumentTypeError(msg) from None

        if 0 < f <= 1:
            return f
        msg = f"invalid value: '{arg}' is not a float > 0 and <= 1. Example: 0.5"
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a valid easing step size value.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not a valid easing step size.

Returns:

Name Type Description
float float

validated easing step size value

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | float) -> float:
    """Validate argument is a valid easing step size value.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not a valid easing step size.

    Returns:
        float: validated easing step size value

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
        msg = f"invalid value: '{arg}' is not a valid float."
        raise argparse.ArgumentTypeError(msg)
    try:
        f = float(arg)
    except ValueError:
        msg = f"invalid value: '{arg}' is not a valid float."
        raise argparse.ArgumentTypeError(msg) from None

    if 0 < f <= 1:
        return f
    msg = f"invalid value: '{arg}' is not a float > 0 and <= 1. Example: 0.5"
    raise argparse.ArgumentTypeError(msg)

GradientDirection

Validate argument is a valid gradient direction.

Raises:

Type Description
ArgumentTypeError

Argument value is not a valid gradient direction.

Source code in terminaltexteffects/utils/argutils.py
class GradientDirection:
    """Validate argument is a valid gradient direction.

    Raises:
        argparse.ArgumentTypeError: Argument value is not a valid gradient direction.

    """

    COMPLETION_CHOICES = ("diagonal", "horizontal", "vertical", "radial")
    METAVAR = f"({', '.join(COMPLETION_CHOICES)})"

    @staticmethod
    def type_parser(arg: str | Gradient.Direction) -> Gradient.Direction:
        """Validate argument is a valid gradient direction.

        Args:
            arg (str): argument to validate

        Returns:
            Gradient.Direction: validated gradient direction

        Raises:
            argparse.ArgumentTypeError: Argument value is not a valid gradient direction.

        """
        if isinstance(arg, Gradient.Direction):
            return arg
        direction_map = {
            "horizontal": Gradient.Direction.HORIZONTAL,
            "vertical": Gradient.Direction.VERTICAL,
            "diagonal": Gradient.Direction.DIAGONAL,
            "radial": Gradient.Direction.RADIAL,
        }
        if isinstance(arg, str) and arg.lower() in direction_map:
            return direction_map[arg.lower()]
        msg = (
            f"invalid gradient direction: '{arg}' is not a valid gradient direction. Choices are diagonal,"
            " horizontal, vertical, or radial."
        )
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a valid gradient direction.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Returns:

Type Description
Direction

Gradient.Direction: validated gradient direction

Raises:

Type Description
ArgumentTypeError

Argument value is not a valid gradient direction.

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | Gradient.Direction) -> Gradient.Direction:
    """Validate argument is a valid gradient direction.

    Args:
        arg (str): argument to validate

    Returns:
        Gradient.Direction: validated gradient direction

    Raises:
        argparse.ArgumentTypeError: Argument value is not a valid gradient direction.

    """
    if isinstance(arg, Gradient.Direction):
        return arg
    direction_map = {
        "horizontal": Gradient.Direction.HORIZONTAL,
        "vertical": Gradient.Direction.VERTICAL,
        "diagonal": Gradient.Direction.DIAGONAL,
        "radial": Gradient.Direction.RADIAL,
    }
    if isinstance(arg, str) and arg.lower() in direction_map:
        return direction_map[arg.lower()]
    msg = (
        f"invalid gradient direction: '{arg}' is not a valid gradient direction. Choices are diagonal,"
        " horizontal, vertical, or radial."
    )
    raise argparse.ArgumentTypeError(msg)

NonNegativeFloat

Validate argument is a nonnegative float. n >= 0.

Raises:

Type Description
ArgumentTypeError

Argument value is not in range.

Source code in terminaltexteffects/utils/argutils.py
class NonNegativeFloat:
    """Validate argument is a nonnegative float. n >= 0.

    Raises:
        argparse.ArgumentTypeError: Argument value is not in range.

    """

    METAVAR = "(float >= 0)"

    @staticmethod
    def type_parser(arg: str | float) -> float:
        """Validate argument is a nonnegative float. n >= 0.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Argument value is not in range.

        Returns:
            float: validated value

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
            msg = f"invalid argument value: '{arg}' is not a valid float."
            raise argparse.ArgumentTypeError(msg)
        try:
            arg_float = float(arg)
        except ValueError:
            msg = f"invalid argument value: '{arg}' is not a valid float."
            raise argparse.ArgumentTypeError(msg) from None

        if arg_float < 0:
            msg = f"invalid argument value: '{arg}' is out of range. Must be float >= 0."
            raise argparse.ArgumentTypeError(msg)
        return arg_float

type_parser(arg) staticmethod

Validate argument is a nonnegative float. n >= 0.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Argument value is not in range.

Returns:

Name Type Description
float float

validated value

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | float) -> float:
    """Validate argument is a nonnegative float. n >= 0.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Argument value is not in range.

    Returns:
        float: validated value

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
        msg = f"invalid argument value: '{arg}' is not a valid float."
        raise argparse.ArgumentTypeError(msg)
    try:
        arg_float = float(arg)
    except ValueError:
        msg = f"invalid argument value: '{arg}' is not a valid float."
        raise argparse.ArgumentTypeError(msg) from None

    if arg_float < 0:
        msg = f"invalid argument value: '{arg}' is out of range. Must be float >= 0."
        raise argparse.ArgumentTypeError(msg)
    return arg_float

NonNegativeInt

Validate argument is a nonnegative integer. n >= 0.

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Source code in terminaltexteffects/utils/argutils.py
class NonNegativeInt:
    """Validate argument is a nonnegative integer. n >= 0.

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    """

    METAVAR = "(int >= 0)"

    @staticmethod
    def type_parser(arg: str | int) -> int:
        """Validate argument is a nonnegative integer. n >= 0.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not in range.

        Returns:
            int: validated gap value

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int)):
            msg = f"invalid value: '{arg}' is not a valid integer."
            raise argparse.ArgumentTypeError(msg)
        try:
            arg_int = int(arg)
        except ValueError:
            msg = f"invalid value: '{arg}' is not a valid integer."
            raise argparse.ArgumentTypeError(msg) from None

        if arg_int < 0:
            msg = f"invalid value: '{arg}' Argument must be int >= 0."
            raise argparse.ArgumentTypeError(msg) from None
        return arg_int

type_parser(arg) staticmethod

Validate argument is a nonnegative integer. n >= 0.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Returns:

Name Type Description
int int

validated gap value

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | int) -> int:
    """Validate argument is a nonnegative integer. n >= 0.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    Returns:
        int: validated gap value

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int)):
        msg = f"invalid value: '{arg}' is not a valid integer."
        raise argparse.ArgumentTypeError(msg)
    try:
        arg_int = int(arg)
    except ValueError:
        msg = f"invalid value: '{arg}' is not a valid integer."
        raise argparse.ArgumentTypeError(msg) from None

    if arg_int < 0:
        msg = f"invalid value: '{arg}' Argument must be int >= 0."
        raise argparse.ArgumentTypeError(msg) from None
    return arg_int

NonNegativeRatio

Validate argument is a float value between zero and one.

0 <= float(n) <= 1

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Source code in terminaltexteffects/utils/argutils.py
class NonNegativeRatio:
    """Validate argument is a float value between zero and one.

    0 <= float(n) <= 1

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    """

    METAVAR = "(0 <= float(n) <= 1)"

    @staticmethod
    def type_parser(arg: str | float) -> float:
        """Validate argument is a float value between zero and one.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not in range.

        Returns:
            float: validated float value

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
            msg = f"invalid value: '{arg}' is not a float or int."
            raise argparse.ArgumentTypeError(msg)
        try:
            arg_float = float(arg)
        except ValueError:
            msg = f"invalid value: '{arg}' is not a float or int."
            raise argparse.ArgumentTypeError(msg) from None

        if 0 <= arg_float <= 1:
            return arg_float
        msg = f"invalid value: '{arg}' is not a float >= 0 and <= 1. Example: 0.5"
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a float value between zero and one.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Returns:

Name Type Description
float float

validated float value

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | float) -> float:
    """Validate argument is a float value between zero and one.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    Returns:
        float: validated float value

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
        msg = f"invalid value: '{arg}' is not a float or int."
        raise argparse.ArgumentTypeError(msg)
    try:
        arg_float = float(arg)
    except ValueError:
        msg = f"invalid value: '{arg}' is not a float or int."
        raise argparse.ArgumentTypeError(msg) from None

    if 0 <= arg_float <= 1:
        return arg_float
    msg = f"invalid value: '{arg}' is not a float >= 0 and <= 1. Example: 0.5"
    raise argparse.ArgumentTypeError(msg)

ParserSpec dataclass

Specification for creating an argparse subparser for an effect config.

Each field maps directly to keyword arguments passed to argparse._SubParsersAction.add_parser().

Source code in terminaltexteffects/utils/argutils.py
@dataclass(frozen=True)
class ParserSpec:
    """Specification for creating an argparse subparser for an effect config.

    Each field maps directly to keyword arguments passed to
    `argparse._SubParsersAction.add_parser()`.
    """

    name: str
    help: str
    description: str
    epilog: str

PositiveFloat

Validate argument is a positive float. n > 0.

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Source code in terminaltexteffects/utils/argutils.py
class PositiveFloat:
    """Validate argument is a positive float. n > 0.

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    """

    METAVAR = "(float > 0)"

    @staticmethod
    def type_parser(arg: str | float) -> float:
        """Validate argument is a positive float. n > 0.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: value is not in range.

        Returns:
            float: validated positive float

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
            msg = f"invalid value: '{arg}' is not a valid float."
            raise argparse.ArgumentTypeError(msg)
        try:
            arg_float = float(arg)
        except ValueError:
            msg = f"invalid value: '{arg}' is not a valid float."
            raise argparse.ArgumentTypeError(msg) from None

        if arg_float > 0:
            return arg_float
        msg = f"invalid value: '{arg}' is not a valid value. Argument must be a float > 0."
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a positive float. n > 0.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

value is not in range.

Returns:

Name Type Description
float float

validated positive float

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | float) -> float:
    """Validate argument is a positive float. n > 0.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: value is not in range.

    Returns:
        float: validated positive float

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
        msg = f"invalid value: '{arg}' is not a valid float."
        raise argparse.ArgumentTypeError(msg)
    try:
        arg_float = float(arg)
    except ValueError:
        msg = f"invalid value: '{arg}' is not a valid float."
        raise argparse.ArgumentTypeError(msg) from None

    if arg_float > 0:
        return arg_float
    msg = f"invalid value: '{arg}' is not a valid value. Argument must be a float > 0."
    raise argparse.ArgumentTypeError(msg)

PositiveFloatRange

Validate argument is a nondecreasing range of positive floats.

Float ranges are expressed as two floats separated by a hyphen, for example 0.1-1.0.

Raises:

Type Description
ArgumentTypeError

Value is not a valid float range.

Source code in terminaltexteffects/utils/argutils.py
class PositiveFloatRange:
    """Validate argument is a nondecreasing range of positive floats.

    Float ranges are expressed as two floats separated by a hyphen, for example
    `0.1-1.0`.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid float range.

    """

    METAVAR = "(hyphen separated float range e.g. '0.25-0.5')"

    @staticmethod
    def type_parser(arg: str | tuple[float, float] | list[float]) -> tuple[float, float]:
        """Validate argument is a valid range of positive floats.

        Args:
            arg (str): argument to validate

        Returns:
            tuple[float,float]: validated range

        """
        try:
            if isinstance(arg, (tuple, list)):
                invalid_value = len(arg) != 2 or any(
                    isinstance(value, bool) or not isinstance(value, (int, float)) for value in arg
                )
                if invalid_value:
                    msg = f"invalid range: '{arg}' is not a valid range. Must be start-end. Ex: 0.1-1.0"
                    raise argparse.ArgumentTypeError(msg)
                start, end = map(float, arg)
            else:
                start, end = map(float, arg.split("-"))
            if start <= 0 or end <= 0:
                msg = f"invalid range: '{arg}' is not a valid range of floats. Must be start > 0. Ex: 0.1-1.0"
                raise argparse.ArgumentTypeError(
                    msg,
                )
            if start > end:
                msg = f"invalid range: '{arg}' is not a valid range of floats. Must be start <= end. Ex: 0.1-1.0"
                raise argparse.ArgumentTypeError(
                    msg,
                )

        except (AttributeError, ValueError):
            msg = f"invalid range: '{arg}' is not a valid range. Must be start-end. Ex: 0.1-1.0"
            raise argparse.ArgumentTypeError(msg) from None

        else:
            return start, end

type_parser(arg) staticmethod

Validate argument is a valid range of positive floats.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Returns:

Type Description
tuple[float, float]

tuple[float,float]: validated range

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | tuple[float, float] | list[float]) -> tuple[float, float]:
    """Validate argument is a valid range of positive floats.

    Args:
        arg (str): argument to validate

    Returns:
        tuple[float,float]: validated range

    """
    try:
        if isinstance(arg, (tuple, list)):
            invalid_value = len(arg) != 2 or any(
                isinstance(value, bool) or not isinstance(value, (int, float)) for value in arg
            )
            if invalid_value:
                msg = f"invalid range: '{arg}' is not a valid range. Must be start-end. Ex: 0.1-1.0"
                raise argparse.ArgumentTypeError(msg)
            start, end = map(float, arg)
        else:
            start, end = map(float, arg.split("-"))
        if start <= 0 or end <= 0:
            msg = f"invalid range: '{arg}' is not a valid range of floats. Must be start > 0. Ex: 0.1-1.0"
            raise argparse.ArgumentTypeError(
                msg,
            )
        if start > end:
            msg = f"invalid range: '{arg}' is not a valid range of floats. Must be start <= end. Ex: 0.1-1.0"
            raise argparse.ArgumentTypeError(
                msg,
            )

    except (AttributeError, ValueError):
        msg = f"invalid range: '{arg}' is not a valid range. Must be start-end. Ex: 0.1-1.0"
        raise argparse.ArgumentTypeError(msg) from None

    else:
        return start, end

PositiveInt

Validate argument is a positive integer. n > 0.

int(n) > 0

Raises:

Type Description
ArgumentTypeError

Value is not a positive integer.

Source code in terminaltexteffects/utils/argutils.py
class PositiveInt:
    """Validate argument is a positive integer. n > 0.

    int(n) > 0

    Raises:
        argparse.ArgumentTypeError: Value is not a positive integer.

    """

    METAVAR = "(int > 0)"

    @staticmethod
    def type_parser(arg: str | int) -> int:
        """Validate argument is a positive integer. n > 0.

        Args:
            arg (str): argument to validate

        Returns:
            int: validated positive integer

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int)):
            msg = f"invalid value: '{arg}' is not a valid integer."
            raise argparse.ArgumentTypeError(msg)
        try:
            arg_int = int(arg)
        except ValueError:
            msg = f"invalid value: '{arg}' is not a valid integer."
            raise argparse.ArgumentTypeError(msg) from None

        if arg_int > 0:
            return arg_int
        msg = f"invalid value: '{arg}' is not a valid value. Argument must be an integer > 0."
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a positive integer. n > 0.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Returns:

Name Type Description
int int

validated positive integer

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | int) -> int:
    """Validate argument is a positive integer. n > 0.

    Args:
        arg (str): argument to validate

    Returns:
        int: validated positive integer

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int)):
        msg = f"invalid value: '{arg}' is not a valid integer."
        raise argparse.ArgumentTypeError(msg)
    try:
        arg_int = int(arg)
    except ValueError:
        msg = f"invalid value: '{arg}' is not a valid integer."
        raise argparse.ArgumentTypeError(msg) from None

    if arg_int > 0:
        return arg_int
    msg = f"invalid value: '{arg}' is not a valid value. Argument must be an integer > 0."
    raise argparse.ArgumentTypeError(msg)

PositiveIntRange

Validate argument is a nondecreasing range that starts with a positive integer.

Positive integer ranges are expressed as two integers separated by a hyphen, for example 1-10.

Example

'1-10' is a valid input.

Raises:

Type Description
ArgumentTypeError

Value is not a valid positive integer range.

Source code in terminaltexteffects/utils/argutils.py
class PositiveIntRange:
    """Validate argument is a nondecreasing range that starts with a positive integer.

    Positive integer ranges are expressed as two integers separated by a hyphen,
    for example `1-10`.

    Example:
        '1-10' is a valid input.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid positive integer range.

    """

    METAVAR = "(hyphen separated positive int range e.g. '1-10')"

    @staticmethod
    def type_parser(arg: str | tuple[int, int] | list[int]) -> tuple[int, int]:
        """Validate argument is a valid range of integers n > 0.

        Args:
            arg (str): argument to validate

        Returns:
            tuple[int,int]: validated range

        """
        try:
            if isinstance(arg, (tuple, list)):
                if len(arg) != 2 or any(isinstance(value, bool) or not isinstance(value, int) for value in arg):
                    msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start-end. Ex: 1-10"
                    raise argparse.ArgumentTypeError(msg)
                start, end = arg
            else:
                start, end = map(int, arg.split("-"))
            if start <= 0:
                msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start > 0. Ex: 1-10"
                raise argparse.ArgumentTypeError(
                    msg,
                )
            if start > end:
                msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start <= end. Ex: 1-10"
                raise argparse.ArgumentTypeError(
                    msg,
                )

        except (AttributeError, ValueError):
            msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start-end. Ex: 1-10"
            raise argparse.ArgumentTypeError(
                msg,
            ) from None
        else:
            return start, end

type_parser(arg) staticmethod

Validate argument is a valid range of integers n > 0.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Returns:

Type Description
tuple[int, int]

tuple[int,int]: validated range

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | tuple[int, int] | list[int]) -> tuple[int, int]:
    """Validate argument is a valid range of integers n > 0.

    Args:
        arg (str): argument to validate

    Returns:
        tuple[int,int]: validated range

    """
    try:
        if isinstance(arg, (tuple, list)):
            if len(arg) != 2 or any(isinstance(value, bool) or not isinstance(value, int) for value in arg):
                msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start-end. Ex: 1-10"
                raise argparse.ArgumentTypeError(msg)
            start, end = arg
        else:
            start, end = map(int, arg.split("-"))
        if start <= 0:
            msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start > 0. Ex: 1-10"
            raise argparse.ArgumentTypeError(
                msg,
            )
        if start > end:
            msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start <= end. Ex: 1-10"
            raise argparse.ArgumentTypeError(
                msg,
            )

    except (AttributeError, ValueError):
        msg = f"invalid range: '{arg}' is not a valid range of positive ints. Must be start-end. Ex: 1-10"
        raise argparse.ArgumentTypeError(
            msg,
        ) from None
    else:
        return start, end

PositiveRatio

Validate argument is a positive float.

0 < float(n) <= 1

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Source code in terminaltexteffects/utils/argutils.py
class PositiveRatio:
    """Validate argument is a positive float.

    0 < float(n) <= 1

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    """

    METAVAR = "(0 < float(n) <= 1)"

    @staticmethod
    def type_parser(arg: str | float) -> float:
        """Validate argument is a positive float.

        Args:
            arg (str): argument to validate

        Raises:
            argparse.ArgumentTypeError: Value is not in range.

        Returns:
            float: validated float value

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
            msg = f"invalid value: '{arg}' is not a float or int."
            raise argparse.ArgumentTypeError(msg)
        try:
            arg_float = float(arg)
        except ValueError:
            msg = f"invalid value: '{arg}' is not a float or int."
            raise argparse.ArgumentTypeError(msg) from None

        if 0 < arg_float <= 1:
            return arg_float
        msg = f"invalid value: '{arg}' must be 0 < n <=1. Example: 0.5"
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a positive float.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Raises:

Type Description
ArgumentTypeError

Value is not in range.

Returns:

Name Type Description
float float

validated float value

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | float) -> float:
    """Validate argument is a positive float.

    Args:
        arg (str): argument to validate

    Raises:
        argparse.ArgumentTypeError: Value is not in range.

    Returns:
        float: validated float value

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int, float)):
        msg = f"invalid value: '{arg}' is not a float or int."
        raise argparse.ArgumentTypeError(msg)
    try:
        arg_float = float(arg)
    except ValueError:
        msg = f"invalid value: '{arg}' is not a float or int."
        raise argparse.ArgumentTypeError(msg) from None

    if 0 < arg_float <= 1:
        return arg_float
    msg = f"invalid value: '{arg}' must be 0 < n <=1. Example: 0.5"
    raise argparse.ArgumentTypeError(msg)

Symbol

Validate argument is a single printable character.

Raises:

Type Description
ArgumentTypeError

Value is not a valid symbol.

Source code in terminaltexteffects/utils/argutils.py
class Symbol:
    """Validate argument is a single printable character.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid symbol.

    """

    METAVAR = "(ASCII/UTF-8 character)"

    @staticmethod
    def type_parser(arg: str) -> str:
        """Validate argument is a single printable character.

        Args:
            arg (str): argument to validate

        Returns:
            str: validated symbol

        """
        if isinstance(arg, str) and len(arg) == 1 and arg.isprintable():
            return arg
        msg = f"invalid symbol: '{arg}' is not a valid symbol. Must be a single ASCII/UTF-8 character."
        raise argparse.ArgumentTypeError(msg)

type_parser(arg) staticmethod

Validate argument is a single printable character.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Returns:

Name Type Description
str str

validated symbol

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str) -> str:
    """Validate argument is a single printable character.

    Args:
        arg (str): argument to validate

    Returns:
        str: validated symbol

    """
    if isinstance(arg, str) and len(arg) == 1 and arg.isprintable():
        return arg
    msg = f"invalid symbol: '{arg}' is not a valid symbol. Must be a single ASCII/UTF-8 character."
    raise argparse.ArgumentTypeError(msg)

TerminalDimension

Validate argument is a valid terminal dimension.

A Terminal Dimension is an integer >= 0.

Raises:

Type Description
ArgumentTypeError

Value is not a valid terminal dimension.

Source code in terminaltexteffects/utils/argutils.py
class TerminalDimension:
    """Validate argument is a valid terminal dimension.

    A Terminal Dimension is an integer >= 0.

    Raises:
        argparse.ArgumentTypeError: Value is not a valid terminal dimension.

    """

    METAVAR = "int >= 0"

    @staticmethod
    def type_parser(arg: str | int) -> int:
        """Validate argument is a valid terminal dimension.

        Args:
            arg (str): argument to validate

        Returns:
            int: validated terminal dimension

        """
        if isinstance(arg, bool) or not isinstance(arg, (str, int)):
            msg = f"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."
            raise argparse.ArgumentTypeError(msg)
        try:
            dimension = int(arg)
            if dimension < 0:
                msg = f"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."
                raise argparse.ArgumentTypeError(msg)

        except ValueError:
            msg = f"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."
            raise argparse.ArgumentTypeError(msg) from None

        else:
            return dimension

type_parser(arg) staticmethod

Validate argument is a valid terminal dimension.

Parameters:

Name Type Description Default
arg str

argument to validate

required

Returns:

Name Type Description
int int

validated terminal dimension

Source code in terminaltexteffects/utils/argutils.py
@staticmethod
def type_parser(arg: str | int) -> int:
    """Validate argument is a valid terminal dimension.

    Args:
        arg (str): argument to validate

    Returns:
        int: validated terminal dimension

    """
    if isinstance(arg, bool) or not isinstance(arg, (str, int)):
        msg = f"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."
        raise argparse.ArgumentTypeError(msg)
    try:
        dimension = int(arg)
        if dimension < 0:
            msg = f"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."
            raise argparse.ArgumentTypeError(msg)

    except ValueError:
        msg = f"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."
        raise argparse.ArgumentTypeError(msg) from None

    else:
        return dimension

TupleAction

Bases: Action

Convert parsed multi-value arguments into tuples.

Used for arguments that accept multiple values via nargs. If argparse provides None, the destination is set to an empty tuple.

Source code in terminaltexteffects/utils/argutils.py
class TupleAction(argparse.Action):
    """Convert parsed multi-value arguments into tuples.

    Used for arguments that accept multiple values via `nargs`. If argparse provides
    `None`, the destination is set to an empty tuple.
    """

    def __call__(
        self,
        _: argparse.ArgumentParser,
        namespace: argparse.Namespace,
        values: typing.Sequence[typing.Any] | None,
        __: str | None = None,
    ) -> None:
        """Convert a list of values into a tuple."""
        if values is None:
            setattr(namespace, self.dest, ())
            return
        setattr(namespace, self.dest, tuple(values))

__call__(_, namespace, values, __=None)

Convert a list of values into a tuple.

Source code in terminaltexteffects/utils/argutils.py
def __call__(
    self,
    _: argparse.ArgumentParser,
    namespace: argparse.Namespace,
    values: typing.Sequence[typing.Any] | None,
    __: str | None = None,
) -> None:
    """Convert a list of values into a tuple."""
    if values is None:
        setattr(namespace, self.dest, ())
        return
    setattr(namespace, self.dest, tuple(values))

format_cli_default(value, type_parser=_MISSING)

Format a canonical value using its equivalent command-line spelling.

This is the fallback used for argument defaults when an ArgSpec does not provide a more specific default_formatter.

Source code in terminaltexteffects/utils/argutils.py
def format_cli_default(value: typing.Any, type_parser: typing.Any = _MISSING) -> str:
    """Format a canonical value using its equivalent command-line spelling.

    This is the fallback used for argument defaults when an `ArgSpec` does not
    provide a more specific `default_formatter`.
    """
    if type_parser in (PositiveIntRange.type_parser, PositiveFloatRange.type_parser):
        return format_cli_range(value)
    if isinstance(value, Color):
        return str(value.color_arg)
    if isinstance(value, Enum):
        return value.name.lower()
    if isinstance(value, (tuple, list)):
        return " ".join(format_cli_default(item) for item in value)
    if callable(value):
        return value.__name__
    return str(value)

format_cli_range(value)

Format a two-value range using the hyphenated command-line syntax.

Source code in terminaltexteffects/utils/argutils.py
def format_cli_range(value: tuple[int, int] | tuple[float, float]) -> str:
    """Format a two-value range using the hyphenated command-line syntax."""
    return f"{value[0]}-{value[1]}"

Example Usage

The RandomSequenceConfig.speed option uses ArgSpec with PositiveFloat.type_parser to require a value greater than zero. This minimal config follows the same declaration pattern and works with both direct construction and CLI parsing:

import argparse
from dataclasses import dataclass

from terminaltexteffects.engine.base_config import BaseConfig
from terminaltexteffects.utils import argutils


@dataclass
class SpeedConfig(BaseConfig):
    parser_spec: argutils.ParserSpec = argutils.ParserSpec(
        name="speed-example",
        help="Show the speed option.",
        description="Example speed configuration.",
        epilog="",
    )
    speed: float = argutils.ArgSpec(
        name="--speed",
        type=argutils.PositiveFloat.type_parser,
        default=0.007,
        metavar=argutils.PositiveFloat.METAVAR,
        help="Speed of the animation.",
    )  # pyright: ignore[reportAssignmentType]


assert SpeedConfig(speed="0.01").speed == 0.01

parser = argparse.ArgumentParser()
SpeedConfig._populate_parser(parser)
config = SpeedConfig._build_config(parser.parse_args(["--speed", "0.01"]))
assert config.speed == 0.01