Argparse - 不同的必需参数取决于提供的标志

Argparse - different required parameters depnding on flag provided

我在 bash 中编写了一个工具,我试图将其转换为 python 以便将我的技能扩展到初学者之外,但由于我最初格式化命令的方式而遇到障碍.

该工具在通常名为 HOSTNAME01-08 的集群中的一组服务器上重新启动服务,因此原始工具采用主机名、集群范围、服务和操作:

$ prog.sh hostname cluster_range httpd status (ex. of range would be 01-04)

它还有第二个功能,只做端口检查

$ prog.sh -p port_number hostname cluster_range

第二个命令不需要service和action参数。这就是我遇到问题的地方。

在将其转换为 python 时,我正在尝试对所有选项和命令使用 argparse,因为我真的很喜欢它能够输出清晰的用法和帮助信息,但原始工具的第二个功能是使这个有点难。

使用 argparse 如果我设置工作正常的 '-p' 标志,但它仍然需要最后两个不需要的参数,或者失败 "too few arguments"

我认为子解析器可能是可行的方法,但子解析器似乎不适用于标志样式名称(我好像在某处读到它去掉了它?)。另一个问题是,如果我为“-p”创建子解析器,即使使用专有名称(比如 portcheck),它也只有在我为其他任务(称为主任务)创建子解析器时才会起作用,它不会接受主解析器的基本参数和子解析器的单独参数。所以我将被迫使用像

这样的命令
$ prog.py  main-task  hostname  range  service  action
$ prog.py  portcheck  port_num  hostname  range

有没有办法使用可选的“-p”标志并触发它不需要其他两个参数?我能想到的最佳解决方案是检查 -p 标志,如果 true 将这两个变量设置为空字符串,是否可以在 if 语句中调整这些 arg 值?我可以将这两个参数设置为默认为空,但如果它们没有提供基本函数的所有参数,我就无法进行错误检查,从而破坏了 argparse 的目的。我最初开始使用 sys.argv 但我认为 argparse 会更 pythonic 并且是初学者尝试的一个很好的课程。也许 sys.argv 可能是最好的方式?

argparse 代码我目前有:

parser = argparse.ArgumentParser(
    usage=None,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    description=textwrap.dedent('''\
    Usage:
    drtt BASE-HOSTNAME  CLS-RANGE  SERVICE  ACTION
    ex. drtt HOSTNAME 01-08 sshd status

    For port check only:
    drtt [-p, --port-number] PORT-NUMBER  BASE-HOSTNAME  CLS-RANGE
    ex. drtt -p 1234 HOSTNAME 01-08'''))

parser.add_argument('base_hostname', help='Host name only')
parser.add_argument('--port-number', '-p', type=int, metavar='PORT-NUMBER', help="Port number to check if listening")
parser.add_argument('cls_range', help='Number of hosts in cluster (written as start-finish ex. 01-16)')
parser.add_argument('service', help='Service/Process to perform an action on')
parser.add_argument('action', help='start, stop status or restart')
args = parser.parse_args()

抱歉啰嗦post

您可以将最后两个参数的 nargs 设置为 '?'(0 或 1),如果 -p 不存在,则手动检查它们是否都存在:

if args.port_number is None and (args.service is None or args.action is None):
    parser.print_help()
    parser.error("Missing mandatory arguments sevice and action")