This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author paul.j3
Recipients paul.j3, rhettinger, vreuter
Date 2021-04-25.06:56:00
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1619333762.26.0.242771351703.issue43876@roundup.psfhosted.org>
In-reply-to
Content
Let's see if I can clarify somethings.  But first, I should say that I've worked with this code for so long, that I may miss things that could confuse a beginner.

A basic distinction is between "optionals" and "positionals".  I put those in quotes because that's not the same as "required or not".  Talk about "options" in commandline arguments goes way back (see getopt, and optparse).

An "optional" is identified by a flag string, such as "-f" or "--foo", short or long, single or double dash.  I prefer to call these "flagged arguments".  "optionals" can occur in any order, and even repeatedly.

A "postional" is identified by position, without any sort of flag string.  In earlier parsers, these where the extras, the strings that weren't handled by "options".  These can only occur in the defined order.  

Conventionally, optionals come first, and positionals at the end.  That's how most "help/usage" messages display them.  But argparse tries to handle them in any order.

Both kinds can take a "nargs" parameter.  This specifies how many arguments (or strings) are required, either following the flag string, or as part of position.  Obviously if you don't specify the flag, you don't have to provide its arguments either.  

There's another point of confusion.  "parse.add_argument" creates an "Action", also called an "argument".  And each "action" has a 'nargs' that specifies how many "arguments" go along with it.  Sorry.


The default "nargs" value is "None", which means 1 string.  "?" means zro or one (optional, but in a different sense than flagged).  "*" means any number.  "+" means one or more.  nargs could also be a number, e.g. "2".  There isn't anything that specifies "2 or more" or "2 or 3" (though that has been requested).  "?+*" are used in basically the same sense as in regex/re patterns.

There's another parameter, "action", which also controls the number of required strings.  With "store_true" no string is allowed after the flag, effectively "nargs=0" (this action makes no sense for positionals).  It's actually of subclass of "store_const", with a default "False" and const "True".

With a flagged argument, you may also specify a "required" parameter.  That's convenient, but does lead to confusing terminology.  "optionals" may be "required", and a "positional" with "?" is optional/not-required.  

Since "+" and "*" allow many strings, something has to define the end of that list.  That end is either the end of the input, or the next flag string. If you are just using flagged arguments this isn't a problem.  But with "positionals", it is hard to handle more than one open-end nargs.  Or to use such a "positional" after an open-ended "optional".  As with regex, these nargs are "greedy".  

In some ways, the documentation is more complicated than the code itself.  The code is well written, with different methods and classes handling different issues.  The code itself does not have a lot of complicated rules and conditions.  The complexity comes from how the different pieces interact.

"flagged vs positional", nargs, and "required" are separate specifications, though they do have significant interactions.


In your example:

    parser.add_argument("outdata", help="Path to output data file")
    parser.add_argument("plotTimes", nargs='*', help="Times to plot")
    parser.add_argument("outplot", help="Path to output plot file")

"outdata" takes one string.  "outplot" takes another.  "plotTimes" then gets anything left over in between.  An empty list of strings satisfies its "nargs".  The strings are actually allocated with a regex expression.

With `arg_argument('--foo', nargs='+')`,

    --foo one
    --foo one two three

are both allowed.  With "*",

     --foo

is also allowed.  For a "positional" omit the "--foo".  That means that a "positional" with "*" is always seen (which can require some special edge case handling).
History
Date User Action Args
2021-04-25 06:56:02paul.j3setrecipients: + paul.j3, rhettinger, vreuter
2021-04-25 06:56:02paul.j3setmessageid: <1619333762.26.0.242771351703.issue43876@roundup.psfhosted.org>
2021-04-25 06:56:02paul.j3linkissue43876 messages
2021-04-25 06:56:00paul.j3create