dHannasch added the comment:
I've attached a file that can be run, but it's a simple script that I can
include here inline, too:
"""
Context:
I am trying to set up a cookiecutter so that newly-created packages will come
with a Jupyter notebook users can play with.
That is, python -m package_name jupyter would open up a Jupyter quickstart
notebook demonstrating the package's features.
argparse.REMAINDER as the first argument isn't important for a top-level
parser, since we can work around it by not using argparse at all,
but using argparse.REMAINDER in a subparser seems like a pretty straightforward
use case.
Any time we want to dispatch a subcommand to a separate tool --- forwarding all
following arguments --- we're going to need it.
"""
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('command', default='cmdname')
parser.add_argument('cmdname_args', nargs=argparse.REMAINDER)
args = parser.parse_args('cmdname --arg1 XX ZZ --foobar'.split())
if args != argparse.Namespace(cmdname_args=['--arg1', 'XX', 'ZZ', '--foobar'],
command='cmdname'):
raise Exception(args)
print('This is how argparse.REMAINDER works when there is an argument in
front.')
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('command', default='cmdname')
parser.add_argument('cmdname_args', nargs=argparse.REMAINDER)
args = parser.parse_args('--foo B cmdname --arg1 XX ZZ --foobar'.split())
if args != argparse.Namespace(cmdname_args=['--arg1', 'XX', 'ZZ', '--foobar'],
command='cmdname', foo='B'):
raise Exception(args)
print('This is how argparse.REMAINDER works there is an option in front.')
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
subparsers = parser.add_subparsers(dest='command')
commandParser = subparsers.add_parser('cmdname')
commandParser.add_argument('--filler-boundary-marker', dest='cmdname_args',
nargs=argparse.REMAINDER)
args = parser.parse_args('--foo B cmdname --filler-boundary-marker --arg1 XX ZZ
--foobar'.split())
if args != argparse.Namespace(cmdname_args=['--arg1', 'XX', 'ZZ', '--foobar'],
command='cmdname', foo='B'):
raise Exception(args)
print('This is how argparse.REMAINDER works with a visible "filler" name for
the list of arguments.')
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
subparsers = parser.add_subparsers(dest='command')
commandParser = subparsers.add_parser('cmdname')
commandParser.add_argument('--filler-boundary-marker', dest='cmdname_args',
nargs=argparse.REMAINDER)
args = parser.parse_args('cmdname --filler-boundary-marker --arg1 XX ZZ
--foobar --foo B'.split())
if args != argparse.Namespace(cmdname_args=['--arg1', 'XX', 'ZZ', '--foobar',
'--foo', 'B'], command='cmdname', foo=None):
raise Exception(args)
print("If an optional argument is provided after cmdname instead of before, it
will get interpreted as part of the argparse.REMAINDER instead of normally. And
that's great! We don't even need to be paranoid about other functions of our
command-line tool sharing arguments with the tool we want to wrap. Everything
will be forwarded.")
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
subparsers = parser.add_subparsers(dest='command')
commandParser = subparsers.add_parser('cmdname')
commandParser.add_argument('positional_arg')
commandParser.add_argument('cmdname_args', nargs=argparse.REMAINDER)
args = parser.parse_args('cmdname can_put_anything_here --arg1 XX ZZ --foobar
--foo B'.split())
if args != argparse.Namespace(cmdname_args=['--arg1', 'XX', 'ZZ', '--foobar',
'--foo', 'B'], command='cmdname', positional_arg='can_put_anything_here',
foo=None):
raise Exception(args)
print("If an optional argument is provided after cmdname instead of before, it
will get interpreted as part of the argparse.REMAINDER instead of normally. And
that's great! We don't even need to be paranoid about other functions of our
command-line tool sharing arguments with the tool we want to wrap. Everything
will be forwarded.")
"""
Note that this means we can fix the bug simply by,
whenever the cmdname subparser is invoked and the cmdname subparser uses
argparse.REMAINDER,
automatically adding an imaginary first positional argument to the s