Python 2.7 argparse: Как правильно вставить необязательные мутабельные аргументы?

Моя программа должна включать следующие параметры, правильно разобранные argparse:

  • чисто необязательный: [-h, --help] и [-v, --version]
  • взаимоисключающий: [-f FILE, --file FILE] и [-u URL, --url URL]
  • необязательно, если выбрано --url: [-V, --verbose]
  • требуется, если выбрано либо --file, либо --url: [-F, --format FORMAT]

Желаемый шаблон использования:

prog.py [-h] [-v] [-f FILE (-F FORMAT) | -u URL [-V] (-F FORMAT) ]

с требованием -F, применяемым к обоим членам взаимоисключающей группы.
Не уверен, что это скорее positional.

Так что должно быть возможно запустить:

prog.py -u "http://foo.bar" -V -F csv

и крик синтаксического анализа в случае, если я забыл -F (как он и предполагал).

Что я сделал до сих пор:

parser = ArgumentParser(decription='foo')

group = parser.add_mutually_exclusive_group()    
group.add_argument('-f','--file', nargs=1, type=str, help='')
group.add_argument('-u','--url', nargs=1, type=str, help='')    

parser.add_argument('-V','--verbose', action='store_true', default=False, help='')
parser.add_argument('-F','--format', nargs=1, type=str, help='')

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

Как я могу реализовать точки 3. и 4. в свой код?

EDIT:
Я пробовал -F и -u как подпарамеры, как описано здесь, но подкоманды, похоже, рассматриваются как позиционные, и синтаксический анализатор дает мне error: too few arguments, если я запускаю это без аргументов.

Ответ 1

Использование nargs = 2 и metavar кортежа приближают вашу цель

parser = argparse.ArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group()
group.add_argument('-f','--file', nargs=2, metavar=('FILE','FORMAT'))
group.add_argument('-u','--url', nargs=2, metavar=('URL','FORMAT'))
parser.add_argument('-V','--verbose', action='store_true',help='optional with url')

который производит:

usage: PROG [-h] [-f FILE FORMAT | -u URL FORMAT] [-V]

optional arguments:
  -h, --help            show this help message and exit
  -f FILE FORMAT, --file FILE FORMAT
  -u URL FORMAT, --url URL FORMAT
  -V, --verbose         optional with url

Для этого требуется формат вместе с именем файла или URL-адресом, он просто не требует -F. Как отмечали другие, -V можно игнорировать в случае -F.


Я попробовал -f и -u как подпарамеры, как описано здесь, но подкоманды, похоже, рассматриваются как позиционные, и синтаксический анализатор дает мне ошибку: слишком мало аргументов, если я запускаю его без аргументов.

В последней версии (ей) подкоманды больше не рассматриваются как обязательные позиционные элементы. Это было, насколько я могу судить, побочным эффектом изменения сообщения об ошибке, чтобы быть более информативным. Вместо _parse_known_args выполните:

    if positionals:
        self.error(_('too few arguments'))

он сканирует _actions, чтобы увидеть, какие из них требуются, и затем перечисляет их по имени в сообщении об ошибке. Это обсуждается в http://bugs.python.org/issue9253. Я знаю, что это изменение находится в разработке (3.4), а также может быть в 3.3.


Ответ 2

Эти точки могут применяться в optparse с помощью метода callback, когда присутствует определенная опция.

Однако в argparse они недоступны.

Вы можете добавить subparser для подкатегории url и file и проанализировать их отдельно. из справки:

Обратите внимание, что объект, возвращаемый parse_args(), будет содержать только атрибуты для основной синтаксический анализатор и подпараметр, который был выбран командной строкой (а не любых других подпараметров). Итак, в приведенном выше примере, когда команда, только атрибуты foo и bar присутствуют, а когда команда b указан только атрибуты foo и baz.

Но я бы просто правильно документировал использование и просто игнорировал аргументы, которые не являются применимо.

например. пусть эти две командные строки ведут себя точно так же:

prog.py -f FILE -V
prog.py -f FILE