Создание приложения командной строки оболочки с помощью Python и нажмите
Я использую click (http://click.pocoo.org/3/) для создания приложения командной строки, но я не знаю, как создать оболочку для этого приложения.
Допустим, я пишу программу под названием тест и у меня есть команды, называемые subtest1 и subtest2
я смог заставить его работать с терминала, как:
$ test subtest1
$ test subtest2
но то, о чем я думал, - это оболочка, поэтому я мог бы сделать:
$ test
>> subtest1
>> subtest2
Is это возможно с кнопкой?
4 ответов
это не невозможно с помощью click, но для этого также нет встроенной поддержки. Первое, что вам нужно сделать, это сделать ваш групповой обратный вызов вызываемым без подкоманды, передав invoke_without_command=True
в декоратор группы (как описано здесь). Тогда ваш групповой обратный вызов должен был бы реализовать REPL. У Python есть cmd framework для этого в стандартной библиотеке. Создание доступных там подкоманд click включает переопределение cmd.Cmd.default
, как в фрагмент кода ниже. Получение всех деталей правильно, как help
, должно быть выполнимо в несколько строк.
import click
import cmd
class REPL(cmd.Cmd):
def __init__(self, ctx):
cmd.Cmd.__init__(self)
self.ctx = ctx
def default(self, line):
subcommand = cli.commands.get(line)
if subcommand:
self.ctx.invoke(subcommand)
else:
return cmd.Cmd.default(self, line)
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
if ctx.invoked_subcommand is None:
repl = REPL(ctx)
repl.cmdloop()
@cli.command()
def a():
"""The `a` command prints an 'a'."""
print "a"
@cli.command()
def b():
"""The `b` command prints a 'b'."""
print "b"
if __name__ == "__main__":
cli()
Я пытался сделать что-то похожее на OP, но с дополнительными опциями / вложенными под-под-командами. Первый ответ с использованием встроенного модуля cmd не работал в моем случае; возможно, с некоторыми более возиться.. Но я только что наткнулся на click-shell. У меня не было возможности протестировать его широко, но до сих пор он работает точно так, как ожидалось.
Я знаю, что это супер старый,но я работал над решением fpbhb для поддержки опций. Я уверен, что это может использовать дополнительную работу, но вот основной пример того, как это можно сделать:
import click
import cmd
import sys
from click import BaseCommand, UsageError
class REPL(cmd.Cmd):
def __init__(self, ctx):
cmd.Cmd.__init__(self)
self.ctx = ctx
def default(self, line):
subcommand = line.split()[0]
args = line.split()[1:]
subcommand = cli.commands.get(subcommand)
if subcommand:
try:
subcommand.parse_args(self.ctx, args)
self.ctx.forward(subcommand)
except UsageError as e:
print(e.format_message())
else:
return cmd.Cmd.default(self, line)
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
if ctx.invoked_subcommand is None:
repl = REPL(ctx)
repl.cmdloop()
@cli.command()
@click.option('--foo', required=True)
def a(foo):
print("a")
print(foo)
return 'banana'
@cli.command()
@click.option('--foo', required=True)
def b(foo):
print("b")
print(foo)
if __name__ == "__main__":
cli()
теперь есть библиотека под названием click_repl что делает большую часть работы для вас. Думал, что поделюсь своими усилиями, чтобы это сработало.
одна трудность заключается в том, что вы должны сделать конкретную команду repl
command, но мы можем перепрофилировать подход @fpbhb, чтобы разрешить вызов этой команды по умолчанию, если другой не предоставляется.
это полностью рабочий пример, который поддерживает все параметры щелчка, с историей команд, а также возможность вызовите команды непосредственно без ввода REPL:
import click
import click_repl
import os
from prompt_toolkit.history import FileHistory
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
"""Pleasantries CLI"""
if ctx.invoked_subcommand is None:
ctx.invoke(repl)
@cli.command()
@click.option('--name', default='world')
def hello(name):
"""Say hello"""
click.echo('Hello, {}!'.format(name))
@cli.command()
@click.option('--name', default='moon')
def goodnight(name):
"""Say goodnight"""
click.echo('Goodnight, {}.'.format(name))
@cli.command()
def repl():
"""Start an interactive session"""
prompt_kwargs = {
'history': FileHistory(os.path.expanduser('~/.repl_history'))
}
click_repl.repl(click.get_current_context(), prompt_kwargs=prompt_kwargs)
if __name__ == '__main__':
cli(obj={})
вот как это выглядит, чтобы использовать REPL:
$ python pleasantries.py
> hello
Hello, world!
> goodnight --name fpbhb
Goodnight, fpbhb.
и использовать подкоманды командной строки напрямую:
$ python pleasntries.py goodnight
Goodnight, moon.