в зависимости от другой настройки? - PullRequest
0 голосов
/ 27 января 2020

Я пытаюсь написать программу, которая поддерживает произвольные побитовые операции: AND, OR, NOT и COUNT для растровых изображений. Использование заключается в том, что вы запускаете program.py --and f1.bit f2.bit, и он выводит результат на стандартный вывод.

Проблема в том, что я бы хотел, чтобы синтаксический анализатор обрабатывал все предупреждения. В частности, я хотел бы, чтобы nargs зависели от установленного режима - если он установлен в COUNT или NOT, ожидается ровно один файл, если он установлен в OR или AND, ожидайте ровно два. Вот пример (нерабочего) примера кода:

#!/usr/bin/env python

import argparse

def main(mode, fnames):
    pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-O', '--or',
        nargs=2,
        action='store_const', const='or'
    )
    args = parser.parse_args()

    import pprint
    pprint.pprint(args.__dict__)

    #main(**args.__dict__)

И ошибка, которую я получаю:

Traceback (most recent call last):
  File "bitmaptool.py", line 12, in <module>
    action='store_const', const='or'
  File "/usr/lib/python3.7/argparse.py", line 1362, in add_argument
    action = action_class(**kwargs)
TypeError: __init__() got an unexpected keyword argument 'nargs'

Комментирование nargs помогает, как и оставление nargs вне но комментируя action - но я хочу и того, и другого. Нужно ли реализовать это вручную или есть хитрость или другая библиотека, которая позволила бы мне туда добраться?

РЕДАКТИРОВАТЬ Я хотел уточнить, что я ищу, показывая, какой код я для того, чтобы все заработало, нужно написать вручную:

if __name__ == '__main__':
    parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
    parser.add_argument('-O', '--or', nargs=2)
    parser.add_argument('-A', '--and', nargs=2)
    parser.add_argument('-M', '--minus', nargs=2)
    parser.add_argument('-C', '--count', nargs=1)
    parser.add_argument('-N', '--not', nargs=1)
    parser.add_argument('-o', '--output', default='/dev/stdout')
    args = parser.parse_args().__dict__

    mode = None
    files = []
    for current_mode in ['or', 'and', 'not', 'count']:
        if current_mode in args:
            if mode is not None:
                sys.exit('ERROR: more than one mode was specified')
            mode = current_mode
            files = args[mode]

    if mode is None:
        sys.stderr.write('ERROR: no mode was specified\n\n')
        parser.print_help()
        sys.exit(1)

    import pprint
    pprint.pprint(args)

Есть ли более элегантный способ добраться туда?

1 Ответ

1 голос
/ 27 января 2020

store_const никогда не получает аргументы, оно буквально хранит то, что вы указали как const или None. Потому что это константа, а не переменная. Из документации action argparse , ephasis mine:

'store_const' - в этом хранится значение, указанное в аргументе ключевого слова const . Действие 'store_const' чаще всего используется с необязательными аргументами, которые задают своего рода флаг .

Вы должны изменить действие на что-то, что фактически будет хранить переданные имена файлов. Согласно документации argparse nargs и примеру, вам вообще не нужно указывать action, по умолчанию (action='store') будет достаточно.

Пример из документации:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs=2) #this line
>>> parser.add_argument('bar', nargs=1)
>>> parser.parse_args('c --foo a b'.split())
Namespace(bar=['c'], foo=['a', 'b'])

РЕДАКТИРОВАТЬ для отредактированной версии вопроса - взаимоисключающая группа будет гарантировать, что только один аргумент (конечно, из этой группы) указано:

if __name__ == '__main__':
    parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
    parser.add_argument('-o', '--output', default='/dev/stdout')

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('-O', '--or', nargs=2)
    group.add_argument('-A', '--and', nargs=2)
    group.add_argument('-M', '--minus', nargs=2)
    group.add_argument('-C', '--count', nargs=1)
    group.add_argument('-N', '--not', nargs=1)

    args = parser.parse_args().__dict__

    import pprint
    pprint.pprint(args)
...