如何使 python 命令行程序自动完成任意事物而不是解释器
Posted
技术标签:
【中文标题】如何使 python 命令行程序自动完成任意事物而不是解释器【英文标题】:How to make a python, command-line program autocomplete arbitrary things NOT interpreter 【发布时间】:2010-09-16 07:14:35 【问题描述】:我知道如何在 python 解释器(在 unix 上)中设置 python 对象的自动完成。
Google 显示了许多关于如何执行此操作的说明。 很遗憾,参考资料太多,很难找到我需要做的事情,这略有不同。我需要知道如何在用 python 编写的命令行程序中启用、制表符/自动完成任意项。
我的具体用例是一个需要发送电子邮件的命令行 python 程序。我希望能够在用户键入部分电子邮件地址(并且可以选择按 TAB 键)时自动完成电子邮件地址(我有磁盘上的地址)。
我不需要它在 windows 或 mac 上工作,只需要在 linux 上工作。
【问题讨论】:
这个blog 应该可以通过配置 .pythonrc 文件来解决问题。 【参考方案1】:这很好用。
#!/usr/bin/python3
import readline
readline.parse_and_bind("tab: complete")
def complete(text,state):
volcab = ['dog','cat','rabbit','bird','slug','snail']
results = [x for x in volcab if x.startswith(text)] + [None]
return results[state]
readline.set_completer(complete)
line = input('prompt> ')
【讨论】:
【参考方案2】:发布的答案工作正常,但我已经开源了一个我在工作中编写的自动完成库。我们已经在生产中使用了一段时间,它快速、稳定且易于使用。它甚至有一个演示模式,因此您可以在输入单词时快速测试您会得到什么。
要安装它,只需运行:pip install fast-autocomplete
这是一个例子:
>>> from fast_autocomplete import AutoComplete
>>> words = 'book': , 'burrito': , 'pizza': , 'pasta':
>>> autocomplete = AutoComplete(words=words)
>>> autocomplete.search(word='b', max_cost=3, size=3)
[['book'], ['burrito']]
>>> autocomplete.search(word='bu', max_cost=3, size=3)
[['burrito']]
>>> autocomplete.search(word='barrito', max_cost=3, size=3) # mis-spelling
[['burrito']]
结帐:https://github.com/seperman/fast-autocomplete 获取源代码。
下面是对其工作原理的解释:http://zepworks.com/posts/you-autocomplete-me/
它处理拼写错误并可选择按单词的权重排序。 (假设burrito
比book
更重要,那么你给burrito
一个更高的“计数”,它会在结果中首先出现在book
之前。
Words 是一本字典,每个单词都可以有一个上下文。例如“计数”、如何显示单词、单词周围的一些其他上下文等。在此示例中,单词没有任何上下文。
【讨论】:
它是否适用于 Windows 和 Linux shell? @Samuel 我听说有人在 Windows 上使用它。唯一在 Windows 上不起作用的是交互模式,它仅用于演示目的。【参考方案3】:您可以尝试使用Python Prompt Toolkit,这是一个用于在 Python 中构建交互式命令行应用程序的库。
该库可以轻松添加交互式自动完成功能,允许用户使用 Tab 键以可视方式循环浏览可用选项。该库是跨平台的(Linux、OS X、FreeBSD、OpenBSD、Windows)。示例:
(图片来源:pcgli)
【讨论】:
【参考方案4】:使用 Python 的 readline
绑定。例如,
import readline
def completer(text, state):
options = [i for i in commands if i.startswith(text)]
if state < len(options):
return options[state]
else:
return None
readline.parse_and_bind("tab: complete")
readline.set_completer(completer)
官方module docs 没有更详细的信息,请参阅readline docs 了解更多信息。
【讨论】:
请注意,如果您使用 cmd 模块编写命令行,那么有更好的方法可以做到这一点。 请注意,readline 在 Windows 上不起作用。 pyreadline 似乎是一个替代品,但它不适用于 linux。 您可以在 python 文件的开头放置一个条件来检查操作系统并导入readline
或pyreadline
。【参考方案5】:
我很惊讶没有人提到 argcomplete,这是文档中的一个示例:
from argcomplete.completers import ChoicesCompleter
parser.add_argument("--protocol", choices=('http', 'https', 'ssh', 'rsync', 'wss'))
parser.add_argument("--proto").completer=ChoicesCompleter(('http', 'https', 'ssh', 'rsync', 'wss'))
【讨论】:
这是一个旧帖子,也许 argcomplete 那时不存在?感谢您提及它,我认为这正是我的项目所需要的! 与argparse 结合也非常好!【参考方案6】:# ~/.pythonrc
import rlcompleter, readline
readline.parse_and_bind('tab:complete')
# ~/.bashrc
export PYTHONSTARTUP=~/.pythonrc
【讨论】:
对于mac os,将readline.parse_and_bind('tab:complete')
替换为readline.parse_and_bind ("bind ^I rl_complete")
这太棒了。为我工作。感谢分享。
@Mani 我被困了很长时间。非常感谢【参考方案7】:
由于您在问题中说“不是解释器”,我想您不想要涉及 python readline 等的答案。 (edit:事后看来,显然不是这样的。呵呵。反正我觉得这个信息很有趣,所以我把它留在这里。)
我想你可能会关注this。
它是关于向任意命令添加 shell 级补全,扩展 bash 自己的制表符补全。
简而言之,您将创建一个包含 shell 函数的文件,该函数将生成可能的补全,将其保存到 /etc/bash_completion.d/
并使用命令 complete
注册它。这是来自链接页面的 sn-p:
_foo()
local cur prev opts
COMPREPLY=()
cur="$COMP_WORDS[COMP_CWORD]"
prev="$COMP_WORDS[COMP_CWORD-1]"
opts="--help --verbose --version"
if [[ $cur == -* ]] ; then
COMPREPLY=( $(compgen -W "$opts" -- $cur) )
return 0
fi
complete -F _foo foo
在这种情况下,键入 foo --[TAB]
将为您提供变量 opts
中的值,即 --help
、--verbose
和 --version
。出于您的目的,您基本上需要自定义放入 opts
的值。
请查看链接页面上的示例,这一切都非常简单。
【讨论】:
其实我就是因为这个来这里 谢谢,这正是我想要的!【参考方案8】:这是由 ehemient here 提供的完整代码版本(谢谢)。
import readline
addrs = ['angela@domain.com', 'michael@domain.com', 'david@test.com']
def completer(text, state):
options = [x for x in addrs if x.startswith(text)]
try:
return options[state]
except IndexError:
return None
readline.set_completer(completer)
readline.parse_and_bind("tab: complete")
while 1:
a = raw_input("> ")
print "You entered", a
【讨论】:
请注意,readline 在 Windows 上不起作用,至少在 Python 2.7.18 中不起作用。 pyreadline 似乎是一个主要的替代品,除了你必须用 readline.readline() 替换 raw_input(),【参考方案9】:关注cmd documentation,你会没事的
import cmd
addresses = [
'here@blubb.com',
'foo@bar.com',
'whatever@wherever.org',
]
class MyCmd(cmd.Cmd):
def do_send(self, line):
pass
def complete_send(self, text, line, start_index, end_index):
if text:
return [
address for address in addresses
if address.startswith(text)
]
else:
return addresses
if __name__ == '__main__':
my_cmd = MyCmd()
my_cmd.cmdloop()
选项卡的输出 -> 选项卡 -> 发送 -> 选项卡 -> 选项卡 -> f -> 选项卡
(Cmd)
help send
(Cmd) send
foo@bar.com here@blubb.com whatever@wherever.org
(Cmd) send foo@bar.com
(Cmd)
【讨论】:
有什么方法可以控制 readline 如何对它的输出进行分列?所以可以说我希望它在每个项目之间用两个空格进行列化。 当我运行此代码时,选项卡会简单地打印到命令行中。事实上,无论我使用 cmd 还是直接 readline,这都是正确的。 我在 cmd 文档中看到很多 readline 引用。这在 Windows shell 中有效吗? @Hack Saw,我在 MacOS 上遇到了这个问题:捆绑的readline
与 Linux 上的不一样,所以我切换到 Linux(一个 Raspberry Pi),它立即工作。有一个叫做gnureadline
的东西可能值得一看。以上是关于如何使 python 命令行程序自动完成任意事物而不是解释器的主要内容,如果未能解决你的问题,请参考以下文章
如何使 Python PyQT 程序无法在 Windows 中打开命令行