Skip to content

Formatters

Opt-in argparse help formatters — defaults-in-help and ANSI color — selected via a class's _help_formatter_ attribute.

duho.formatters

Opt-in argparse help formatters: defaults-in-help + ANSI color.

Both formatters are plain :class:argparse.HelpFormatter subclasses a class opts into via the sandwich-named _help_formatter_ attribute, which Args._parser_ plumbs into argparse's formatter_class. They are off by default -- duho's --help output is unchanged unless a class sets _help_formatter_.

  • :class:DefaultsFormatter -- append (default: X) to each option's help, but (unlike argparse's own ArgumentDefaultsHelpFormatter) skip the noise of None/""/False defaults.
  • :class:ColorHelpFormatter -- ANSI-color section headings and option flags, gated on a TTY (and NO_COLOR/FORCE_COLOR). When color is off the output is byte-identical to the base formatter, so alignment and piping are unaffected.
  • :class:ColorDefaultsFormatter -- both composed.

The ANSI codes reuse logging.py's _asicode (hard-coded escapes -- no colorama import, so import duho pays nothing for these).

__all__ = ['DefaultsFormatter', 'ColorHelpFormatter', 'ColorDefaultsFormatter'] module-attribute

ColorDefaultsFormatter(*args, **kwargs)

Bases: ColorHelpFormatter, DefaultsFormatter

Compose :class:ColorHelpFormatter + :class:DefaultsFormatter.

Colors headings/flags AND appends (default: X) -- the batteries-included pretty-help formatter. The two mix cleanly: color overrides start_section / _format_action, defaults overrides _get_help_string -- called from inside the BASE _format_action that color's own override delegates to, so a colored line still gets its (default: X) suffix before color is spliced back in.

Source code in src/duho/formatters.py
153
154
155
def __init__(self, *args: _ty.Any, **kwargs: _ty.Any) -> None:
    super().__init__(*args, **kwargs)
    self._duho_color_ = False if _NATIVE_HELP_COLOR else _color_enabled()

ColorHelpFormatter(*args, **kwargs)

Bases: HelpFormatter

ANSI-color section headings and option flags, when color is enabled.

Color is resolved once at formatter construction via :func:_color_enabled (NO_COLOR/FORCE_COLOR/TTY), and unconditionally OFF on 3.14+ (see :data:_NATIVE_HELP_COLOR). When it is OFF, every override falls through to the base :class:argparse.HelpFormatter, so the output -- and its column alignment -- is byte-identical to duho's default help. When ON, section headings are bold and option invocations (-v, --verbose) are colored.

The invocation is colored strictly AFTER layout: pre-3.14 argparse measures an action's invocation with plain len() -- both when tracking the widest invocation (add_argument, which drives the shared help column) and when padding an individual line to it (_format_action) -- so if that measured string carried ANSI escape bytes (a previous version of this class colored inside _format_action_invocation, the same method both call), the escapes counted toward its width: columns went ragged, and a longer invocation could wrap early. Overriding _format_action instead -- letting the base class format the ENTIRE line uncolored (correct alignment, guaranteed), then substituting a colored copy of the plain invocation text back into it -- colors the output without the measurement ever seeing a color code.

Source code in src/duho/formatters.py
153
154
155
def __init__(self, *args: _ty.Any, **kwargs: _ty.Any) -> None:
    super().__init__(*args, **kwargs)
    self._duho_color_ = False if _NATIVE_HELP_COLOR else _color_enabled()

start_section(heading)

Source code in src/duho/formatters.py
157
158
159
160
def start_section(self, heading: _ty.Optional[str]) -> None:
    if self._duho_color_ and heading is not None:
        heading = f"{_HEADING_CODE}{heading}{_RESET}"
    super().start_section(heading)

DefaultsFormatter

Bases: HelpFormatter

Append (default: X) to each option's help, skipping empty defaults.

Like argparse's own ArgumentDefaultsHelpFormatter but it does NOT add the suffix when the effective default is None, "", False, or an empty sized container ([], {}, (), set()) -- an unset optional, a store_true flag, or duho's own resting default for every list/set/dict field -- those contribute noise, not information. An explicit %(default)s already in the help text is left untouched, and a SUPPRESS-defaulted action (--help/--version, inherited-suppressed fields) never gains a suffix.

Shows the field's CLASS default, never a live env/config value: duho.agenthelp._stash_default_provenance -- called from duho.args's _AgentHelpAction right before it renders human help -- snapshots each action's declared default (and, when the value actually came from env or config, a value-free provenance note) as _duho_class_default_/ _duho_default_source_. Falls back to plain action.default when those are absent (a parser built but never run through that print path, e.g. calling cls._parser_().format_help() directly in a test) -- identical to the previous behavior there, since nothing has layered action.default away from its class default in that case either.