Reputation: 1290
I've read through the Python argparse documentation several times and must be missing something huge. I'm trying to add a makefile like syntax onto my cli tool, but despite the --help
flag showing me the expected behavior the execution of it errors out:
test.py
import argparse
import os
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
make_subparser = subparsers.add_parser("make")
make_subparser.add_argument("update", action="store_false", help="Runs all make targets")
make_subparser.add_argument("clean", action="store_false", help="Cleans up everything done previously")
args = parser.parse_args()
if args.update:
os.system("touch test.txt")
elif args.clean:
os.system("rm test.txt")
else:
print("Bad args, see: python test.py make --help.")
if __name__ == "__main__":
main()
Then in my terminal:
$> python test.py make --help
usage: test.py make [-h]
positional arguments:
update Runs all make targets
$> python test.py make update
usage: test.py [-h] {make} ...
test.py: error: unrecognized arguments: update
$> # this should make a file
$>
$> python test.py make clean
usage: test.py [-h] {make} ...
test.py: error: unrecognized arguments: clean
$> # this should delete the file
This works fine if I swap out the action="store_false"
for action="store_true"
, but there's a dozen make commands so I only want to run the one that the user adds in the cli, if they try to enter any more it should exit.
Upvotes: 1
Views: 489
Reputation: 530960
Instead of separate boolean flags, use single argument target
which allows a restricted set of values.
make_subparser.add_argument("target", choices=['update', 'clean'], help="Runs all make targets")
if args.target == "update":
...
elif args.target == "clean":
...
No else
is needed, because any attempt to pass something other than update
or clean
will cause an error in parse_args
, before args.target
ever gets set.
Upvotes: 1
Reputation: 545528
In the POSIX (and POSIX adjacent) world, boolean arguments are handled as flags which are passed via the command line as --argument
. What you want isn’t boolean arguments (and that isn’t how Make treats them either), it’s simply a variable number of positional arguments, i.e. having arity *
:
make_subparser.add_argument('targets', nargs='*')
This would be closest to how Make operates. However, from your command line it looks more like what you actually want is nested subcommands.
Upvotes: 1