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)
Не очень элегантно, но это работает.