1

I am trying to write a parsing for my python script where the command parameters should be in the following order,

OUTPUT : cli unmount [-h] -f FS_NAME [-n NODE_SPEC] [--evict [--force]]]

I am able to write the code for rest of the commands except for the last one. [--evict [--force]]. This means that --force argument will only apply if --evict is given.

parser = argparse.ArgumentParser('CLI demo')
sub_parser = parser.add_subparsers()
unmount = sub_parser.add_parser('unmount')
unmount.add_argument("-f", "--fs", dest="fs_name", required=True, help="filesystem name.")
unmount.add_argument("-n", "--nodes", dest="nodes", metavar='NODE_SPEC', help="pdsh style nodes hostnames (If this parameters ")

These are the two approaches I have taken for adding the optional child argument, --force to the optional parent argument, --evict,

Approach 1:

evict_parser = unmount.add_subparsers()
evict = evict_parser.add_parser("--evict", help="evict lustre clients before unmount.")
evict.add_argument("--force", dest="force", action="store_true", default=False, help="force mode for evict lustre clients.")
parser.parse_args()

and Approach 2:

parent_cmd_parser = argparse.ArgumentParser(add_help=F)
parent_cmd_parser.add_argument("--force", dest="force", action="store_true", default=False, help="force mode for evict lustre clients.")
evict_parser = unmount.add_subparsers()
evict = evict_parser.add_parser("--evict",  help="evict lustre clients before unmount.", parents=[parent_cmd_parser])

Unfortunately none is working. In first case I am not getting the desired help output/usage help and in the second the --force argument is hidden.

2
  • What should happen if --force is used without --evict? What if it is given first? Commented Sep 29, 2015 at 1:03
  • @hpaulj, in that case it would be error. since --force would be enabled only if --evict is enabled. Commented Sep 29, 2015 at 7:21

2 Answers 2

2

argparse doesn't support interdependent arguments directly.

Just add --force as a regular argument, document that it only applies when --evict is given, and give an error when --force is used without --evict:

if args.force and not args.evict:
    parser.error('--force can only be used together with --evict')
Sign up to request clarification or add additional context in comments.

3 Comments

I do not understand what do you mean by 'support independent arguments directly'? Does that mean it adding a child argument to another argument?
@BhupeshPant: yes, 'interdependent' means arguments that depend on other arguments.
oh I see, Thanks for your quick response.
1

Another option is to define --evict with nargs='?', and define both default and const.

parser.add_argument('--evict', nargs='?', default='noEvict', const='EvictWOArgument')

Then args.evict will be either 'noEvict', 'EvictWOArgument', or what ever string the user gave (e.g. 'force'). You can choose any values and interpretation that is convenient. You could even use 'choices':

In [2]: parser=argparse.ArgumentParser()    
In [4]: parser.add_argument('-e','--evict',nargs='?',choices=['force'],default=False, const=True)

In [5]: parser.parse_args([])
Out[5]: Namespace(evict=False)

In [6]: parser.parse_args(['-e'])
Out[6]: Namespace(evict=True)

In [7]: parser.parse_args(['-e','test'])
usage: ipython3.5 [-h] [-e [{force}]]
ipython3.5: error: argument -e/--evict: invalid choice: 'test' (choose from 'force')
...

In [8]: parser.parse_args(['-e','force'])
Out[8]: Namespace(evict='force')

If the patch in http://bugs.python.org/issue9334 is ever implemented, it might be possible to define '--force' as a choice. Currently the parser classifies, early on in parsing, such as string an optionals flag. Such usage could also confuse the end user - is --force an optional that can go anywhere, or a argument that must follow --evict?

2 Comments

Thanks for your reply @hpaulj. This can certainly help me with my purpose. But I am still stuck in one thing. I am getting error when I am trying to do parser.parse_args(['unmount','-f file_node','--evict', '--force']) with this line of code, unmount_parser.add_argument('--evict',nargs='?',choices=['--force'],default=False, const=True). But when I am using force instead of --force its working though. I wanted force to be --force. This is because I don't want to break existing functionality.
Right, the parser treats a '--force' string as a optionals flag, not as an argument. There is a backlogged patch (9334) that would add a args_default_to_positional parameter which would change this behavior.

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.