Jak sprawić, by program wiersza poleceń w języku Python automatycznie uzupełniał dowolne rzeczy, NIE interpretując


98

Wiem, jak skonfigurować autouzupełnianie obiektów Pythona w interpreterach Pythona (na unixie).

  • Google pokazuje wiele trafień, aby wyjaśnić, jak to zrobić.
  • Niestety, jest tak wiele odniesień do tego, że trudno jest znaleźć to, co muszę zrobić, co jest nieco inne.

Muszę wiedzieć, jak włączyć tabulator / automatyczne uzupełnianie dowolnych elementów w programie wiersza poleceń napisanym w języku Python.

Moim konkretnym przypadkiem użycia jest program w języku Python z wiersza poleceń, który musi wysyłać e-maile. Chcę mieć możliwość autouzupełniania adresów e-mail (mam adresy na dysku), gdy użytkownik wpisze ich część (i opcjonalnie naciśnie klawisz TAB).

Nie potrzebuję go do pracy na Windowsie lub Macu, tylko na Linuksie.


Ten blog powinien zrobić sztuczki z konfiguracją pliku .pythonrc.
Kris Roofe

Odpowiedzi:


65

Użyj readlinepowiązań Pythona . Na przykład,

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)

Oficjalne dokumenty modułów nie są dużo bardziej szczegółowe, zobacz dokumentację readline, aby uzyskać więcej informacji.


1
Zwróć uwagę, że jeśli napiszesz wiersz poleceń z modułem cmd, istnieją lepsze sposoby na zrobienie tego.
Florian Bösch

60

Postępuj zgodnie z dokumentacją cmd, a wszystko będzie dobrze

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

Dane wyjściowe dla tab -> tab -> send -> tab -> tab -> f -> tab

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

Czy istnieje sposób kontrolowania sposobu, w jaki readline kolumizuje swoje dane wyjściowe? Powiedzmy więc, że chciałbym, aby był on zbiorczy z dwiema spacjami między każdym elementem.
Fnord

Kiedy uruchamiam ten kod, zakładki są po prostu drukowane w wierszu poleceń. W rzeczywistości jest to prawdą niezależnie od tego, czy używam cmd, czy straight readline.
Hack Saw

38

Ponieważ w swoim pytaniu mówisz „NIE interpreter”, myślę, że nie chcesz odpowiedzi obejmujących python readline i tym podobne. ( edytuj : z perspektywy czasu, oczywiście tak nie jest. Hej. Myślę, że ta informacja i tak jest interesująca, więc zostawię ją tutaj ).

Myślę, że możesz być po tym .

Chodzi o dodanie uzupełniania na poziomie powłoki do dowolnych poleceń, rozszerzając własne uzupełnianie tabulatorami basha.

W skrócie, utworzysz plik zawierający funkcję powłoki, która wygeneruje możliwe uzupełnienia, zapiszesz ją /etc/bash_completion.d/i zarejestrujesz za pomocą polecenia complete. Oto fragment z połączonej strony:

_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

W tym przypadku, wpisując foo --[TAB]daje wartości w zmiennej opts, to znaczy --help, --verbosei --version. Do swoich celów zasadniczo będziesz chciał dostosować wartości, które są wstawiane opts.

Spójrz na przykład na połączonej stronie, wszystko jest dość proste.


11
Właściwie to przyszedłem tutaj z tego powodu
user1767754

Dzięki, właśnie tego szukałem!
Teekeks

30

Dziwię się, że nikt nie wspomniał o argcomplete, oto przykład z dokumentacji:

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

To stary post, może argcomplete wtedy nie istniał? Dziękuję za wspomnienie, myślę, że to jest dokładnie to, czego potrzebuje mój projekt!
FrustratedWithFormsDesigner

Bardzo ładne w połączeniu z argparse !
AstroFloyd

14

Oto w pełni działająca wersja kodu, który został bardzo dostarczony przez ephemient tutaj (dziękuję).

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
W systemie Mac OS, należy wymienić readline.parse_and_bind('tab:complete') zreadline.parse_and_bind ("bind ^I rl_complete")
Mani

To jest niesamowite. Pracował dla mnie. Dzięki za udostępnienie.
Ajay Ahuja

@Mani Utknąłem w tym przez długi czas. Dziękuję bardzo
AnaS Kayed

5

Możesz spróbować użyć Python Prompt Toolkit , biblioteki do tworzenia interaktywnych aplikacji wiersza poleceń w Pythonie.

Biblioteka ułatwia dodawanie interaktywnej funkcji autouzupełniania, umożliwiając użytkownikowi użycie Tabklawisza do wizualnego przechodzenia między dostępnymi opcjami. Biblioteka jest wieloplatformowa (Linux, OS X, FreeBSD, OpenBSD, Windows). Przykład:

pgcli - Python Prompt Toolkit

(Źródło obrazu: pcgli )


1

Opublikowane odpowiedzi działają poprawnie, ale mam otwartą bibliotekę autouzupełniania, którą napisałem w pracy. Używamy go od jakiegoś czasu w produkcji, jest szybki, stabilny i łatwy w użyciu. Ma nawet tryb demonstracyjny, dzięki czemu możesz szybko przetestować, co otrzymasz podczas wpisywania słów.

Aby go zainstalować, po prostu uruchom: pip install fast-autocomplete

Oto przykład:

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

Do kasy: https://github.com/wearefair/fast-autocomplete dla kodu źródłowego.

A oto wyjaśnienie, jak to działa: http://zepworks.com/posts/you-autocomplete-me/

Zajmuje się błędami w pisowni i opcjonalnie sortowaniem według wagi słowa. (powiedzmy, że burritojest ważniejsze niż book, wtedy podajesz burritowyższą „liczbę” i pojawi się ona jako pierwsza bookw wynikach.

Słowa to słownik i każde słowo może mieć kontekst. Na przykład „licznik”, jak wyświetlić słowo, inny kontekst wokół słowa itp. W tym przykładzie słowa nie miały żadnego kontekstu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.