How to make argparse accept "-4^2+5.3*abs(-2-1)/2" string argument?

Mark Bourne nntp.mbourne at spamgourmet.com
Sat Jan 28 08:59:41 EST 2023


Jach Feng wrote:
> Jach Feng 在 2023年1月22日 星期日上午11:11:22 [UTC+8] 的信中寫道:
>> Fail on command line,
>>
>> e:\Works\Python>py infix2postfix.py "-4^2+5.3*abs(-2-1)/2"
>> usage: infix2postfix.py [-h] [infix]
>> infix2postfix.py: error: unrecognized arguments: -4^2+5.3*abs(-2-1)/2
>>
>> Also fail in REPL,
>>
>> e:\Works\Python>py
>> Python 3.8.8 (tags/v3.8.8:024d805, Feb 19 2021, 13:08:11) [MSC v.1928 32 bit (Intel)] on win32
>> Type "help", "copyright", "credits" or "license" for more information.
>>>>> import argparse
>>>>> parser = argparse.ArgumentParser(description='Convert infix notation to postfix')
>>>>> parser.parse_args("-4^2+5.3*abs(-2-1)/2")
>> usage: [-h]
>> : error: unrecognized arguments: - 4 ^ 2 + 5 . 3 * a b s ( - 2 - 1 ) / 2
>>
>> Just can't figure out where is wrong!?
>>
>> --Jach
> I have to admit that I don't know the background upon which the argparse was built. The good side is that I don't carry its historical knowledge ( or burden?), that's why I can use it in a new way which may make someone feel uneasy.

If you can use it in the way you want, that's great.  I thought you were 
asking here because you *couldn't* use it the way you want.

You're writing a command-line application.  Your users are either 
already familiar with the conventions of command-line applications, or 
they'll soon need to be.

If your application supports options beginning with a "-" (which is what 
argparse gives you, even if only the default "-h" and "--help" options 
are actually valid), and you also need to be able to pass positional 
arguments which begin with a "-", you need some way for the user to 
indicate whether any particular argument is an option or positional. 
Using "--" to indicate that all subsequent arguments are positional, not 
options, is a common convention.

Some of your users might already be familiar with that convention from 
other command-line tools.  By using the same convention, you'd be making 
it easier for them to use yours.  Others might not already be familiar 
with the convention, but by being consistent with other tools you'd 
still be helping them when they eventually do come across it elsewhere. 
You can always include an explanation of using "--" in your usage output 
or other documentation.

Apart from dealing with how to pass an argument beginning with "-", your 
users will also likely have to deal with the features of whichever shell 
they're using, which you have no control over.  For example, it's quite 
common to need to enclose an argument in quotes if it contains spaces. 
It may also be necessary to use quotes if certain special characters are 
used, such as "*", "?" or "$" (perhaps "%" on Windows).

> The reason I am still keep on using argparse on this "one positional argument only" CLI app is that I can't see what advantage I can get when writing code to handling sys.argv directly for the following two situations,
> -----
> e:\Works\Python>py infix2postfix.py
> usage: infix2postfix.py [-h] infix
> infix2postfix.py: error: the following arguments are required: infix
> 
> e:\Works\Python>py infix2postfix.py -h
> usage: infix2postfix.py [-h] infix
> 
> Convert infix notation to postfix
> 
> positional arguments:
>    infix       Put equations in quote if there is space in it and separate each one with a comma, ie.
>                "-4^2+5.3*abs(-2-1)/2, abs(Abc)*(B+C)/D, (-3) * sqrt(1-(x1/7)*(y1/7)) * sqrt(abs((x0-4.5)/(y0-4)))"
> 
> optional arguments:
>    -h, --help  show this help message and exit
> -----
> 
> comparing with code using the argparse below,
> 
> import argparse
> sample = "-4^2+5.3*abs(-2-1)/2, abs(Abc)*(B+C)/D, (-3) * sqrt(1-(x1/7)*(y1/7)) * sqrt(abs((x0-4.5)/(y0-4)))"
> parser = argparse.ArgumentParser(description='Convert infix notation to postfix')
> parser.add_argument('infix',
> help='Put equations in quote if there is space in it and separate each one with a comma, ie. "{}"'.format(sample))
> 
> import sys
> if len(sys.argv) > 1 and not '-h' in sys.argv:
> ....sys.argv.insert(1, '--')
> args = parser.parse_args()

Personally, I do quite often use argparse even for simple cases, partly 
because it produces nice usage details, and deals with wrapping the 
output to whatever width the console is.  But I work with it rather than 
against it, and accept that a "--" is needed if a positional argument 
starts with a "-".

I notice you explain the need to enclose the equation in quotes if it 
contains spaces.  That's not even a feature of your application, but of 
the shell used to call it.  So why so much objection to explaining the 
need for "--"?

Depending on the shell, there are other cases where quoting might be 
needed, e.g. if the equation includes a "*" or "?" and happens to look 
like a pattern matching files in the current directory (most shells I've 
used pass the pattern unchanged if it doesn't match any files).  In 
bash, if a "$" is used I'd need to enclose that in 'single quotes' 
(can't even use "double quotes" for that one).  You can't really expect 
to document all that sort of thing, because it depends on which shell 
the user happens to run your application from - you just have to trust 
the user to know or learn how to use their shell.

-- 
Mark.


More information about the Python-list mailing list