Como fazer um python, programa de linha de comando preencher automaticamente coisas arbitrárias NÃO interpretador


92

Estou ciente de como configurar o preenchimento automático de objetos Python no interpretador Python (no Unix).

  • O Google mostra muitos acessos para explicações sobre como fazer isso.
  • Infelizmente, há tantas referências a isso que é difícil encontrar o que preciso fazer, o que é um pouco diferente.

Preciso saber como habilitar o preenchimento automático / tab de itens arbitrários em um programa de linha de comando escrito em python.

Meu caso de uso específico é um programa python de linha de comando que precisa enviar e-mails. Quero poder preencher automaticamente os endereços de e-mail (tenho os endereços no disco) quando o usuário digitar parte deles (e, opcionalmente, pressionar a tecla TAB).

Não preciso dele para funcionar em windows ou mac, apenas linux.


Este blog deve fazer os truques com a configuração do arquivo .pythonrc.
— Kris Roofe

Respostas:


63

Use as readlineligações do Python . Por exemplo,

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)

Os documentos oficiais do módulo não são muito mais detalhados, veja os documentos readline para mais informações.


1
Observe que se você escrever sua linha de comando com o módulo cmd, existem maneiras melhores de fazê-lo.
— Florian Bösch,

60

Siga a documentação do cmd e você ficará bem

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()

Saída para guia -> guia -> enviar -> guia -> guia -> f -> guia

(Cmd)
help  send
(Cmd) send
foo@bar.com            here@blubb.com         whatever@wherever.org
(Cmd) send foo@bar.com
(Cmd)

Existe alguma maneira de controlar como readline coluniza sua saída? Então, digamos que eu gostaria que fosse uma coluna com dois espaços entre cada item.
— Fnord

Quando executo este código, as guias são simplesmente impressas na linha de comando. Na verdade, isso é verdade, independentemente de eu usar cmd ou readline direto.
— Hack Saw

37

Já que você diz "NÃO é intérprete" em sua pergunta, acho que você não quer respostas envolvendo python readline e coisas do gênero. ( editar : em retrospectiva, obviamente não é o caso. Ei, hum. Acho que essas informações são interessantes de qualquer maneira, então vou deixá-las aqui ) .

Eu acho que você pode estar depois disso .

Trata-se de adicionar o preenchimento no nível do shell a comandos arbitrários, estendendo o preenchimento com tab do próprio bash.

Em poucas palavras, você criará um arquivo contendo uma função de shell que irá gerar possíveis completações, salvá-lo /etc/bash_completion.d/e registrá-lo com o comando complete. Aqui está um snippet da página vinculada:

_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

Nesse caso, a digitação foo --[TAB]fornecerá os valores da variável opts, ou seja --help, --verbosee --version. Para seus propósitos, você essencialmente desejará personalizar os valores que são colocados em opts.

Dê uma olhada no exemplo na página vinculada, é tudo muito simples.


10
Na verdade, eu vim aqui por causa disso
— user1767754

Obrigado, isso é exatamente o que eu estava procurando!
— Teekeks

27

Estou surpreso que ninguém tenha mencionado argcomplete, aqui está um exemplo dos documentos:

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'))

É um post antigo, talvez argcomplete não existisse naquela época? Obrigado por mencionar isso, porém, acho que é exatamente o que meu projeto precisa!
— FrustratedWithFormsDesigner,

Muito bom em combinação com argparse também!
— AstroFloyd

13

Aqui está uma versão funcional completa do código que foi fornecido pela ephemient aqui (obrigado).

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

10
# ~/.pythonrc
import rlcompleter, readline
readline.parse_and_bind('tab:complete')

# ~/.bashrc
export PYTHONSTARTUP=~/.pythonrc

Para mac os, substitua readline.parse_and_bind('tab:complete') porreadline.parse_and_bind ("bind ^I rl_complete")
— Mani

Isso é incrível. Funcionou para mim. Obrigado por compartilhar.
— Ajay Ahuja,

5

Você pode tentar usar o Python Prompt Toolkit , uma biblioteca para construir aplicativos de linha de comando interativos em Python.

A biblioteca facilita a adição de funcionalidade de preenchimento automático interativo, permitindo que o usuário use a Tabchave para alternar visualmente pelas opções disponíveis. A biblioteca é multiplataforma (Linux, OS X, FreeBSD, OpenBSD, Windows). Exemplo:

pgcli - Python Prompt Toolkit

(Fonte da imagem: pcgli )


1

As respostas postadas funcionam bem, mas abri o código-fonte de uma biblioteca de preenchimento automático que escrevi no trabalho. Nós o usamos há algum tempo na produção e é rápido, estável e fácil de usar. Ele ainda tem um modo de demonstração para que você possa testar rapidamente o que obteria ao digitar palavras.

Para instalá-lo, basta executar: pip install fast-autocomplete

Aqui está um exemplo:

>>> 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']]

Checkout: https://github.com/wearefair/fast-autocomplete para o código-fonte.

E aqui está uma explicação de como funciona: http://zepworks.com/posts/you-autocomplete-me/

Lida com erros de grafia e, opcionalmente, classificação pelo peso da palavra. (digamos que burritoseja mais importante do que book, então você dá burritouma "contagem" maior e ela aparecerá antes booknos resultados.

Palavras são um dicionário e cada palavra pode ter um contexto. Por exemplo, a "contagem", como exibir a palavra, algum outro contexto em torno da palavra, etc. Neste exemplo, as palavras não têm nenhum contexto.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.