cpython icon indicating copy to clipboard operation
cpython copied to clipboard

argparse with option/value like --gpg-options "--homedir=/home/user" errors out but adding binding op works.

Open kwloafman opened this issue 1 year ago • 3 comments

Bug report

Bug description:

--gpg-options is defined as follows:

    gpg_options=dict(
        metavar=_("options"),
        action=SplitOptionsAction,
        help="Verbatim gpg options.  May be supplied multiple times.",
        default=dflt(config.gpg_options),
    ),

This does not work (using space):

prog --gpg-options "--homedir=/home/user"

and gets argument --gpg-options: expected one argument

But this one does (using the binding op):

prog --gpg-options="--homedir=/home/user"

with gpg_options being set correctly.

The deprecated optparse handled this correctly.

See Also: https://gitlab.com/duplicity/duplicity/-/issues/795 https://gitlab.com/duplicity/duplicity/-/issues/816

CPython versions tested on:

3.8, 3.9, 3.10, 3.11, 3.12

Operating systems tested on:

Linux, macOS

kwloafman avatar May 03 '24 15:05 kwloafman

You might like to add a clear way to produce the bug. How does the gpg_options dictionary interface with the argparse module?

So far this sounds like the known bug #53580. Unfortunately, the documentation https://docs.python.org/3/library/argparse.html#arguments-containing indicates it is intended that cases like this assume the user made a mistake and an error is reported.

vadmium avatar May 04 '24 07:05 vadmium

It's a simple case of using a dataclass of dictionaries so that we can do:

    for opt in sorted(all_options):
        var = opt2var(opt)
        names = [opt] + OptionAliases.__dict__.get(var, [])
        parser.add_argument(*names, **OptionKwargs[var])

where OptionKwargs[var] is the dictionary above, one of 109 in duplicity.

So putting it all together it would appear as if expanded to multiple calls:

    parser.add_argument(
        "gpg-options", 
        metavar=_("options"),
        action=SplitOptionsAction,
        help="Verbatim gpg options.  May be supplied multiple times.",
        default=dflt(config.gpg_options),
)

kwloafman avatar May 04 '24 16:05 kwloafman

Note that per the linked ticket, the overall answer here is that optparse has POSIX-compatible semantics and argparse does not, and if you find yourself hitting this argparse bug the answer is to switch (back?) to optparse.

eli-schwartz avatar May 20 '24 21:05 eli-schwartz

When exactly does optparse get removed? It's been deprecated for years.

kwloafman avatar May 21 '24 15:05 kwloafman

There are no plans to ever remove it.

CPython considers it feature- complete and closed for future development, and also considered less ergonomic than argparse, hence "soft deprecated in the sense that for existing scripts it's fine to keep using it forever".

Note that argparse is also considered feature-complete and no one is really willing to develop it further beyond bugfixes, because it turns out that argument parsing libraries are hard and no one wants to touch them or something. 🤷 Ask most people and they will tell you to give up on the standard library as a bad idea and go use click instead.

eli-schwartz avatar May 21 '24 15:05 eli-schwartz