Wie man ein Python-Befehlszeilenprogramm dazu bringt, beliebige Dinge automatisch zu vervollständigen, NICHT zu interpretieren

92

Mir ist bekannt, wie die automatische Vervollständigung von Python-Objekten im Python-Interpreter (unter Unix) eingerichtet wird.

  • Google zeigt viele Treffer für Erklärungen dazu.
  • Leider gibt es so viele Hinweise darauf, dass es schwierig ist zu finden, was ich tun muss, was etwas anders ist.

Ich muss wissen, wie man beliebige Elemente in einem in Python geschriebenen Befehlszeilenprogramm aktiviert, tab / automatisch vervollständigt.

Mein spezieller Anwendungsfall ist ein Befehlszeilen-Python-Programm, das E-Mails senden muss. Ich möchte in der Lage sein, E-Mail-Adressen automatisch zu vervollständigen (ich habe die Adressen auf der Festplatte), wenn der Benutzer einen Teil davon eingibt (und optional die TAB-Taste drückt).

Ich brauche es nicht, um unter Windows oder Mac zu arbeiten, nur Linux.

Paul D. Eden
quelle
Dieser Blog sollte die Tricks mit der Konfiguration der .pythonrc-Datei ausführen.
Kris Roofe

Antworten:

63

Verwenden Sie Pythons readlineBindungen. Beispielsweise,

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)

Die offiziellen Moduldokumente sind nicht viel detaillierter. Weitere Informationen finden Sie in den Readline-Dokumenten .

kurzlebig
quelle
1
Beachten Sie, dass es bessere Möglichkeiten gibt, wenn Sie Ihre Befehlszeile mit dem cmd-Modul schreiben.
Florian Bösch
60

Befolgen Sie die cmd-Dokumentation und alles wird gut

import cmd

addresses = [
    '[email protected]',
    '[email protected]',
    '[email protected]',
]

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

Ausgabe für Registerkarte -> Registerkarte -> Senden -> Registerkarte -> Registerkarte -> f -> Registerkarte

(Cmd)
help  send
(Cmd) send
foo@bar.com            here@blubb.com         whatever@wherever.org
(Cmd) send foo@bar.com
(Cmd)
Florian Bösch
quelle
Gibt es eine Möglichkeit zu steuern, wie readline die Ausgabe kolumniert? Nehmen wir also an, ich möchte, dass es zwischen jedem Element zwei Leerzeichen enthält.
Fnord
Wenn ich diesen Code ausführe, werden Registerkarten einfach in die Befehlszeile gedruckt. Tatsächlich gilt dies unabhängig davon, ob ich cmd oder gerade Readline verwende.
Hack Saw
37

Da Sie in Ihrer Frage "NICHT Dolmetscher" sagen, möchten Sie wahrscheinlich keine Antworten mit Python-Readline und dergleichen. ( edit : im nachhinein ist das offensichtlich nicht der Fall. Ho hum. Ich denke, diese Info ist sowieso interessant, also lasse ich sie hier. )

Ich glaube , Sie könnten nach sein diese .

Es geht darum, beliebigen Befehlen die Vervollständigung auf Shell-Ebene hinzuzufügen und die eigene Vervollständigung der Registerkarten von bash zu erweitern.

Kurz gesagt, Sie erstellen eine Datei mit einer Shell-Funktion, die mögliche Vervollständigungen generiert, und speichern sie in /etc/bash_completion.d/ und mit dem Befehl registrieren complete. Hier ist ein Ausschnitt von der verlinkten Seite:

_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 diesem Fall erhalten Sie durch die Eingabe foo --[TAB]die Werte in der Variablenopts , dh --help, --verboseund --version. Für Ihre Zwecke möchten Sie im Wesentlichen die Werte anpassen, die eingegeben werden opts.

Schauen Sie sich das Beispiel auf der verlinkten Seite an, es ist alles ziemlich einfach.

Owen
quelle
10
Eigentlich
bin
Danke, genau das habe ich gesucht!
Teekeks
27

Ich bin überrascht, dass niemand argcomplete erwähnt hat. Hier ist ein Beispiel aus den Dokumenten:

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'))
qed
quelle
Es ist ein alter Beitrag, vielleicht gab es damals noch kein Argcomplete? Vielen Dank, dass Sie es erwähnt haben. Ich denke, es ist genau das, was mein Projekt braucht!
FrustratedWithFormsDesigner
Sehr schön in Kombination mit Argparse !
AstroFloyd
13

Hier ist eine voll funktionsfähige Version des Codes, der von Ephemient hier sehr bereitgestellt wurde (danke).

import readline

addrs = ['[email protected]', '[email protected]', '[email protected]']

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
Paul D. Eden
quelle
10
# ~/.pythonrc
import rlcompleter, readline
readline.parse_and_bind('tab:complete')

# ~/.bashrc
export PYTHONSTARTUP=~/.pythonrc
user178047
quelle
Für Mac OS ersetzen Sie readline.parse_and_bind('tab:complete') durchreadline.parse_and_bind ("bind ^I rl_complete")
Mani
Das ist fantastisch. Hat für mich gearbeitet. Danke für das Teilen.
Ajay Ahuja
5

Sie können versuchen, die Python Prompt Toolkit zu verwenden , eine Bibliothek zum Erstellen interaktiver Befehlszeilenanwendungen in Python.

Die Bibliothek erleichtert das Hinzufügen interaktiver Funktionen zur automatischen Vervollständigung, sodass der Benutzer den TabSchlüssel verwenden kann, um die verfügbaren Optionen visuell zu durchlaufen. Die Bibliothek ist plattformübergreifend (Linux, OS X, FreeBSD, OpenBSD, Windows). Beispiel:

pgcli - Python Prompt Toolkit

(Bildquelle: pcgli )

Fluss
quelle
1

Die veröffentlichten Antworten funktionieren einwandfrei, aber ich habe eine Bibliothek mit automatischer Vervollständigung, die ich bei der Arbeit geschrieben habe, als Open-Source-Lösung bereitgestellt. Wir verwenden es seit einiger Zeit in der Produktion und es ist schnell, stabil und einfach zu bedienen. Es gibt sogar einen Demo-Modus, mit dem Sie schnell testen können, was Sie beim Eingeben von Wörtern erhalten würden.

Um es zu installieren, führen Sie einfach Folgendes aus: pip install fast-autocomplete

Hier ist ein Beispiel:

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

Kasse: https://github.com/wearefair/fast-autocomplete für den Quellcode.

Und hier ist eine Erklärung, wie es funktioniert: http://zepworks.com/posts/you-autocomplete-me/

Es befasst sich mit Rechtschreibfehlern und optional dem Sortieren nach dem Gewicht des Wortes. (Nehmen wir an, es burritoist wichtiger als book, dann geben Sie burritoeine höhere "Anzahl" an und es wird zuerst bookin den Ergebnissen angezeigt.

Wörter sind ein Wörterbuch und jedes Wort kann einen Kontext haben. Zum Beispiel die "Anzahl", wie das Wort angezeigt wird, ein anderer Kontext um das Wort herum usw. In diesem Beispiel hatten Wörter keinen Kontext.

Seperman
quelle