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