Python argparse - либо оба необязательных аргумента, либо ни один

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

parser.add_argument(
    '-n',
    '--name',
    help='the login name that you wish the program to use'
    )

parser.add_argument(
    '-p',
    '--password',
    help='the password to log in with.'
    )

Но не имеет смысла указывать только имя или только пароль, но было бы бессмысленно указывать ни один. Я заметил, что у argparse есть возможность указать, что два аргумента являются взаимоисключающими. Но у меня есть два аргумента, которые должны появиться вместе. Как мне получить это поведение? (Я нашел "группы аргументов", упомянутые в документах, но они, похоже, не решают мою проблему http://docs.python.org/2/library/argparse.html#argument-groups)

Ответ 1

Я считаю, что лучший способ справиться с этим - это обработать возвращаемое пространство имен. Причина, по которой argparse не поддерживает это, состоит в том, что она анализирует аргументы 1 за раз. Легко для argparse проверить, не было ли что-то уже разобрано (вот почему работают взаимоисключающие аргументы), но нелегко понять, будет ли что-то разбираться в будущем.

Прост:

parser.add_argument('-n','--name',...,default=None)
parser.add_argument('-p','--password',...,default=None)
ns = parser.parse_args()

if len([x for x in (ns.name,ns.password) if x is not None]) == 1:
   parser.error('--name and --password must be given together')

name = ns.name if ns.name is not None else "default_name"
password = ns.password if ns.password is not None else "default_password"

похоже, что этого будет достаточно.

Ответ 2

Я знаю, что прошло уже более двух лет, но я нашел хороший и лаконичный способ сделать это:

if bool(ns.username) ^ bool(ns.password):
    parser.error('--username and --password must be given together')

^ - это оператор XOR в Python. Требовать, чтобы оба аргумента, заданные в командной строке, были в основном тестом XOR.

Ответ 3

Скорее всего, я это сделаю. Поскольку у вас есть существующие значения по умолчанию с возможностью изменения, определите значения по умолчанию, но не используйте их в качестве аргументов по умолчанию:

default_name = "x"
default_pass = "y"
parser.add_argument(
    '-n',
    '--name',
    default=None,
    help='the login name that you wish the program to use'
    )

parser.add_argument(
    '-p',
    '--password',
    default=None,
    help='the password to log in with.'
    )
args = parser.parse_args()
if all(i is not None for i in [args.name, args.password]):
    name = args.name
    passwd = args.password
elif any(i is not None for i in [args.name, args.password]):
    parser.error("Both Name and Password are Required!")
else:
    name = default_name
    passwd = default_pass