Как я могу создать непрерывный / бесконечный CLI с Click? - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь использовать Нажмите , чтобы создать CLI для моего приложения Python 3. По сути, мне нужно, чтобы приложение работало непрерывно, ожидая пользовательских команд и выполняя их, и выходя из системы, если введена определенная команда (скажем, «q»). Не удалось найти пример в документах Click или в других местах.

Пример интерактивной оболочки будет выглядеть так:

myapp.py
> PLEASE ENTER LOGIN: 
mylogin
> PLEASE ENTER PASSWORD:
mypwd
> ENTER COMMAND: 
a
> Wrong command! 
> USAGE: COMMAND [q|s|t|w|f] OPTIONS ARGUMENTS
> ENTER COMMAND:
f
> (output of "f" command...)
> ENTER COMMAND:
q
> QUITTING APP...

Я пробовал вот так:

import click

quitapp = False # global flag

@click.group()
def cli():
    pass

@cli.command(name='c')
@click.argument('username')
def command1(uname):
    pass # do smth

# other commands...

@cli.command(name='q')
def quitapp():
    global quitapp
    quitapp = True

def main():    
    while not quitapp:
        cli()

if __name__ == '__main__':
    main()

Но консоль просто запускает приложение один и тот же.

Ответы [ 2 ]

1 голос
/ 10 июня 2019

Я на самом деле переключился на fire и сумел создать непрерывную функцию, похожую на оболочку, например:

COMMAND_PROMPT = '\nCOMMAND? [w to quit] >'
CAPTCHA_PROMPT = '\tEnter captcha text (see your browser) >'
BYE_MSG = 'QUITTING APP...'
WRONG_CMD_MSG = 'Wrong command! Type "h" for help.'
EMPTY_CMD_MSG = 'Empty command!'

class MyClass:
    def __init__(self):
        # dict associating one-letter commands to methods of this class
        self.commands = {'r': self.reset, 'q': self.query, 'l': self.limits_next, 'L': self.limits_all, 
                'y': self.yandex_logo, 'v': self.view_params, 'h': self.showhelp, 'c': self.sample_captcha, 'w': None}
        # help (usage) strings
        self.usage = '\nUSAGE:\t[{}] [value1] [value2] [--param3=value3] [--param4=value4]'.format('|'.join(sorted(self.commands.keys())))
        self.usage2 = '\t' + '\n\t'.join(['{}:{}'.format(fn, self.commands[fn].__doc__) for fn in self.commands if fn != 'w'])

    def run(self):
        """
        Provides a continuously running commandline shell.        
        The one-letter commands used are listed in the commands dict.
        """
        entered = ''
        while True:
            try:
                print(COMMAND_PROMPT, end='\t')
                entered = str(input())
                if not entered:
                    print(EMPTY_CMD_MSG)
                    continue
                e = entered[0]
                if e in self.commands:
                    if self.commands[e] is None: 
                        print(BYE_MSG)
                        break
                    cmds = entered.split(' ')
                    # invoke Fire to process command & args
                    fire.Fire(self.commands[e], ' '.join(cmds[1:]) if len(cmds) > 1 else '-')
                else:
                    print(WRONG_CMD_MSG)
                    self.showhelp()
                    continue     
            except KeyboardInterrupt:
                print(BYE_MSG)
                break

            except Exception:
                continue

    # OTHER METHODS...

if __name__ == '__main__':
    fire.Fire(MyClass)

Тем не менее, я был бы признателен, если бы кто-то показал, как это сделать с помощью щелчка (который мне кажется более функциональным, чем огонь).

0 голосов
/ 13 июня 2019

Я наконец-то обнаружил другие библиотеки для интерактивных оболочек в Python: cmd2 и prompt , которые намного более продвинуты для оболочек, подобных REPL, из коробки ...

...