arparse аргумент python из каталога

У меня есть такая структура файла:

project/ main_prog.py tools/ script.py md_script/ __init__.py md_script.py

Я ищу в инструментах для локальных модулей Python. В этом примере это md_script. И я хочу использовать его как позиционный аргумент, такой как install в моем коде, но когда я его использую, у меня появляется ошибка:

./jsh.py md_script
usage: jsh.py [-h] {install,call,list,log,restore} ... [md_script]
jsh.py: error: invalid choice: 'md_script' (choose from 'install', 'call', 'list', 'log', 'restore')

Python3.4 на Ubuntu14.10 Вот мой код:

parser = argparse.ArgumentParser(prog='jsh.py',
    description='Some help.', epilog='Example of usage: some help')
subparsers = parser.add_subparsers()
parser_install = subparsers.add_parser('install', help = 'Install new project.')
parser_install.add_argument('install', nargs='?', help = 'Name of project to be installed')
if os.path.isdir(full/path/to/tools/):
   name_arg = next(os.walk(full/path/to/tools))[1]
   tools_arg = parser.add_argument_group('Tools', 'Modules from tools')
   for element in name_arg:
      tools_arg.add_argument(element, nargs='?', help='md_script description')
args = parser.parse_args()
try:
  if not len(sys.argv) > 1:
     parser.print_help()
  elif 'install' in args:
     do_some_stuff
  elif element in args:
     do_some_md_script_stuff
  else:
     parser.print_help()

2 ответа

usage строка показывает, что не так:

usage: jsh.py [-h] {install,call,list,log,restore} ... [md_script]

Вам нужно использовать что-то вроде

jsh.py install md_script

Вы указали подпарсеры, поэтому вы должны дать ему имя подпарсера.


От usage похоже, что вы создали другие подпарсеры, call, listи т. д., что вы не показываете в коде.

Вы также определяете позиционные аргументы после создания подпаратера. Вот где [md_script] происходит от. Будьте осторожны, делая много nargs='?' позиционеры (включая аргумент для install subparser). Это может запутать ваших пользователей. На самом деле это, кажется, сбивает вас с толку. Помни что subparser в действительности это позиционный аргумент (тот, который требует 1 строку).

Я бы предложил поэкспериментировать с более простым парсером, прежде чем создавать такой сложный.


Итак, из ваших комментариев и примеров я вижу, что ваша цель - дать пользователю имя модуля, чтобы ваш скрипт мог так или иначе вызывать его. Для этого имеет смысл заполнять подпапки этими именами.

Интересно, почему вы также создаете необязательный позиционный аргумент с тем же именем:

module_pars = subparsers.add_parser(element, help = 'Modules from tools')
module_pars.add_argument(element, nargs='?', help=element+' description')

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

elif element in args:
    do_some_md_script_stuff

argparse В документации есть пара других идей.

Одним из особенно эффективных способов обработки подкоманд является объединение использования метода add_subparsers() с вызовами set_defaults(), чтобы каждый подпарсер знал, какую функцию Python он должен выполнить.

а также

Однако, если необходимо проверить имя вызванного подпаратера, аргумент ключевого слова dest к вызову add_subparsers() будет работать:

Это позволяет избежать беспорядка "?" позиционный аргумент, освобождая вас от использования аргументов субпарсера для реальной информации.

subparsers = parser.add_subparsers(dest='module')
....
for element in name_arg:
    # module_pars = 'parser_'+element   # this does nothing
    module_pars = subparsers.add_parser(element, help = 'Modules from tools')
    module_pars.set_defaults(func = do_some_md_script_stuff)
    # or module_pars.set_default(element='I am here')
    module_pars.add_argument('real_argument')

Теперь вы можете проверить:

if args.module='md_script':
    do_some_md_script_stuff(args)

или же

if hasattr(args, 'func'):
    func(args)

С альтернативой set_defaults, ваш оригинальный тест должен все еще работать:

if element in args:
    do_some_md_script_stuff

Я сделал это так Это именно то, что я хочу.

if os.path.isdir(TOOLS_PATH):
   name_arg = next(os.walk(TOOLS_PATH))[1]
   for element in name_arg:
      module_pars = 'parser_'+element
      module_pars = subparsers.add_parser(element, help = 'Modules from tools')
      module_pars.add_argument(element, nargs='?', help=element+' description')

Я не проверял это, потому что у меня нет тестового модуля, но ./jsh.py md_script переходит в elif element in args: print('md_script') и распечатать строку. Похоже, это работает. Спасибо за все ответы.

Изменить: я проверял это. В add_argument я должен изменить nargs='?' для nargs='*' чтобы поймать более одного аргумента. И чтобы поймать аргументы из командной строки, я использовал это:

elif args:
   for element in name_arg:
      if element in args:
         element_arg = sys.argv[2:]
         done_cmd,msg = opt_exec_module(element,*element_arg)
         my_logger(done_cmd,msg)

Не очень элегантно, но это работает.

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