Аргумент командной строки перезаписывается значением по умолчанию при использовании subparser

#python #parsing #command-line-arguments #argparse #subcommand

#python #синтаксический анализ #аргументы командной строки #argparse #подкоманда

Вопрос:

У меня есть программа с вложенными командами, но все они имеют общие аргументы (например, все они требуют каталогов ввода и вывода), которые я включил в родительский анализатор, чтобы избежать избыточности. Однако я хочу, чтобы каждая подкоманда имела другое значение по умолчанию, но это приводит к игнорированию значения, указанного в командной строке.

MWE:

 import argparse

top_parser = argparse.ArgumentParser()
top_parser.add_argument("--input-dir", type=str)

subparsers = top_parser.add_subparsers()

generate_parser = subparsers.add_parser("generate")
generate_parser.set_defaults(input_dir=".")

process_parser = subparsers.add_parser("process")
process_parser.set_defaults(input_dir="SOME_OTHER_DIR")

generate_args = top_parser.parse_args("--input-dir USE_THIS_DIR generate".split())
print("generate_args = ", generate_args)

process_args = top_parser.parse_args("--input-dir USE_THIS_DIR process".split())
print("process_args = ", process_args)
 

Это дает:

 generate_args =  Namespace(input_dir='.')
process_args =  Namespace(input_dir='SOME_OTHER_DIR')
 

но я хочу:

 generate_args =  Namespace(input_dir='USE_THIS_DIR')
process_args =  Namespace(input_dir='USE_THIS_DIR')
 

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

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

1. Изменение, внесенное несколько лет назад argparse , делает значение subparser по умолчанию переопределяющим значение по умолчанию и / или значение основного синтаксического анализатора. Придумайте какой-нибудь другой способ, возможно, при последующем анализе, чтобы установить пользовательское значение по умолчанию (если, например, значение по умолчанию по умолчанию None ).

2. Или используйте другое dest при установке значения по умолчанию для subparser.

Ответ №1:

Одним из обходных путей было бы проверить значение input_dir after синтаксического анализа и заменить в это время значение по умолчанию, зависящее от subparser.

 import argparse

top_parser = argparse.ArgumentParser()
top_parser.add_argument("--input-dir", type=str)

subparsers = top_parser.add_subparsers()

generate_parser = subparsers.add_parser("generate")
generate_parser.set_defaults(alt_input_dir=".")

process_parser = subparsers.add_parser("process")
process_parser.set_defaults(alt_input_dir="SOME_OTHER_DIR")

args = top_parser.parse_args()
if args.input_dir is None:
    args.input_dir = args.alt_input_dir
del args.alt_input_dir
 

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

1. Спасибо! Это обходное решение определенно работает. Хотя я все еще немного в замешательстве. Почему использование set_defaults функции с каждым подразделом приводит USE_THIS_DIR к полному игнорированию?

2. Это хороший вопрос; я еще не понял, намеренно это или ошибка.

3. Это было преднамеренное поведение — со стороны первоначального разработчика. Смотрите _SubParsersAction.__call__ метод.

4.bugs.python.org/issue9351 argparse set_defaults on subcommands should override top level set_defaults

5. @hpaulj Это немного отличается; значение по умолчанию subparser не переопределяет значение по умолчанию синтаксического анализатора; оно переопределяет явное использование параметра.