python argparse store --foo = bar como args.key = 'foo', args.value = 'bar'
Eu gostaria de analisar uma linha de comando que tenha um grupo de opções mutuamente exclusivo. Normalmente, eu usaria--foo bar
que produziria, no espaço de nomes,args.foo = 'bar'
No entanto, como todas essas opções são mutuamente exclusivas, e eu estou interessado no nome da opção e no argumento passado para a opção, e eu tenho várias dessas opções que precisam ser alimentadas a jusante, o que eu realmente gostaria é voltarargs.option_name = 'foo', args.option_value = 'bar'
no meu espaço para nome em vez deargs.foo='bar'
.
O que eu fiz é:
class KeyAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
setattr(namespace, self.dest+'_key', option_string)
frob = parser.add_mutually_exclusive_group()
frob.add_argument('--foo', dest='thing', nargs='?', action=KeyAction)
frob.add_argument('--nar', dest='thing', nargs='?', action=KeyAction)
quando executado, meu namespace será semelhante a:
Namespace(thing_key='--foo', thing='bar')
quando--foo=bar
é analisado. Obviamente, infelizmente, se --foo ou --nar nunca é passado,namespace.thing_key
não é definido, então eu tenho que usar umgetattr()
.
A substituição da ação, embora funcional, não parece realmente correta.
Suspeito que as mentes brilhantes por trás do argparse já tenham acertado de alguma forma, e só estou perdendo isso na documentação e na minha leitura do argparse.py.
Qual é a melhor maneira, certa, pitônica, de fazer isso? Subparsers? Estou usando python 3.5.
Então, acabei usando os dados de ambas as suas respostas para construir isso, que lida com a opção, seu argumento e define tudo de forma sutil no momento da inicialização.
Muito obrigado pelas dicas, pistas e validação. Estou surpreso que isso não tenha sido discutido antes e se tornado algo padronizado. istoé uma caixa de canto, mas não é uma caixa de cantoao usar opções mutuamente exclusivas.
class ValueAction(argparse.Action):
"""Override to store both the format type as well as the argument"""
# pylint: disable=too-few-public-methods
def __init__(self, option_strings, dest, **kwargs):
self._dest = dest
dest = dest + '_arguments'
container = kwargs.pop('container')
kwargs['action'] = kwargs.pop('subaction')
action_class = container._pop_action_class(kwargs)
if not callable(action_class):
raise ValueError('unknown action "%s"' % (action_class,))
self._action = action_class(option_strings, dest, **kwargs)
super().__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
self._action(parser, namespace, values, option_string)
if isinstance(option_string, str):
while option_string[0] in parser.prefix_chars:
option_string = option_string[1:]
setattr(namespace, self._dest, option_string)