Argparse: опции для подпарсеров переопределяют main, если оба совместно используют родитель - PullRequest
0 голосов
/ 26 мая 2018

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

from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('--verbose', '-v', action='count')

sub = p.add_subparsers()
a = sub.add_parser('a')

print(p.parse_args())

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

$ python tmp.py -v a
Namespace(verbose=1)

$ python tmp.py a -v
usage: tmp.py [-h] [--verbose] {a} ...
tmp.py: error: unrecognized arguments: -v

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

from argparse import ArgumentParser

parent = ArgumentParser(add_help=False)
parent.add_argument('--verbose', '-v', action='count')

main = ArgumentParser(parents=[parent])

sub = main.add_subparsers()
a = sub.add_parser('a', parents=[parent])

print(main.parse_args())

По какой-то причине ни один из общих флагов не работает в главном парсере.

$ python tmp2.py a -vvv
Namespace(verbose=3)
$ python tmp2.py -vvv a
Namespace(verbose=None)

Обратите внимание, что основной синтаксический анализатор определенно имеет соответствующие аргументы, потому что когда я изменяю его на main = ArgumentParser(), я получаю error: unrecognized arguments: -v.Что мне здесь не хватает?

1 Ответ

0 голосов
/ 26 мая 2018

Сначала пара общих комментариев.

Главный анализатор обрабатывает ввод до вызова подпаратера, затем вызывается подпарсер и получает оставшиеся argv.Когда это сделано, его namespace объединяется с основным namespace.

Механизм parents копирует действия из parent по ссылке.Таким образом, ваш основной и вспомогательный разделители используют один и тот же verbose объект действия.Это было проблемой, когда подпарсер пытается установить другое значение по умолчанию или справку.Это может не быть проблемой здесь, но просто имейте это в виду.

Даже без механизма parents совместное использование флага dest или параметров между main и subparser может быть непростым делом.Следует ли использовать действие подпаратера по умолчанию?Что делать, если оба используются?Перезаписывает ли подпарщик действия основного анализатора?

Первоначально основной namespace был передан подпарсеру, который он изменил и возвратил.Это было изменено некоторое время назад (я могу найти ошибку / проблему при необходимости).Теперь подпарсер начинается с пустого значения по умолчанию namespace и заполняет его.И эти значения затем объединяются в основную.

Так что в вашем связанном SO вопросе будьте осторожны со старыми ответами.argparse, возможно, изменилось с тех пор.

Я думаю, что в вашем случае происходит то, что основной и вспомогательный verbose считаются отдельно.И когда вы получаете None, вы видите значение по умолчанию для субпарсера.

__call__ для _Count_Action:

def __call__(self, parser, namespace, values, option_string=None):
    new_count = _ensure_value(namespace, self.dest, 0) + 1
    setattr(namespace, self.dest, new_count)

Я подозреваю, что в старших argparse, когдапространство имен было общим, count было бы кумулятивным, но я не могу протестировать его, не воссоздав класс действий subparser старого стиля.

https://bugs.python.org/issue15327 - здесь оригинальный разработчик предлагает датьдва аргумента разные dest.Это записывает входные данные от основного и вспомогательного.Ваш собственный код может затем объединить результаты при необходимости.

https://bugs.python.org/issue27859 argparse - subparsers does not retain namespace.Здесь я предлагаю способ воссоздания старого стиля.

https://bugs.python.org/issue9351 argparse set_defaults on subcommands should override top level set_defaults - это проблема 2014 года, которая изменила использование пространства имен.

...