Skip to content

Cannot use lazy translation proxies in argparse help #148468

@edgarrmondragon

Description

@edgarrmondragon

Bug report

Bug description:

#142960 introduced a regression for lazy strings in the help= parameter of ArgumentParser.add_argument(). This is used at least by the Sphinx CLI with its _TranslationProxy, at least during testing, where sphinx.locale.init_console is monkeypatched.

The new version of _expand_help() calls re.sub() on help strings when color is enabled, but re.sub() requires an actual str/bytes object and rejects string-like proxies that only implement __str__/__mod__.

# mre_argparse_lazy_str.py

import argparse


class LazyStr:
    """Minimal stand-in for gettext lazy-translation objects."""

    def __init__(self, message: str) -> None:
        self._message = message

    def __str__(self) -> str:
        return self._message  # resolve lazily

    def __mod__(self, other):
        return self._message % other  # supports 'help % params'

    def __contains__(self, item) -> bool:
        return item in self._message  # supports '"%" in help'


p = argparse.ArgumentParser(description='demo')
# Works fine without color; fails with FORCE_COLOR=1 (or a color TTY):
p.add_argument('--output', default='out.txt', help=LazyStr('write to %(default)s'))
p.parse_args([])
print('OK – parsed without error')
$ uvx -p 3.15.0a4 python mre_argparse_lazy_str.py
OK – parsed without error
$ uvx -p 3.15.0a5 python mre_argparse_lazy_str.py
Traceback (most recent call last):
  File "/Users/personal/.local/share/uv/python/cpython-3.15.0a5-macos-aarch64-none/lib/python3.15/argparse.py", line 1822, in _check_help
    formatter._expand_help(action)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "/Users/personal/.local/share/uv/python/cpython-3.15.0a5-macos-aarch64-none/lib/python3.15/argparse.py", line 725, in _expand_help
    return _re.sub(fmt_spec, colorize, help_string, flags=_re.VERBOSE)
           ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/personal/.local/share/uv/python/cpython-3.15.0a5-macos-aarch64-none/lib/python3.15/re/__init__.py", line 206, in sub
    return _compile(pattern, flags).sub(repl, string, count)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
TypeError: expected string or bytes-like object, got 'LazyStr'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/personal/Contrib/sphinx-doc/sphinx/mre_argparse_lazy_str.py", line 47, in <module>
    p.add_argument('--output', default='out.txt', help=LazyStr('write to %(default)s'))
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/personal/.local/share/uv/python/cpython-3.15.0a5-macos-aarch64-none/lib/python3.15/argparse.py", line 1630, in add_argument
    self._check_help(action)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/Users/personal/.local/share/uv/python/cpython-3.15.0a5-macos-aarch64-none/lib/python3.15/argparse.py", line 1824, in _check_help
    raise ValueError('badly formed help string') from exc
ValueError: badly formed help string

If this indeed something CPython rather than Sphinx should fix, the simplest solution would be to coerce help_string:

- return _re.sub(fmt_spec, colorize, help_string, flags=_re.VERBOSE)
+ return _re.sub(fmt_spec, colorize, str(help_string), flags=_re.VERBOSE)

and I'd be happy to send a PR if that's the case.

Related

CPython versions tested on:

3.15

Operating systems tested on:

macOS

Metadata

Metadata

Labels

stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions