【问题标题】:How to show help for all subparsers in argparse when using a Class()使用 Class() 时如何在 argparse 中显示所有子解析器的帮助
【发布时间】:2015-11-04 01:14:42
【问题描述】:

对使用 argparse 和 cmd 行非常陌生。我已经开始构建一个解析器,它允许前端用户通过 cmd 终端输入数据。解析器正在调用我创建的 API() 类(创建 SQLALCHEMY 会话等),此处显示的示例:

class API(object):
    def __init__(self):
        # all the session / engine config here

    def create_user(self, username, password, firstname, lastname, email):
        new_user = User(username, password, firstname, lastname, email)
        self.session.add(new_user)
        self.session.commit()
        print(username, firstname, lastname) 

    def retrieve_user(self, username, firstname, lastname):
       # code here ... etc .

在此处的 CMD 文件中实现:

def main():

    parser = argparse.ArgumentParser(prog='API_ArgParse', description='Create, Read, Update, and Delete (CRUD) Interface Commands')
    subparsers = parser.add_subparsers(
        title='subcommands', description='valid subcommands', help='additional help')    

    api = API() # calling the API class functions/engine 

    # Create command for 'user' 
    create_parser = subparsers.add_parser('create_user', help='create a user') 
    create_parser.add_argument('username', type=str, help='username of the user')
    create_parser.add_argument('password', type=str, help='password')
    create_parser.add_argument('firstname', type=str, help='first name')
    create_parser.add_argument('lastname', type=str, help='last name')
    create_parser.add_argument('email', type=str, help='email address')
    #args = parser.parse_args() <--EDIT:removed from here and placed on bottom
    api.create_user(args.username, args.password, args.firstname, args.lastname, args.email)       

    # Retrieve command for 'user'
    retrieve_parser = subparsers.add_parser('retrieve_user', help='retrieve a user')
    retrieve_parser.add_argument('username', type=str, help='username')
    retrieve_parser.add_argument('firstname', type=str, help='first name')
    retrieve_parser.add_argument('lastname', type=str, help='last name')
    api.retrieve_user(args.username, args.firstname, args.lastname)

NEW EDIT/ADDITION OF args = parser.parse_args() 使用这两个命令来反映下面的 cmets。

     args = parser.parse_args() 
     print(args)


if __name__ == '__main__':
    main()

等等……

我的问题是终端没有打印新解析器的帮助命令(例如,retrieve_parser、update_parser 等)。我是否必须为每个部分创建一个“args = parser.parse_arg()”? 其次,我是否创建一个“args = create_parser.parse_args()”来代替“parser.parse ...”我注意到他们在终端上打印了两个不同的东西。

非常感谢任何关于放置 parse_arg() 方法的说明(考虑到 API() 函数的使用)!

【问题讨论】:

  • 尝试从终端调用retrieve_user 时,出现以下错误:usage: API_ArgParse [-h] {create_user} ... API_ArgParse: error: invalid choice: 'retrieve_user' (choose from 'create_user')
  • 第一次调用parse_args,你定义的就是create_user。这就是错误消息告诉您的内容。在创建所有子解析器后放置parse_args
  • 我把args = parser.parse_args() 放在最后(在我所有的子解析器之后),现在我得到Traceback (most recent call last): File "/usr/local/bin/notssdb-cmd", line 57, in &lt;module&gt; main() File "/usr/local/bin/notssdb-cmd", line 25, in main api.create_user(args.username, args.password, args.firstname, args.lastname, args.email) UnboundLocalError: local variable 'args' referenced before assignment,这是有道理的,因为现在在底部定义了args。我会用适当的标记来反映这一点,以便完成编辑。
  • 也许这是一个我应该构建 IF/ELIF/ELIF 语句的实例,以便解析器遍历命令直到匹配正确的命令。

标签: python-2.7 command-line-arguments argparse


【解决方案1】:

通常,您在创建 parser(包括任何子解析器)之后调用 parse_args 方法,在您需要使用生成的命名空间(通常称为 args)之前。

retrieve_parser.add_argument('lastname', type=str, help='last name')

args = parser.parse_args()  # <=========

api.retrieve_user(args.username, args.firstname, args.lastname)

parse_args 的目的是读取sys.argv 列表(shell/解释器从您的命令行创建),并使用您使用add_argument 创建的规范“解析”它等等。

主要的parser“知道”子解析器,并将 argv 列表传递给适当的解析器(由“retrieve_user”等名称选择)。

如果命令行包含-h(或--help),解析器将显示帮助消息并退出。此消息列出了子解析器,但不显示它们的参数。如果-h 跟在子解析器名称后面,则显示帮助的就是子解析器。

python main.py -h     # main help
python main.py retrieve_user -h   # subparser help

parser.print_help() 可以在您的代码中使用以显示相同的帮助消息。 retrieve_parser.print_help() 将对子解析器执行相同的操作。显然这些命令只能在main 内工作,并且在调试(而非生产)时更有用。

argparse 中没有规定显示所有子解析器的帮助。但是,您可以从我刚刚描述的print_help 命令构造这样的函数。可能有这样一个功能的答案(但我不知道什么是好的搜索词)。

粗略地说,main() 可能包括:

 parser.add_argument('--bighelp', action='store_true', help='show help for all subparsers')
 ....
 if args.bighelp:
      parser.print_help()
      subparser1.print_help()
      subparser2.print_help()
      ....
      sys.exit(1)  # if want to quit

可以从解析器中获取子解析器的列表,但维护自己的列表可能更容易、更清晰。


我专注于如何让parser 工作,而不是下一步调用api

需要修改add_subparsers,添加dest参数。

subparsers = parser.add_subparsers(dest='cmd',
    title='subcommands', description='valid subcommands', help='additional help')    

然后在你定义了所有子解析器之后:

# should call cmd since I have stored `.dest` there e.g.`subparsers = parser.add_subparsers(dest='cmd'...`
 args = parser.parse_args()
 if args.cmd in ['create_user']:  # or just == 'create_user'
     api.create_user(args...)
 elif args.cmd in ['retrieve_user']:
     api.retrieve_user(args...)

argparse 文档展示了如何通过调用来简化此操作:

 args.subcmdfunc(args)

查看子命令部分的最后两个示例:https://docs.python.org/3/library/argparse.html#sub-commands

无论哪种方式,想法都是从args命名空间中找出用户指定的子命令,然后调用正确的api方法。

请记住,parser.parse_args() 等同于 parser.parse_args(sys.argv[1:])。因此,无论您使用什么解析器,无论是主解析器还是子解析器之一,它都必须准备好处理用户可能提供的所有字符串。它是知道如何处理子解析器名称的主解析器。子解析器只需处理其名称后面的字符串。如果给出完整的argv[1:] 列表,它可能会出错。所以通常你不会为特定的子解析器调用parse_args

【讨论】:

  • 我在每个新的“解析器”之后调用了“parse_args”方法,但它仍然没有显示在终端上,只有“create_user”。
  • 那么我需要为每个子解析器调用 parse_args 方法还是在所有子解析器工作的最后调用它? @hpaulj
  • 在调用api 方法时添加了注释。
  • ++ 我查了args.subcmdfunc(args),但在 argparse 文档中没有找到任何内容。
  • 我想到了本节的最后两个示例:docs.python.org/3/library/argparse.html#sub-commands
猜你喜欢
  • 2013-02-01
  • 1970-01-01
  • 2023-03-23
  • 2015-12-11
  • 2013-12-04
  • 2018-03-27
  • 2012-06-19
  • 2021-09-04
  • 2019-03-16
相关资源
最近更新 更多