python / cpython

The Python programming language
https://www.python.org
Other
62.43k stars 29.97k forks source link

argparse eats initial '=' from short option argument #124305

Open netch80 opened 4 hours ago

netch80 commented 4 hours ago

Bug report

Bug description:

When configured with a short option that requires an argument, and an input commandline has the option argument at the same argv item, argparse deletes initial '=' from it. This behavior is inconsistent with other implementations of the same parsing (at least: getopt, getopt_long from glibc or FreeBSD libc; getopt and optparse from Python standard library).

Actual result: initial '=' is deleted under the described conditions.

Expected result: initial '=' is kept in the collected option value.

Example code:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-Q', type=str)
args = parser.parse_args()
print(getattr(args, 'Q', None))

Running it:

$ ./t_eq_argparse.py -Q22
22
$ ./t_eq_argparse.py -Q=22
22

With a separate argument, truncating has no place:

$ ./t_eq_argparse.py -Q =22
=22

Compare to getopt module:

$ ./t_eq_getopt.py -Q22
22
$ ./t_eq_getopt.py -Q=22
=22

The same result with libc getopt (Ubuntu 22.04) and optparse module. Test code for getopt and optparse is obvious.

The issue is present with today's Lib/argparse.py from github trunk.

CPython versions tested on:

3.10, CPython main branch

Operating systems tested on:

Linux

netch80 commented 3 hours ago

Credits for finding to: discussion at: https://habr.com/ru/companies/timeweb/articles/840200/

savannahostrowski commented 3 hours ago

While I don't have the historical context to understand why this behaviour differs between optparse and argparse, I feel like this is expected behaviour. Using = as a delimiter between the option and the value is pretty standard.

Changing the behaviour is also likely to be a hugely breaking change at this point, given that many folks rely on this convention.

netch80 commented 3 hours ago

Using = as a delimiter between the option and the value is pretty standard.

It is not. It could be in another universe, but this is not how other libraries work now.

Forcing '=' between option name and value, if they are in the same argv item, is the matter of fact for long options because 1) they need an explicit name terminator and 2) they allow optional argument case (and this could have been also done because of opportunity by (1)). But this is not how short options work. They are either without an argument or with mandatory argument, and '=' is not added in the latter case.

You may, of course, make the current behavior nailed and documented... but you'll gather curses from all programmers that face the discrepancy.

given that many folks rely on this convention.

Extremely unlikely, because default expectation is what is average among the whole industry - and this is not how argparse works to date.