GeezerVison is showing github.com — Cannot use lazy translation proxies in argparse help · Issue #148468 · python/cpython
Cannot use lazy translation proxies in argparse help #148468DescriptionBug 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
Linked PRs
Activitympkocher commented on Apr 12, 2026 Because of this explicit casting, doesn't this mean that any mistake from a user will never raise a type error?
For example, (... help=["hello"]) or (help=True) ?
Also, this LazyStr pattern doesn't really play nice with type checkers (perhaps this is a separate issue).
mypy mre_argparse.py
mre_argparse.py:24: error: Argument "help" to "add_argument" of "_ActionsContainer" has incompatible type "LazyStr"; expected "str | None" [arg-type] edgarrmondragon commented on Apr 16, 2026 ContributorAuthor More actions
Also, this LazyStr pattern doesn't really play nice with type checkers (perhaps this is a separate issue).
Yeah, I honestly think this something the sphinx folks should fix in their tests, but maybe the maintainers believe it's worth considering it a breaking change. savannahostrowski commented on Apr 17, 2026 I think perhaps we could coerce to str, but not at the place suggested. Instead, we could just do it in colorize(). By that point help_string % params has already validated the input, so help=True or help=["hello"] still raise in the way they do today. hugovk commented on Jul 29, 2026 I get the same result for 3.15.0a4 and a5:
❯ 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/hugo/.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/hugo/.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/hugo/.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/hugo/github/python/cpython/main/mre_argparse_lazy_str.py", line 24, in <module>
p.add_argument('--output', default='out.txt', help=LazyStr('write to %(default)s'))
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hugo/.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/hugo/.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
And a6 and a7 also raise ValueError.
But all the betas and latest main work okay:
❯ uvx -p 3.15.0b1 python mre_argparse_lazy_str.py
OK – parsed without error
❯ uvx -p 3.15.0b2 python mre_argparse_lazy_str.py
OK – parsed without error
❯ uvx -p 3.15.0b3 python mre_argparse_lazy_str.py
OK – parsed without error
❯ uvx -p 3.15.0b4 python mre_argparse_lazy_str.py
OK – parsed without error
❯ px --version --version
Python 3.16.0a0 (heads/main-dirty:9ccd5bb81ed, Jul 29 2026, 18:37:18) [Clang 17.0.0 (clang-1700.6.4.2)]
❯ px mre_argparse_lazy_str.py
OK – parsed without error
Git bisect points to 8cad740 from #148827 as the fix. savannahostrowski commented on Jul 29, 2026 It looks like 8cad740 indirectly fixed the construction-time failure by making the validation formatter colorless. However, colored help rendering still fails on current main and the 3.15 branch. With FORCE_COLOR=1:
parser.add_argument(
"--output",
default="out.txt",
help=LazyStr("write to %(default)s"),
)
print(parser.format_help())
still raises:
TypeError: expected string or bytes-like object, got 'LazyStr'
Reacted by Edgar Ramírez Mondragón and Hugo van Kemenade added 3 commits that reference this issue on Jul 30, 2026GH-148468: Accept string-like proxy objects in colorized argparse help (
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|