【问题标题】:Custom tab completion in python argparsepython argparse中的自定义选项卡完成
【发布时间】:2013-01-13 21:11:24
【问题描述】:

如何在 Python 脚本中获得与 argparse 合作的 shell 选项卡完成?

#!/usr/bin/env python
import argparse

def main(**args):
    pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('positional', choices=['spam', 'eggs'])
    parser.add_argument('--optional', choices=['foo1', 'foo2', 'bar'])
    args = parser.parse_args()
    main(**vars(args))

在 .py 文件上设置可执行标志后,预期结果应类似于:

$ ./example.py sp<tab>             
   ->  completes to "./example.py spam"
$ ./example.py --op<tab> 
   ->  completes to "./example.py --optional"
$ ./example.py --optional b<tab>
   ->  completes to "./example.py --optional bar"
$ ./example.py --optional f<tab>   
   ->  completes to "./example.py --optional foo"
       and, additionally, prints  "foo1  foo2"  choices on stdout on a new line

【问题讨论】:

标签: python bash command-line-interface argparse tab-completion


【解决方案1】:

要使自动完成功能起作用,您需要一个 bash 函数来生成可能的选项,然后您需要运行 complete -F &lt;function_name&gt; &lt;program_name&gt;

最好的方法是让程序根据自己的解析算法生成完成函数,以避免重复。但是,快速浏览一下 argparse,我找不到访问其内部结构的方法,但我建议您寻找它。

这是一个 bash 函数,可以用于上述程序:

function _example_auto() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    local prev=${COMP_WORDS[COMP_CWORD-1]}

    case "$prev" in
    --optional ) 
        COMPREPLY=( $(compgen -W "foo1 foo2 bar" -- $cur) )
        return 0
        ;;
    *)
        COMPREPLY=( $(compgen -W "--optional spam eggs" -- $cur) )
        return 0
        ;;
    esac
}

【讨论】:

  • 这个程序只是一个例子。可以列出特定程序的所有选项,但不能列出库。类似optcomplete 等价于argparse 的东西可以完成这项工作,但也欢迎其他(包括部分)解决方案。
【解决方案2】:

看看 Andrey Kislyuk 的 argcomplete

安装它:

pip install argcomplete

在调用parser.parse_args()之前导入模块并在源代码中添加一行:

#!/usr/bin/env python

import argparse as ap
import argcomplete

def main(**args):
  pass

if __name__ == '__main__':
  parser = ap.ArgumentParser()
  parser.add_argument('positional', choices=['spam', 'eggs'])
  parser.add_argument('--optional', choices=['foo1', 'foo2', 'bar'])
  argcomplete.autocomplete(parser)
  args = parser.parse_args()
  main(**vars(args))

为了确保 bash 知道这个脚本,你使用

eval "$(register-python-argcomplete your_script)"

您应该将该行放在您的 ~/.bashrc 中或按照 argcomplete 的文档并激活“全局”完成。

之后,您按要求完成工作。

其工作方式是 eval 行创建一个函数 _python_argcomlete,该函数使用 complete 注册。 (运行register-python-argcomplete your_script 来看看什么被评估到了bash)。自动完成功能会查找 bash 完成机制设置的环境变量,看它是否需要行动。如果它起作用,它就会退出程序。如果它不动作,这是对程序的正常调用,该函数什么也不做,程序的正常流程继续。

【讨论】:

  • 如果启用“全局补全”,则需要将注释 # PYTHON_ARGCOMPLETE_OK 放在 Python 文件的开头(例如,作为第二行,紧跟在 #!/usr/bin/env python 之后),或者自动完成将不起作用。我建议编辑答案中的代码,添加上述注释行。
  • @AlbertoPettarin 我明确地没有提到全局完成,因为它需要额外的设置并且会在选项卡完成时产生一般性能损失(因为打开多个文件搜索潜在的PYTHON_ARGCOMPLETE_OK。全局选项卡文章中的链接(现在在您的评论中)中提到了完成和要求,这已经足够了。
  • 还有activate-global-python-argcomplete 可用(我认为这可能是新的,因为我不记得上次我看时它在那里)。
  • 我有一个大项目,所以如果这将帮助我自动生成 bash 完成脚本,或者无论如何我不必手动维护脚本以完成命令?
  • @shiminsh 这就是它的意图,但它是否适合你在某种程度上取决于它。 argcomplete 启动应用程序以动态生成完成信息,这可能需要一些时间,具体取决于应用程序的结构。对我来说,这导致的延迟已经够烦人了,以至于我的大多数项目都没有使用 argcomplete。但是,如果您已经使用 argparse 添加 argcomplete 来尝试它,那么工作量真的很小。
猜你喜欢
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多