1

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.

4
  • 1
    I'm not familiar with make but I am with argparse. Could you expand the example with some more possible arguments to make it clear what you want to achieve? ATM I think you want an argument with options Commented Feb 17, 2020 at 16:37
  • 1
    The source of the error is escaping me, but note that having an argument named update doesn't mean you are restricted to providing the value update on the command line. Commented Feb 17, 2020 at 16:38
  • Sure, the functionality can be anything, but in general if I type python test.py make X I want to run some python code under if args.x == True. Commented Feb 17, 2020 at 16:38
  • store_true and store_false only make sense with flagged (optionals) arguments. With store_false, ` --clean` flag would set args.clean to False, otherwise it would True. Commented Feb 17, 2020 at 17:34

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

You're absolutely correct I was trying to do this with subcommands. This cli already has some extra functionality using subparsers so I wanted to tack on a make simulator, and when I say boolean I meant "if the argument is present then I want to execute this code, else do nothing"
1

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.

1 Comment

This definately solves the problem, however now I lose the nice help descriptions, there's going to be about a dozen choices each with a DAG behind it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.