Оказывается, правильный способ справиться с этим - реализовать собственный argparse.Action
.
В конкретном случае c это что-то работает разумно:
!/bin/env python3
from argparse import ArgumentParser, Action
class KeypairAction(Action):
def __init__(self, option_strings, dest, keys=None, **kwargs):
super().__init__(option_strings, dest, **kwargs)
if keys is None:
raise ValueError('must define "keys" argument')
if isinstance(keys, dict):
self.keys = keys
elif isinstance(keys, (list, tuple)):
self.keys = {}
for k in keys:
if isinstance(k, tuple):
k, v = k
else:
v = None
self.keys[k] = v
def __call__(self, parser, namespace, values, option_string=None):
d = {}
for x in values.split(','):
try:
k, v = x.split('=')
except ValueError:
k = x
v = None
d[k] = v
setattr(namespace, self.dest, d)
ap = ArgumentParser(description="My nice program")
ap.add_argument('-D', '--database', action=KeypairAction, keys=('type', 'host', 'port', 'user', 'pass', 'db'))
ap.add_argument('-M', '--mail', action=KeypairAction, keys=('type', 'host', 'port', 'user', 'pass'))
ap.add_argument('-W', '--whatever', action=KeypairAction, keys=('key1', 'key2', 'key3', 'etcetera'))
args = ap.parse_args('--database type=mysql,user=root,pass=secret,db=mydb '
'--mail type=imap,host=imap.my.domain,user=myself,pass=othersecret,port=999 '
'--whatever key1=val,key2=val2,etcetera'.split())
print(args)
Это может быть тривиально расширен для обработки значений по умолчанию.