GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

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 #148468

New issue
Copy link
New issue
Copy link
Closed
Closed
Cannot use lazy translation proxies in argparse help#148468
Copy link
Assignees
savannahostrowski
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@edgarrmondragon
edgarrmondragon
opened on Apr 12, 2026
Issue body actions

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

  • Cannot use format specifiers in argparse help #142950

CPython versions tested on:

3.15

Operating systems tested on:

macOS

Linked PRs

  • gh-148468: Accept string-like help proxies in argparse #150276
  • GH-148468: Accept string-like proxy objects in colorized argparse help #154653
  • [3.15] GH-148468: Accept string-like proxy objects in colorized argparse help (GH-154653) #154946
Reacted by Maciej Olko

Activity

  1. edgarrmondragon
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Apr 12, 2026
  2. picnixz
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    on Apr 12, 2026
  3. StanFromIreland
    added this to Argparse issueson Apr 12, 2026
  4. mpkocher commented on Apr 12, 2026

    @mpkocher
    mpkocher
    on Apr 12, 2026
    Contributor
    More actions

    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]
  5. serhiy-storchaka
    assigned
    savannahostrowski
    on Apr 13, 2026
  6. edgarrmondragon commented on Apr 16, 2026

    @edgarrmondragon
    edgarrmondragon
    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.

  7. savannahostrowski commented on Apr 17, 2026

    @savannahostrowski
    savannahostrowski
    on Apr 17, 2026
    Member
    More actions

    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.

  8. RaghunandanKumar
    added 5 commits that reference this issue on May 26, 2026

    pythongh-148468: scope down argparse proxy fix

    581c750

    pythongh-148468: rerun CI

    61f49ef

    pythongh-148468: Accept string-like help proxies in argparse

    0a892d4

    pythongh-148468: scope down argparse proxy fix

    dc8b7d7

    pythongh-148468: handle plain string-like argparse help proxies

    bfc7f21
  9. savannahostrowski
    moved this to Bugs in Argparse issueson Jun 5, 2026
  10. hugovk commented on Jul 29, 2026

    @hugovk
    hugovk
    on Jul 29, 2026
    Member
    More actions

    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.

  11. savannahostrowski commented on Jul 29, 2026

    @savannahostrowski
    savannahostrowski
    on Jul 29, 2026
    Member
    More actions

    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
  12. savannahostrowski
    added 3 commits that reference this issue on Jul 30, 2026

    Merge branch 'main' into fix-pythongh-148468-lazy-help

    f90ccd3

    GH-148468: Accept string-like proxy objects in colorized argparse help (

    a147366

    [3.15] GH-148468: Accept string-like proxy objects in colorized argpa…

    c22cbf8
  13. savannahostrowski
    closed this as completedon Jul 30, 2026
  14. github-project-automation
    moved this from Bugs to Doc issues in Argparse issueson Jul 30, 2026
  15. mbeijen
    added a commit that references this issue on Aug 14, 2026

    pythonGH-148468: Accept string-like proxy objects in colorized argpar…

    8fe0edc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @savannahostrowski
    savannahostrowski

Labels

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

Projects

  • Argparse issues
    Status
    Doc issues
    Show more project fields

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.