Python argparse:必须在1个参数或参数组之间进行选择

Python argparse:必须在1个参数或参数组之间进行选择,python,argparse,Python,Argparse,在我的python应用程序中,我的用户可以选择指定: 一次约会 日期范围(开始、结束) 我在一个相互排斥的组中创建了一个嵌套的参数组: argument_group +--- mutually_exclusive_group +--- date (argument) +--- argument_group +--- start (argument) +--- end

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

  • 一次约会
  • 日期范围(开始、结束)
我在一个相互排斥的
组中创建了一个嵌套的
参数组

argument_group
+--- mutually_exclusive_group
     +--- date                 (argument)
     +--- argument_group
          +--- start           (argument)
          +--- end             (argument)
我想向我的用户指出需要
日期
(开始,结束)
,并且如果他们选择了组,则两个(
开始,结束
)都是必需的:

这就是我到目前为止所做的:

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)
问题1:

指定
(开始,结束)
不起作用,因为argparse(我猜)看不到我指定了
互斥组的
参数组
部分,而不是
日期
,并且由于互斥组是必需的,它会发出:

$ ./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
我可以通过使互斥组不必来解决这个问题,但这显然是不正确的,并且不适用于没有指定任何内容的情况(事实上,这是必需的)

问题2:

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

互斥组
中的选项周围没有
(选项1 |选项2)
,如果我没有嵌套组的话就会有

此外,甚至没有显示
开始
结束
的帮助

$ ./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)
我想要的是这样的东西:

$ ./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)

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

我不知道如何表达参数和参数组之间的选择,但解决问题的简单方法是使用以下方法:

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('--date-range',
    nargs=2, help='Start and End')

只需将日期范围指定为带有两个参数的单参数。

如果您的评论是
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')
使用自定义的
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
因此,如果给定参数:

args = ap.parse_args(['--start','20100102', '--end', '20121123'])
# args.start = 20100102
# args.end   = 20121123
如果没有:

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

# args.start = 20100102
# args.end   = 20100102
当然,如果您在解析后只需操作
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

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

谢谢,这是一个我从未考虑过的聪明的工作!不错!我想更明确地说明这些选项(根据我原来的问题),但如果使用了
--date
,则这是一个不错的第二个选项,在
--start
--end
中它的等价物是什么?@Idlehands就好像
start
==
end
一个
参数组
不能嵌套在
互斥组
中一样。它不会引发错误,但不会执行您想要的操作。
参数组
仅影响帮助显示;它在解析过程中没有什么特殊的功能。相反地,
互斥的
组控制使用(在限制范围内)并在解析过程中测试出现的情况(使用简单的异或逻辑,没有“and”或“any”子组)。@hpaulj所以实际上,我要找的,argparse不支持?正确。参数组合的内置逻辑非常简单——只是平面异或。我在一个bug/问题中添加了一个更全面的机制,但我认为它永远不会实现。测试逻辑还不错,但是生成一个有意义的使用行太复杂了。这是我最初拥有的,但后来尝试通过添加互斥组使其更智能。我可能会回到你在这里提出的建议,因为我现在想做的似乎是不可能的。如果将
--date
(-start,--end)
明确分开,没有什么好处,我会坚持KISS原则。它使您的实现更干净。我正要提到KISS-这是一个有原因的原则!:)谢谢你的帮助!