argparse 解决方案 requested for commands and subcommands with subcommands

argparse solution requested for commands and subcommands with subcommands

希望这会转化为一个优雅的解决方案,但我自己无法弄清楚。我一直在阅读大量示例和解释,但我似乎无法让它发挥作用。

我正在编写一个需要以下选项的程序:

myprogram:
-h              help
--DEBUG         debugging on

Commands are: dashboard / promote / deploy / auto-tag / dbquery
Some commands have sub-commands.

Dashboard prosesing:
  dashboard <ALL | DEBUG | AAA [sub1-aaa |  ...] >

Promoting:
  promote <environment> [to environment] <system> [version]

Deployment
  deploy <system> [version] <in environment>

Auto-tagging
  auto-tag <repo> <project> [--days-back]

Database queries  (--tab is optional)
         (system or env or both are required)
  dbquery lock set    <system | environment>   [--tab]
  dbquery lock clear  <system | environment>   [--tab]
  dbquery lock show   <system | environment | before-date | after-date>   [--tab]

  dbquery promote list <system| version| environment | before-date | after-date>  [--tab]
  dbquery deploy list <system| version| environment | before-date | after-date>   [--tab]

如果使用命令,则需要一些子命令或选项。

我很难使用 argparse 库完成这项工作。我尝试使用 add_argument_group、子解析器等。但我想我在这里遗漏了一些基本的东西。我发现接近的所有示例都是关于 svn 的,但它们似乎只在 svn 之后进入 1 级。我需要更多,或者不同的方法。

如果可能,我想将 dbquery deploy list 之后的所有参数设为可选,至少需要 1 个选项。但是区分系统名称和环境名称可能会变得棘手,因此最好更改此名称:

dbquery lock set    <system | environment>

进入

dbquery lock set    <system=system | env=environment>

p.s。 [] 之间的选项是可选的,<> 之间的选项是必需的。

提前致谢。

针对提供我的代码的评论,让我们关注 dbquery,因为其余部分可能是重复的:

import argparse
parser = argparse.ArgumentParser(description="Main cli tool for processing in the CD pipeline (%s)" % VERSION)
subparsers = parser.add_subparsers(help='additional help',title='subcommands')
dbq_parser=subparsers.add_parser("dbqueue", aliases=['dbq'])
dbq_group_lock = dbq_parser.add_argument_group('lock', 'lock desc')
dbq_group_promote =dbq_parser.add_argument_group('promote')
dbq_group_deploy = dbq_parser.add_argument_group('deploy','Deployment description')

dbq_group_lock.add_argument('set', help="Sets lock")
dbq_group_lock.add_argument('clear', help='Clears lock')
dbq_group_lock.add_argument('show', help='Show lock status')

dbq_group_deploy.add_argument('name system etc')

执行结果:

# python3 main.py -h
usage: main.py [-h] [--debug] {dbqueue,dbq} ...

Main cli tool for processing in the CD pipeline (cdv3, Jun 2019, F.IJskes)

optional arguments:
  -h, --help     show this help message and exit
  --debug        Generate debug output and keep temp directories

subcommands:
  {dbqueue,dbq}  additional help

这看起来不错,但是:

#python3 main.py dbq -h
usage: main.py dbqueue [-h] set clear show name system etc

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

lock:
  lock desc

  set              Sets lock
  clear            Clears lock
  show             Show lock status

显示预期参数不是锁定、提升或部署。

好的,反馈有助于我的理解。我现在明白解析器可以获得子解析器,而那些可以获得解析器。所以一个人可以去的深度可能没有限制。 这个新见解让我想到了这一点:(我的工作示例的部分副本)


import argparse
main_parser = argparse.ArgumentParser(description="Main cli tool for processing in the CD pipeline (%s)" % VERSION)

main_subparsers = main_parser.add_subparsers(help='',title='Possible commnds')

dashbrd_subparser = main_subparsers.add_parser('dashboard', help="Proces specified dashboards", allow_abbrev=True)
dashbrd_subparser.add_argument('who?',help='Proces dashboard for ALL, Supplier or DEBUG what should happen.')
dashbrd_subparser.add_argument('-subsystem', help='Select subsystem to proces for given supplier')

dbq_main=main_subparsers.add_parser("dbquery", help="Query database for locks,deployments or promotes")
dbq_main_sub=dbq_main.add_subparsers(help="additions help", title='sub commands for dbquery')
dbq_lock=dbq_main_sub.add_parser('lock', help='query db for lock(s)')
dbq_lock_sub=dbq_lock.add_subparsers(help='', title='subcommands for lock')
dbq_lock_sub_set=dbq_lock_sub.add_parser('set', help='sets a lock')
dbq_lock_sub_set.add_argument('-env', required=True)
dbq_lock_sub_set.add_argument('--tab',required=False, action="store_true" )
dbq_lock_sub_clear=dbq_lock_sub.add_parser('clear', help='clears a lock')
# dbq_lock_sub_set.add_argument('-env', required=True)
# dbq_lock_sub_set.add_argument('--tab', required=False)
dbq_lock_sub_show=dbq_lock_sub.add_parser('show', help='shows a lock/locks')
# dbq_lock_sub_set.add_argument('-env', required=True)
# dbq_lock_sub_set.add_argument('--tab', required=False)

print( vars(main_parser.parse_args()))
exit(1)

我现在似乎只有在不同子命令中使用“-env”和“-subsystem”参数时才会遇到问题。因为当我将它们添加到另一个解析器时存在冲突。 我也没有关于选择了哪些选项的数据。这也是需要的东西。

差不多了,我现在拥有的东西在很大程度上是有用的,所以我会 post 这样其他用户可能会从我的工作中受益,而 hpaulj 的评论让我受益匪浅到可以澄清其他部分的其他文件。

# see: https://pymotw.com/3/argparse/

# BLOCK FOR SHARED options used at more places,
# see also: 
env_shared = argparse.ArgumentParser(add_help=False)
env_shared.add_argument('-env', action="store", help='name of environment <tst|acc|acc2|prod|...>', metavar='<environment>', required=True)
ds_shared = argparse.ArgumentParser(add_help=False)
ds_shared.add_argument('-ds', action="store", help='name of subsystem to use <ivs-gui|ivs-vpo|...>', metavar='<system name>', required=True)
version_shared = argparse.ArgumentParser(add_help=False)
version_shared.add_argument('-version', action="store", help='version to use. If used, specify at least sprint as in 1.61', metavar='<version>')
tab_shared=argparse.ArgumentParser(add_help=False)
tab_shared.add_argument('--tab', required=False, action="store_true", help='Use nice tabulation for output')
# END OF SHARED options

# MAIN
main_p = argparse.ArgumentParser(description="Main cli tool for use in the CD v3 pipeline (%s)" % VERSION, epilog='Defaults are taken from the configuration file, which is pulled from git when needed.', )
# Change formatting of help output for main-parser
main_p.formatter_class = lambda prog: argparse.HelpFormatter(prog, max_help_position=30, width=80)
main_p.add_argument("--debug", action="store_true", help="Generate debug output and keep temp directories")

# MAIN-SUB
main_s_p = main_p.add_subparsers(title='Commands', dest='main_cmd')

# MAIN-SUB-DASHBOARD
dashbrd_p = main_s_p.add_parser('dashboard', aliases=['db'], help="Proces specified dashboards", parents=[ds_shared])
dashbrd_p.formatter_class = lambda prog: argparse.HelpFormatter(prog, max_help_position=40, width=80)
dashbrd_p.add_argument('which', help='Proces dashboard for <ALL|Supplier|DEBUG what would happen>. If supplier is specified an optional subsystem to be processed can be passed using -ds')

# MAIN-SUB-QUERY
query_p = main_s_p.add_parser("query", aliases=['qry'], help="Query database for locks,deployments or promotes")
query_p.formatter_class = lambda prog: argparse.HelpFormatter(prog, max_help_position=40, width=80)
# MAIN-SUB-QUERY-SUB
query_s_p = query_p.add_subparsers(help="additions help", title='sub commands for query', dest='query_cmd')
# MAIN-SUB-QUERY-LOCK
q_lock_p = query_s_p.add_parser('lock', help='query db for lock(s)', )
# MAIN-SUB-QUERY-LOCK-SUB
q_lock_sub = q_lock_p.add_subparsers(help='', title='subcommands for dbquery lock', dest='lock_cmd')
# MAIN-SUB-QUERY-LOCK-SUB-SET
q_lock_set_p = q_lock_sub.add_parser('set', help='sets a lock', parents=[env_shared, ds_shared])
# MAIN-SUB-QUERY-LOCK-SUB-CLEAR
q_lock_clear_p = q_lock_sub.add_parser('clear', help='clears a lock', parents=[env_shared, ds_shared], )
# MAIN-SUB-QUERY-LOCK-SUB-SHOW
q_lock_show_p = q_lock_sub.add_parser('show', help='shows a lock/locks', parents=[env_shared, tab_shared])


# MAIN-SUB-QUERY-PROMOTE
q_promote_p = query_s_p.add_parser('promote', help='query db for promotions', parents=[env_shared,ds_shared] )

# MAIN-SUB-QUERY-DEPLOY
q_deploy_p = query_s_p.add_parser('deploy', help='query db for deployments')

# MAIN-SUB-PROMOTE
promote_p = main_s_p.add_parser('promote', help='Do a promotion.', parents=[env_shared, ds_shared, version_shared])
promote_p.add_argument('-dest', required=False, action="store", help='If used specifies the destination, otherwise defaults are used. (-dest is optional, -env is not)', metavar='<dest_env>')

# MAIN-SUB-DEPLOY
deploy_p = main_s_p.add_parser('deploy', help='Deploy software', parents=[ds_shared, env_shared])

# MAIN-SUB-AUTOTAG
autotag_p = main_s_p.add_parser('autotag', help="Autotags specified repository", parents=[ds_shared])

print("------------arguments-----------")
print(vars(main_p.parse_args()))

这创建了许多我想要的功能。