0

我有这样的文件结构:

project/ main_prog.py tools/ script.py md_script/ __init__.py md_script.py

我在工具中搜索本地 python 模块。在本例中,它是 md_script。我想在我的代码中使用它作为位置参数,比如 install ,但是当我使用它时,我遇到了一个错误:

./jsh.py md_script
usage: jsh.py [-h] {install,call,list,log,restore} ... [md_script]
jsh.py: error: invalid choice: 'md_script' (choose from 'install', 'call', 'list', 'log', 'restore')

ubuntu14.10 上的 python3.4 这是我的代码:

parser = argparse.ArgumentParser(prog='jsh.py',
    description='Some help.', epilog='Example of usage: some help')
subparsers = parser.add_subparsers()
parser_install = subparsers.add_parser('install', help = 'Install new project.')
parser_install.add_argument('install', nargs='?', help = 'Name of project to be installed')
if os.path.isdir(full/path/to/tools/):
   name_arg = next(os.walk(full/path/to/tools))[1]
   tools_arg = parser.add_argument_group('Tools', 'Modules from tools')
   for element in name_arg:
      tools_arg.add_argument(element, nargs='?', help='md_script description')
args = parser.parse_args()
try:
  if not len(sys.argv) > 1:
     parser.print_help()
  elif 'install' in args:
     do_some_stuff
  elif element in args:
     do_some_md_script_stuff
  else:
     parser.print_help()
4

2 回答 2

2

usage行显示出了什么问题:

usage: jsh.py [-h] {install,call,list,log,restore} ... [md_script]

你需要使用类似的东西

jsh.py install md_script

您指定了子解析器,因此您必须给它一个子解析器名称。


usage它看来,您还创建了其他未在代码中显示的子解析器、 、 等calllist

您还可以在创建子解析器之后定义位置参数。这就是它的[md_script]来源。小心制作很多nargs='?'位置(包括子解析器的参数install)。这可能会使您的用户感到困惑。事实上,它似乎让你感到困惑。请记住,这subparser实际上是一个位置参数(需要 1 个字符串)。

我建议在创建一个如此复杂的解析器之前尝试使用更简单的解析器。


因此,从您的评论和示例中,我看到您的目标是让用户命名一个模块,以便您的脚本可以以某种方式调用它。因为使用这些名称填充子解析器是有意义的。

我想知道为什么您还创建一个具有相同名称的可选位置参数:

module_pars = subparsers.add_parser(element, help = 'Modules from tools')
module_pars.add_argument(element, nargs='?', help=element+' description')

那是因为您使用属性的存在作为调用此子解析器的证据吗?

elif element in args:
    do_some_md_script_stuff

argparse文档还有其他一些想法。

处理子命令的一种特别有效的方法是将 add_subparsers() 方法的使用与对 set_defaults() 的调用结合起来,以便每个子解析器都知道它应该执行哪个 Python 函数。

但是,如果需要检查被调用的子解析器的名称,add_subparsers() 调用的 dest 关键字参数将起作用:

这些避免了“?”的混乱。位置参数,让您可以使用子解析器参数获取真实信息。

subparsers = parser.add_subparsers(dest='module')
....
for element in name_arg:
    # module_pars = 'parser_'+element   # this does nothing
    module_pars = subparsers.add_parser(element, help = 'Modules from tools')
    module_pars.set_defaults(func = do_some_md_script_stuff)
    # or module_pars.set_default(element='I am here')
    module_pars.add_argument('real_argument')

现在您可以检查:

if args.module='md_script':
    do_some_md_script_stuff(args)

或者

if hasattr(args, 'func'):
    func(args)

使用替代方法set_defaults,您的原始测试应该仍然有效:

if element in args:
    do_some_md_script_stuff
于 2015-08-31T16:23:35.923 回答
0

我是这样做的。这正是我想要的。

if os.path.isdir(TOOLS_PATH):
   name_arg = next(os.walk(TOOLS_PATH))[1]
   for element in name_arg:
      module_pars = 'parser_'+element
      module_pars = subparsers.add_parser(element, help = 'Modules from tools')
      module_pars.add_argument(element, nargs='?', help=element+' description')

我没有测试它,因为我没有测试模块,而是./jsh.py md_script进入elif element in args: print('md_script')并打印字符串。所以看起来它有效。感谢所有回复。

编辑:我测试了它。在 add_argument 我必须改变 nargs='?' 用于 nargs='*' 捕获多个参数。为了从命令行捕获参数,我使用了这个:

elif args:
   for element in name_arg:
      if element in args:
         element_arg = sys.argv[2:]
         done_cmd,msg = opt_exec_module(element,*element_arg)
         my_logger(done_cmd,msg)

不是很优雅,但它有效。

于 2015-09-01T12:46:12.330 回答