As explained in: Argparse - do not catch positional arguments with `nargs`.
an nargs='+'
optional
(flagged argument) followed by a positional
has problems. The optional
consumes all the strings, leaving none for the positional
. There is a proposed bug patch, but it hasn't been released.
The normal quick solution is to use '--'
to mark the end of the optional
and its arguments. Everything else is treated as positionals
. You could also put some other flagged argument in between.
What complicates your case is that -s
takes choices. And the positional
is a subparsers
, which also takes choices, ['build', 'run']
. As a human you understand 's2' as a choice that belongs to -s
, and 'build' as one of the parsers. But argparse
does not allocate arguments based on choices; it just uses counts (the nargs
). choices
are checked after allocating the arguments.
I'd have to look at the code to see why '-s s1 s2 -- build'
raises a subparsers choices error. Normally '--' is ignored. But apparently subparsers
is not doing that. It is a special positional
Action class.
==========================
I found the code that explains your '--'
problem. In a function that converts strings to the type
, there is a code block:
# for everything but PARSER, REMAINDER args, strip out first '--'
if action.nargs not in [PARSER, REMAINDER]:
try:
arg_strings.remove('--')
except ValueError:
pass
Your subparsers
argument has nargs=PARSER
, so the --
is not removed.
============================
I think you need to change -s
so it accepts a fixed number of arguments. Or define some other optional
, useful or not, that can mark its end. Feel free to look at the linked bug issue if you want to get into the argparse
guts.