argparse:需要在 1 个参数或参数组之间进行选择

Ste*_*mer 5 python argparse

在我的 python 应用程序中,我的用户可以选择指定:

  • 一次约会
  • 日期范围(开始、结束)

argument_group我在 a 中创建了一个嵌套mutually_exclusive_group

argument_group
+--- mutually_exclusive_group
     +--- date                 (argument)
     +--- argument_group
          +--- start           (argument)
          +--- end             (argument)
Run Code Online (Sandbox Code Playgroud)

我想向我的用户表明,一个 date 一个组(start, end)是必需的,如果他们选择该组,则两个 ( start, end) 都是必需的:

这是我到目前为止所拥有的:

ap = argparse.ArgumentParser()
grp = ap.add_argument_group('test dates')
date_group = grp.add_mutually_exclusive_group(required=True)

date_group.add_argument('--date', help='date (YYYYMMDD)')
date_range = date_group.add_argument_group('date range')

date_range.add_argument('--start',help='start date (YYYYMMDD)', required=True)
date_range.add_argument('--end',  help='end date (YYYYMMDD)', required=True)
Run Code Online (Sandbox Code Playgroud)

问题一:

指定(start, end)不起作用,因为 argparse (我猜)无法看到我指定了替代的argument_group部分,并且由于需要mutual_exclusive_group ,所以它会报错:mutually_exclusive_groupdate

$ ./app.py --start 20180101 --end 20180102
usage: app.py [-h] --date date --start date --end date
app.py: error: one of the arguments --date is required
Run Code Online (Sandbox Code Playgroud)

我可以通过使mutual_exclusive_group not required来解决这个问题,但这显然是不正确的,并且不会捕获未指定任何内容的情况(事实上,它是必需的)

问题2:

不幸的是,上述帮助并没有反映我的意图:

如果我没有嵌套组,则没有(option_1 | option_2)任何选项。mutually_exclusive_group

此外,甚至没有显示start和的帮助。end

$ ./app.py --help
usage: app.py [-h] --date date --start date --end date

optional arguments:
  -h, --help         show this help message and exit

test dates:
  --date date        date (YYYYMMDD) (default: None)
Run Code Online (Sandbox Code Playgroud)

我想要的是这样的东西:

$ ./app.py --help
usage: app.py [-h] (--date date | --start date --end date)

optional arguments:
  -h, --help         show this help message and exit

test dates:
  --date date        date (YYYYMMDD) (default: None)
  --start date       start date (YYYYMMDD) (default: None)
  --end date         end date (YYYYMMDD) (default: None)
Run Code Online (Sandbox Code Playgroud)

我如何表达参数和参数组之间所需的选择?

r.o*_*ook 2

鉴于您的评论,start == end如果--date给出,我会保持简单并坚持仅两个论点:

class DefaultEnd(argparse.Action):
  def __call__(self, parser, namespace, values, option_string=None):
    setattr(namespace, self.dest, values)
    setattr(namespace, 'end', values)

ap = argparse.ArgumentParser()
ap.add_argument('--start', help='date (YYYYMMDD) Mandatory', action=DefaultEnd, required=True)
ap.add_argument('--end', help='date (YYYYMMDD) Optional, defaulted to START if not provided')
Run Code Online (Sandbox Code Playgroud)

使用自定义,如果仅提供后者,argparse.Action它也默认--end为:--start

optional arguments:
  -h, --help     show this help message and exit
  --start START  date (YYYYMMDD) Mandatory
  --end END      date (YYYYMMDD) Optional, defaulted to START if not provided
Run Code Online (Sandbox Code Playgroud)

因此,如果给出参数:

args = ap.parse_args(['--start','20100102', '--end', '20121123'])
# args.start = 20100102
# args.end   = 20121123
Run Code Online (Sandbox Code Playgroud)

如果不:

args = ap.parse_args(['--start','20100102'])

# args.start = 20100102
# args.end   = 20100102
Run Code Online (Sandbox Code Playgroud)

当然,如果您只是args在解析后进行操作并完全跳过自定义,那么您也可以让事情变得简单argparse.Action

ap.add_argument('--end', help='date (YYYYMMDD) Optional, defaulted to START if not provided', default=None)

...

args.end = args.end if args.end else args.start
Run Code Online (Sandbox Code Playgroud)

当然,这可能会改变您的后参数代码的处理方式,因此如果您的代码必须需要args.date.