Python с использованием argparse с cmd

Есть ли способ использовать argparse модуль подключен как интерпретатор для каждой подсказки в интерфейсе, наследующемся от cmd?

Я хотел бы, чтобы мой интерфейс cmd интерпретировал типичный line Параметр таким же образом можно интерпретировать параметры и аргументы, переданные во время выполнения в оболочке bash, используя необязательные аргументы с - а также позиционные аргументы.

2 ответа

Прямой путь был бы создать argparse парсер и парсинг line.split() в пределах вашей функции, expectИНГ SystemExit если указаны неверные аргументы (parse_args() звонки sys.exit() когда он находит недействительные аргументы).

class TestInterface(cmd.Cmd):

    __test1_parser = argparse.ArgumentParser(prog="test1")
    __test1_parser.add_argument('--bar', help="bar help")

    def help_test1(self): self.__test1_parser.print_help()

    def do_test1(self, line):
        try:
            parsed = self.__test1_parser.parse_args(line.split())
        except SystemExit:
            return
        print("Test1...")
        print(parsed)

Если переданы неверные аргументы, parse_args() выведет ошибки, и программа вернется к интерфейсу без выхода.

(Cmd) test1 --unk
usage: test1 [-h] [--bar BAR]
test1: error: unrecognized arguments: --unk
(Cmd)

Все остальное должно работать так же, как обычный argparse вариант использования, также поддерживая все cmdфункциональность (справочные сообщения, список функций и т. д.)

Источник: https://groups.google.com/forum/


Другой способ, который упрощает настройку выше, использует декоратор ниже:

class ArgparseCmdWrapper:
    def __init__(self, parser):
        """Init decorator with an argparse parser to be used in parsing cmd-line options"""
        self.parser = parser
        self.help_msg = ""

    def __call__(self, f):
        """Decorate 'f' to parse 'line' and pass options to decorated function"""
        if not self.parser:  # If no parser was passed to the decorator, get it from 'f'
            self.parser = f(None, None, None, True)

        def wrapped_f(*args):
            line = args[1].split()
            try:
                parsed = self.parser.parse_args(line)
            except SystemExit:
                return
            f(*args, parsed=parsed)

        wrapped_f.__doc__ = self.__get_help(self.parser)
        return wrapped_f

    @staticmethod
    def __get_help(parser):
        """Get and return help message from 'parser.print_help()'"""
        f = tempfile.SpooledTemporaryFile(max_size=2048)
        parser.print_help(file=f)
        f.seek(0)
        return f.read().rstrip()

Это упрощает определение дополнительных команд, когда они требуют дополнительных parsed параметр, который содержит результат успешного parse_args(), Если есть недопустимые аргументы, функция никогда не вводится, все обрабатывается декоратором.

__test2_parser = argparse.ArgumentParser(prog="test2")
__test2_parser.add_argument('--foo', help="foo help")

@WrapperCmdLineArgParser(parser=__test2_parser)
def do_test2(self, line, parsed):
    print("Test2...")
    print(parsed)

Все работает как оригинальный пример, в том числе argparse сгенерированные справочные сообщения - без необходимости определять help_command() функция.

Источник: https://codereview.stackexchange.com/questions/134333/using-argparse-module-within-cmd-interface

Ну, один из способов сделать это - переопределить cmd "s default метод и использовать его для анализа строки с argparse, потому что все команды без do_ метод в вашем подклассе cmd.Cmd провалится, чтобы использовать default метод. Обратите внимание на дополнительные _ до do_test чтобы избежать его использования в качестве cmd команда.

import argparse
import cmd
import shlex

class TestCLI(cmd.Cmd):

    def __init__(self, **kwargs):
        cmd.Cmd.__init__(self, **kwargs)

        self.parser = argparse.ArgumentParser()
        subparsers = self.parser.add_subparsers()
        test_parser = subparsers.add_parser("test")
        test_parser.add_argument("--foo", default="Hello")
        test_parser.add_argument("--bar", default="World")
        test_parser.set_defaults(func=self._do_test)

    def _do_test(self, args):
        print args.foo, args.bar

    def default(self, line):
        args = self.parser.parse_args(shlex.split(line))
        if hasattr(args, 'func'):
            args.func(args)
        else:
            cmd.Cmd.default(self, line)

test = TestCLI()
test.cmdloop()

argparse делает sys.exit если он сталкивается с неизвестными командами, то вам придется переопределить или обезьяна исправить ваш ArgumentParser "s error способ вызвать исключение вместо выхода и обработать его в default метод, чтобы остаться в cmd Командный цикл.

Я бы посоветовал вам взглянуть на скалу, которая позволяет вам писать команды, которые могут автоматически использоваться как argparse а также cmd команды, что довольно аккуратно. Он также поддерживает команды загрузки из setuptools точки входа, которые позволяют распределять команды в виде плагинов для вашего приложения. Обратите внимание, что cliff использования cmd2, который cmd более сильный кузен, но вы можете заменить его cmd как cmd2 был разработан в качестве замены для замены cmd,

Другие вопросы по тегам