Skip to content

Conversation

@hugovk
Copy link
Member

@hugovkhugovk commented Apr 9, 2025

Add color parameter to argparse.ArgumentParser, which by default is False. When set to True, the help text is in colour if allowed (for example, we're not piping, NO_COLOR=1 is not set).

Example output

Using this script:

importargparseparser=argparse.ArgumentParser( description="calculate X to the power of Y", formatter_class=argparse.ArgumentDefaultsHelpFormatter, prefix_chars="-+", prog="PROG", ) parser.color=Truegroup=parser.add_mutually_exclusive_group() group.add_argument("-v", "--verbose", action="store_true", help="more spam") group.add_argument("-q", "--quiet", action="store_true", help="less spam") parser.add_argument("x", type=int, help="the base") parser.add_argument("y", type=int, help="the exponent", deprecated=True) parser.add_argument( "this_indeed_is_a_very_long_action_name", type=int, help="the exponent" ) parser.add_argument("-o", "--optional1", action="store_true", deprecated=True) parser.add_argument("--optional2", help="pick one") parser.add_argument("--optional3", choices=("X", "Y", "Z")) parser.add_argument("--optional4", choices=("X", "Y", "Z"), help="pick one") parser.add_argument("--optional5", choices=("X", "Y", "Z"), help="pick one") parser.add_argument("--optional6", choices=("X", "Y", "Z"), help="pick one") parser.add_argument( "-p", "--optional7", choices=("Aaaaa", "Bbbbb", "Ccccc", "Ddddd"), help="pick one" ) parser.add_argument("+f") parser.add_argument("++bar") parser.add_argument("-+baz") parser.add_argument("-c", "--count") subparsers=parser.add_subparsers( title="subcommands", description="valid subcommands", help="additional help" ) subparsers.add_parser("sub1", deprecated=True, help="sub1 help") sub2=subparsers.add_parser("sub2", deprecated=True, help="sub2 help") sub2.add_argument("--baz", choices=("X", "Y", "Z"), help="baz help") args=parser.parse_args()
image

Performance

With the same script and PGO+LTO on macOS, running it once (time ./python.exe argparse-cli.py --help) and 100 times (time ./100.sh):

# 100.shforiin$(seq 1 100);do ./python.exe argparse-cli.py -h done

main (3feac7a):

./python.exe argparse-cli.py --help 0.03s user 0.01s system 88% cpu 0.046 total ./100.sh 1.51s user 0.39s system 93% cpu 2.041 total 

PR and colour not enabled:

./python.exe argparse-cli.py --help 0.02s user 0.02s system 58% cpu 0.072 total ./100.sh 1.52s user 0.40s system 92% cpu 2.070 total 

PR and colour enabled:

./python.exe argparse-cli.py --help 0.04s user 0.02s system 70% cpu 0.080 total ./100.sh 1.57s user 0.40s system 93% cpu 2.106 total 

Something like 0.65 ms difference per run between before and after, averaging from 100.sh.


📚 Documentation preview 📚: https://cpython-previews--132323.org.readthedocs.build/

@bedevere-appbedevere-appbot mentioned this pull request Apr 9, 2025
@hugovkhugovk added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Apr 9, 2025
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @hugovk for commit 3d174b7 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F132323%2Fmerge

If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again.

@bedevere-botbedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Apr 9, 2025
@hugovkhugovk added type-feature A feature request or enhancement stdlib Standard Library Python modules in the Lib/ directory labels Apr 9, 2025
@hugovkhugovk marked this pull request as ready for review April 9, 2025 18:12
@python-cla-bot
Copy link

python-cla-botbot commented Apr 18, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app
Copy link

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

Copy link
Member

@savannahostrowskisavannahostrowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment about the approach and whether we can simplify a bit.

@hugovk
Copy link
MemberAuthor

ArgumentParser() has a lot of parameters, color is its 16th.

Many argparse CLIs I see already use keywords for most parameters, but I think we should make these new ones keyword-only, especially for new bools, as a long list of (..., True, False, True, ...) is best avoided.

suggest_on_error was added in 3.14, I suggest we also make that keyword-only (in another PR).

What do you think?

@ambvambv dismissed savannahostrowski’s stale reviewMay 2, 2025 13:03

Commandeering this to make the beta 1 cut. Code owner's feedback can be addressed in follow-up PRs.

@ambvambv merged commit 4701ff9 into python:mainMay 2, 2025
51 of 52 checks passed
@hugovkhugovk deleted the 3.14-argparse-colour-help branch May 2, 2025 13:31
hauntsaninja pushed a commit to python/mypy that referenced this pull request May 3, 2025
python/cpython#132323 added an optional `color` argument to ArgumentParser. As a side effect the help formatters are now called with two new keyword arguments `prefix_chars` and `color`. Add `**kwargs` to the custom `AugmentedHelpFormatter` and pass it through to the super class.
@asottile
Copy link
Contributor

asottile commented May 3, 2025

this patch breaks virtualenv by the way: (yay deadsnakes nightly builds catching this: https://github.com/deadsnakes/py3.14/actions/runs/14809355288/job/41582164772 )

$ ./prefix/bin/python3 virtualenv.pyz venvvvvTraceback (most recent call last): File "<frozen runpy>", line 198, in _run_module_as_main File "<frozen runpy>", line 88, in _run_code File "/home/asottile/workspace/cpython/virtualenv.pyz/__main__.py", line 178, in <module> run() ~~~^^ File "/home/asottile/workspace/cpython/virtualenv.pyz/__main__.py", line 174, in run run_virtualenv() ~~~~~~~~~~~~~~^^ File "/home/asottile/workspace/cpython/virtualenv.pyz/virtualenv/__main__.py", line 20, in run session = cli_run(args, options, env) File "/home/asottile/workspace/cpython/virtualenv.pyz/virtualenv/run/__init__.py", line 31, in cli_run of_session = session_via_cli(args, options, setup_logging, env) File "/home/asottile/workspace/cpython/virtualenv.pyz/virtualenv/run/__init__.py", line 49, in session_via_cli parser, elements = build_parser(args, options, setup_logging, env) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/asottile/workspace/cpython/virtualenv.pyz/virtualenv/run/__init__.py", line 64, in build_parser add_version_flag(parser) ~~~~~~~~~~~~~~~~^^^^^^^^ File "/home/asottile/workspace/cpython/virtualenv.pyz/virtualenv/run/__init__.py", line 138, in add_version_flag parser.add_argument( ~~~~~~~~~~~~~~~~~~~^ "--version", ^^^^^^^^^^^^ ...<2 lines>... help="display the version of the virtualenv package and its location, then exit", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/home/asottile/workspace/cpython/prefix/lib/python3.14/argparse.py", line 1566, in add_argument formatter = self._get_formatter() File "/home/asottile/workspace/cpython/prefix/lib/python3.14/argparse.py", line 2733, in _get_formatter return self.formatter_class( ~~~~~~~~~~~~~~~~~~~~^ prog=self.prog, ^^^^^^^^^^^^^^^ prefix_chars=self.prefix_chars, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ color=self.color, ^^^^^^^^^^^^^^^^^ ) ^TypeError: HelpFormatter.__init__() got an unexpected keyword argument 'prefix_chars'

it looks like adding the parameters to the help formatter here breaks the subclass there

cc @gaborbernat

@cdce8p
Copy link
Contributor

this patch breaks virtualenv by the way

It broke mypy as well. The fix was trivial though: python/mypy#19020

@The-Compiler
Copy link
Contributor

This breaks tox as well: tox-dev/tox#3523

The-Compiler added a commit to The-Compiler/tox that referenced this pull request May 8, 2025
python/cpython#132323 passes prefix_chars= (and other arguments) to the formatter_class, but the custom HelpFormatter only accepted prog=. Accept any keyword arguments and pass them on to the parent class. Fixestox-dev#3523
The-Compiler added a commit to The-Compiler/tox that referenced this pull request May 8, 2025
python/cpython#132323 passes prefix_chars= (and other arguments) to the formatter_class, but the custom HelpFormatter only accepted prog=. Accept any keyword arguments and pass them on to the parent class. Fixestox-dev#3523
@hugovk
Copy link
MemberAuthor

We'll fix it for beta 2: #133653. Fixes (temporary or not) is helpful in other tools to enable testing beta 1, thanks!

JelleZijlstra added a commit to python/typeshed that referenced this pull request May 12, 2025
…13947) These are - `suggest_on_error`, added by python/cpython#124456, made keyword-only by python/cpython#133302 - `color`, added by python/cpython#132323 Co-authored-by: Sebastian Rittau <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
mmingyu pushed a commit to mmingyu/typeshed that referenced this pull request May 16, 2025
…ython#13947) These are - `suggest_on_error`, added by python/cpython#124456, made keyword-only by python/cpython#133302 - `color`, added by python/cpython#132323 Co-authored-by: Sebastian Rittau <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
Pranjal095 pushed a commit to Pranjal095/cpython that referenced this pull request Jul 12, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@hugovk@bedevere-bot@asottile@cdce8p@The-Compiler@savannahostrowski@ambv