Несколько аргументов без флажков с цементом

#python #command-line-interface

#python #интерфейс командной строки

Вопрос:

Я пишу инструмент интерфейса командной строки python поверх cement. Цемент работает достаточно хорошо для стандартного синтаксического анализа аргументов. Тем не менее, я хочу иметь возможность добавлять определенное количество немеченых аргументов. Позвольте мне объяснить.

Типичный инструмент командной строки:

 cmd subcmd -flag -stored=flag
  

Теперь, допустим, я хочу добавить некоторые аргументы без флагов, например, как работает cd

 cd my/dir
  

my/dir является аргументом без флага.

Есть ли способ сделать это с цементом?

Мой текущий пример приложения cement:

 # define application controllers
class MyAppBaseController(controller.CementBaseController):
    class Meta:
        label = 'base'
        interface = controller.IController
        description = "My Application Does Amazing Things"
        arguments = [
            (['--base-opt'], dict(help="option under base controller")),
            ]

    @controller.expose(help="base controller default command", hide=True)
    def default(self):
        self.app.args.parse_args(['--help'])
        print "Inside MyAppBaseController.default()"

    @controller.expose(help="another base controller command")
    def command1(self):
        print "Inside MyAppBaseController.command1()"
  

Итак, допустим, я хотел сделать myapp command1 some/dir some_string

есть ли способ проанализировать эти аргументы?

Ответ №1:

Вы можете сделать это, используя необязательные позиционные аргументы в ArgParse. На самом деле в GitHub открыта проблема для лучшей документации по этому вопросу:

https://github.com/datafolklabs/cement/issues/256

В принципе, если вы хотите, чтобы «command1» обрабатывал операцию, то «some / dir some_string» будут позиционными аргументами. Вы могли бы добавить следующее в MyAppBaseController.Meta.arguments:

( ['extra_arguments'], dict(action='store', nargs='*') ),

А затем получить доступ к этим аргументам следующим образом внутри command функции:

if self.app.pargs.extra_arguments:
print "Extra Argument 0: %s" % self.app.pargs.extra_arguments[0]
print "Extra Argument 1: %s" % self.app.pargs.extra_arguments[1]

Комментарии:

1. Это ИМЕННО то, что я хотел!! Я собирался создать свой собственный фреймворк, потому что не мог найти ответ. Я бы проголосовал за это примерно 10 раз, если бы мог.

2. Очень полезно. Спасибо!

Ответ №2:

Как сказано в документе Cement: «Cement определяет интерфейс аргументов с именем IArgument, а также ArgParseArgumentHandler по умолчанию, который реализует интерфейс. Этот обработчик построен поверх модуля ArgParse, который включен в стандартную библиотеку Python »

Вы могли бы добиться этого, указав модулю argparse использовать один аргумент из списка arguments и сохранить его в атрибуте name списка pargs.

 # define application controllers
class MyAppBaseController(controller.CementBaseController):
    class Meta:
        label = 'base'
        interface = controller.IController
        description = "My Application Does Amazing Things"
        arguments = [
            (['--base-opt'], dict(help="option under base controller")),
        ]

    @controller.expose(help="base controller default command", hide=True)
    def default(self):
        self.app.args.parse_args(['--help'])
        print "Inside MyAppBaseController.default()"

    @controller.expose(
        help="another base controller command",
        arguments=[
            (['path'],
             dict(type=str, metavar='PATH', nargs='?', action='store', default='.')),
            (['string'],
             dict(type=str, metavar='STRING', nargs='?', action='store', default='')),
        ]
    )
    def command1(self):
        print "Inside MyAppBaseController.command1() path: %s string: %s" % (self.app.pargs.name, self.app.pargs.string)