how to set argparse to exclude optional argument by values of positional argument

StackOverflow https://stackoverflow.com/questions/22470483

  •  16-06-2023
  •  | 
  •  

the arg include an action field and optional switches that modify the behavior of the actions.

the argparse code is like the below:

parser=argparse.ArgumentParser()
parser.add-argument('action',metavar='action', choices=['analysis','report','update'],nargs='?', default='report')
parser.add-argument('-d',dest='delay',type=int, choices=range(1,10),default=1)
parser.add-argument('-v',dest='verbose',action='store-true',default=False)
parser.add-argument('-o',dest='offline',action='store-true',default=False)
parser.add-argument('-n',dest='names',required=False)

i want to make the switch option -o, -d, -v only available for action=report, while option -n only available for action=analysis.

i know there is a mutual group setting, but it is just set for the arguments not for the argument values!

btw, does argparse support combine options, like -vo...???

有帮助吗?

解决方案

First: Yes, combined options like -vo are supported

Now to the action switching: Adding a SubParser to your ArgumentParser is exactely what you want to do. See Section 15.4.5.1. Sub-commands in the Documentation of argparse, everything is explained to some detail and with example there

EDIT: I know refer to your comment below this post: If you do not provide a subcommand parameter in the program call, the parser normally gives you a kind advice how to use the program and then exits with a "too few arguments error" I rewrote your code to show this

test.py

import argparse
parser=argparse.ArgumentParser()

subparsers = parser.add_subparsers(help='sub-command help')

parser_analysis = subparsers.add_parser('analysis', help='analysis help text')
parser_analysis.add_argument('-n',dest='names',required=False)

parser_report = subparsers.add_parser('report', help='report help text')
parser_report.add_argument('-d',dest='delay',type=int, choices=range(1,10),default=1)
parser_report.add_argument('-v',dest='verbose',action='store_true',default=False)
parser_report.add_argument('-o',dest='offline',action='store_true',default=False)

parser_update = subparsers.add_parser('update', help='update help text')
parser.parse_args()

Now some calls of this test.py with different arguments:

$python test.py
usage: test.py [-h] {analysis,report,update} ...
test.py: error: too few arguments
$python test.py -h
usage: test.py [-h] {analysis,report,update} ...

positional arguments:
  {analysis,report,update}
                        sub-command help
    analysis            analysis help text
    report              report help text
    update              update help text

optional arguments:
  -h, --help            show this help message and exit
$python test.py report -h
usage: test.py report [-h] [-d {1,2,3,4,5,6,7,8,9}] [-v] [-o]

optional arguments:
  -h, --help            show this help message and exit
  -d {1,2,3,4,5,6,7,8,9}
  -v
  -o

So as I see it the only problem is that the program throws an error after calling python test.py without any subcommand. So I would do s.th. like this

try:
  args=parser.parse_args()
except:
  exit(0)

to avoid that the user sees that there was an unhandled error. You have then the same behaviour as i.e. the svn command.

If you want to handle this in the way that a default subcommand is executed, you whould have to do s.th. like mentioned in this post answer:

Argparse - How to Specify a Default Subcommand

import sys
#...your parser definitions
if (len(sys.argv) < 2):
    args = parser.parse_args(['update'])
else:
    args = parser.parse_args()

This would parse a command update if the argument list in sys.argv is smaller than 2. Why 2? Because the first argument in the argument list is always the program which you called, i.e. test.py

The question is, do you really want this behaviour? Because there is no need for calling test.py update if i can always call test.py, so users will probably get lazy and never use test.py update command. Also if you later want a different default behaviour like test.py starting an interactive mode, users which are by then used to calling test.py for updating will get confused or their scripts which use your program get broken.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top