Come creare un programma a riga di comando Python che completi automaticamente cose arbitrarie NON interprete


92

Sono a conoscenza di come impostare il completamento automatico degli oggetti Python nell'interprete Python (su Unix).

  • Google mostra molti risultati per spiegazioni su come farlo.
  • Sfortunatamente, ci sono così tanti riferimenti che è difficile trovare quello che devo fare, che è leggermente diverso.

Ho bisogno di sapere come abilitare, tab / completamento automatico di elementi arbitrari in un programma a riga di comando scritto in python.

Il mio caso d'uso specifico è un programma Python da riga di comando che deve inviare e-mail. Voglio essere in grado di completare automaticamente gli indirizzi e-mail (ho gli indirizzi su disco) quando l'utente ne digita una parte (e opzionalmente preme il tasto TAB).

Non ne ho bisogno per funzionare su Windows o Mac, solo su Linux.


Questo blog dovrebbe fare i trucchi con la configurazione del file .pythonrc.
Kris Roofe

Risposte:


63

Usa le readlineassociazioni di Python . Per esempio,

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)

I documenti ufficiali del modulo non sono molto più dettagliati, vedere i documenti readline per maggiori informazioni.


1
nota bene che se scrivi la tua riga di comando con il modulo cmd ci sono modi migliori per farlo.
Florian Bösch

60

Segui la documentazione di cmd e starai bene

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

Output per scheda -> scheda -> invia -> scheda -> scheda -> f -> scheda

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

C'è un modo per controllare come readline impagina il suo output? Quindi diciamo che vorrei che fosse in colonne con due spazi tra ogni elemento.
Fnord

Quando eseguo questo codice, le schede vengono semplicemente stampate nella riga di comando. In effetti questo è vero indipendentemente dal fatto che io usi cmd o straight readline.
Hack Saw

38

Dato che dici "NON interprete" nella tua domanda, immagino che tu non voglia risposte che coinvolgono readline python e simili. ( modifica : col senno di poi, ovviamente non è così. Ho hum. Penso che questa informazione sia comunque interessante, quindi la lascio qui. )

Penso che potresti essere dopo questo .

Si tratta di aggiungere il completamento a livello di shell a comandi arbitrari, estendendo il completamento con tabulazioni di bash.

In poche parole, creerai un file contenente una funzione di shell che genererà possibili completamenti, lo salverai /etc/bash_completion.d/e lo registrerai con il comando complete. Ecco uno snippet dalla pagina collegata:

_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

In questo caso, la tipizzazione foo --[TAB]vi darà i valori nella variabile opts, vale a dire --help, --verbosee --version. Per i tuoi scopi, essenzialmente vorrai personalizzare i valori in cui vengono inseriti opts.

Dai un'occhiata all'esempio nella pagina collegata, è tutto abbastanza semplice.


10
In realtà sono venuto qui per questo
user1767754

Grazie, questo è esattamente quello che stavo cercando!
Teekeks

27

Sono sorpreso che nessuno abbia menzionato argcomplete, ecco un esempio dai documenti:

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

È un vecchio post, forse allora argcomplete non esisteva? Grazie per averlo menzionato, penso che sia esattamente ciò di cui il mio progetto ha bisogno!
FrustratedWithFormsDesigner

Molto bello anche in combinazione con argparse !
AstroFloyd,

13

Ecco una versione funzionante del codice che è stata molto fornita da ephemient qui (grazie).

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

1
Per mac os, sostituire readline.parse_and_bind('tab:complete') conreadline.parse_and_bind ("bind ^I rl_complete")
Mani

Questo e spettacolare. Ha funzionato per me. Grazie per la condivisione.
Ajay Ahuja

@ Man sono rimasto bloccato in questo per molto tempo. Grazie mille
AnaS Kayed

5

Puoi provare a utilizzare Python Prompt Toolkit , una libreria per la creazione di applicazioni a riga di comando interattive in Python.

La libreria semplifica l'aggiunta di funzionalità di completamento automatico interattivo, consentendo all'utente di utilizzare la Tabchiave per scorrere visivamente le scelte disponibili. La libreria è multipiattaforma (Linux, OS X, FreeBSD, OpenBSD, Windows). Esempio:

pgcli - Toolkit dei prompt di Python

(Fonte immagine: pcgli )


1

Le risposte pubblicate funzionano bene ma ho reso open source una libreria di completamento automatico che ho scritto al lavoro. Lo utilizziamo da tempo in produzione ed è veloce, stabile e facile da usare. Ha anche una modalità demo in modo da poter testare rapidamente cosa otterresti mentre digiti le parole.

Per installarlo, esegui semplicemente: pip install fast-autocomplete

Ecco un esempio:

>>> 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 per il codice sorgente.

Ed ecco una spiegazione di come funziona: http://zepworks.com/posts/you-autocomplete-me/

Si occupa di errori di ortografia e, facoltativamente, di ordinamento in base al peso della parola. (diciamo che burritoè più importante di book, quindi dai burritoun "conteggio" più alto e verrà visualizzato prima booknei risultati.

Words è un dizionario e ogni parola può avere un contesto. Ad esempio il "conteggio", come visualizzare la parola, qualche altro contesto attorno alla parola ecc. In questo esempio le parole non avevano alcun contesto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.