Comment faire un Python, un programme de ligne de commande qui remplit automatiquement des choses arbitraires PAS un interpréteur

92

Je sais comment configurer l'auto-complétion des objets python dans l'interpréteur python (sous unix).

  • Google affiche de nombreux appels pour des explications sur la façon de procéder.
  • Malheureusement, il y a tellement de références à cela qu'il est difficile de trouver ce que j'ai besoin de faire, ce qui est légèrement différent.

J'ai besoin de savoir comment activer, tabulation / complétion automatique d'éléments arbitraires dans un programme de ligne de commande écrit en python.

Mon cas d'utilisation spécifique est un programme python en ligne de commande qui doit envoyer des e-mails. Je veux pouvoir saisir automatiquement les adresses e-mail (j'ai les adresses sur le disque) lorsque l'utilisateur en tape une partie (et appuie éventuellement sur la touche TAB).

Je n'en ai pas besoin pour fonctionner sur Windows ou Mac, juste Linux.

Paul D. Eden
la source
Ce blog devrait faire les astuces avec la configuration du fichier .pythonrc.
Kris Roofe

Réponses:

63

Utilisez les readlineliaisons de Python . Par exemple,

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)

Les documents officiels du module ne sont pas beaucoup plus détaillés, consultez les documents readline pour plus d'informations.

éphémère
la source
1
notez que si vous écrivez votre ligne de commande avec le module cmd, il existe de meilleures façons de le faire.
Florian Bösch
60

Suivez la documentation cmd et tout ira bien

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

Sortie pour onglet -> onglet -> envoyer -> onglet -> onglet -> f -> onglet

(Cmd)
help  send
(Cmd) send
foo@bar.com            here@blubb.com         whatever@wherever.org
(Cmd) send foo@bar.com
(Cmd)
Florian Bösch
la source
Existe-t-il un moyen de contrôler la manière dont readline colore sa sortie? Disons donc que je voudrais qu'il soit en colonne avec deux espaces entre chaque élément.
Fnord
Lorsque j'exécute ce code, les onglets sont simplement imprimés dans la ligne de commande. En fait, cela est vrai que j'utilise cmd ou straight readline.
Hack Saw
38

Puisque vous dites "PAS d'interprète" dans votre question, je suppose que vous ne voulez pas de réponses impliquant Python readline et autres. ( modifier : avec le recul, ce n'est évidemment pas le cas. Ho hum. Je pense que cette info est intéressante de toute façon, alors je vais la laisser ici. )

Je pense que vous pourriez être après ça .

Il s'agit d'ajouter la complétion au niveau du shell aux commandes arbitraires, étendant la complétion par tabulation de bash.

En un mot, vous allez créer un fichier contenant une fonction shell qui générera des complétions possibles, l'enregistrer /etc/bash_completion.d/et l'enregistrer avec la commande complete. Voici un extrait de la page liée:

_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

Dans ce cas, le typage foo --[TAB]vous donnera les valeurs de la variable opts, c'est --help-à- dire --verboseet --version. Pour vos besoins, vous souhaiterez essentiellement personnaliser les valeurs insérées opts.

Jetez un œil à l'exemple sur la page liée, tout est assez simple.

Owen
la source
10
En fait, je suis venu ici à cause de cela
user1767754
Merci, c'est exactement ce que je cherchais!
Teekeks
27

Je suis surpris que personne n'ait mentionné argcomplete, voici un exemple tiré de la documentation:

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
la source
C'est un vieux post, peut-être qu'argcomplete n'existait pas à l'époque? Merci de l'avoir mentionné, je pense que c'est exactement ce dont mon projet a besoin!
FrustratedWithFormsDesigner
Très bien en combinaison avec argparse aussi!
AstroFloyd
13

Voici une version complète du code qui a été très fournie par ephemient ici (merci).

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

# ~/.bashrc
export PYTHONSTARTUP=~/.pythonrc
user178047
la source
1
Pour mac OS, remplacez readline.parse_and_bind('tab:complete') parreadline.parse_and_bind ("bind ^I rl_complete")
Mani
C'est génial. A travaillé pour moi. Merci d'avoir partagé.
Ajay Ahuja
@Mani J'étais coincé là-dedans pendant longtemps. Merci beaucoup
AnaS Kayed
5

Vous pouvez essayer d'utiliser le Python Prompt Toolkit , une bibliothèque pour créer des applications de ligne de commande interactives en Python.

La bibliothèque facilite l'ajout d'une fonctionnalité de saisie semi-automatique interactive, permettant à l'utilisateur d'utiliser la Tabclé pour parcourir visuellement les choix disponibles. La bibliothèque est multiplateforme (Linux, OS X, FreeBSD, OpenBSD, Windows). Exemple:

pgcli - Boîte à outils d'invite Python

(Source de l'image: pcgli )

Flux
la source
1

Les réponses publiées fonctionnent bien, mais j'ai ouvert une bibliothèque à saisie semi-automatique que j'ai écrite au travail. Nous l'utilisons depuis un certain temps en production et il est rapide, stable et facile à utiliser. Il dispose même d'un mode démo pour que vous puissiez rapidement tester ce que vous obtiendriez en tapant des mots.

Pour l'installer, exécutez simplement: pip install fast-autocomplete

Voici un exemple:

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

Paiement: https://github.com/wearefair/fast-autocomplete pour le code source.

Et voici une explication de son fonctionnement: http://zepworks.com/posts/you-autocomplete-me/

Il traite des fautes d'orthographe et éventuellement du tri en fonction du poids du mot. (disons que burritoc'est plus important que book, alors vous donnez burritoun "compte" plus élevé et il apparaîtra en premier bookdans les résultats.

Les mots sont un dictionnaire et chaque mot peut avoir un contexte. Par exemple, le "compte", comment afficher le mot, un autre contexte autour du mot, etc. Dans cet exemple, les mots n'avaient aucun contexte.

Seperman
la source