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.


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 .


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 = [
    '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()

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)

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.


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

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 = ['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

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 )


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.