Подтвердить что ты не робот

Не удается заставить argparse читать цитированную строку с тире в ней?

Есть ли способ заставить argparse распознавать что-либо между двумя кавычками как один аргумент? Кажется, что он продолжает видеть тире и полагает, что это начало новой опции

У меня есть что-то вроде:

mainparser = argparse.ArgumentParser()
subparsers = mainparser.add_subparsers(dest='subcommand')
parser = subparsers.add_parser('queue')
parser.add_argument('-env', '--extraEnvVars', type=str,
                        help='String of extra arguments to be passed to model.')
...other arguments added to parser...

Но когда я запускаю:

python Application.py queue -env "-s WHATEVER -e COOL STUFF"

Это дает мне:

Application.py queue: error: argument -env/--extraEnvVars: expected one argument

Если я отойду от первого тире, он будет работать отлично, но это очень важно, чтобы я мог передать строку с тире в ней. Я попытался убежать от него с \, что приводит к его успеху, но добавляет строку\в строку аргументов. Кто-нибудь знает, как обойти это? Это происходит независимо от того, является или нет аргументом ss в парсере.

EDIT: я использую Python 2.7.

EDIT2:

python Application.py -env " -env"

работает отлично, но

python Application.py -env "-env"

нет.

EDIT3: Похоже, это на самом деле ошибка, которая уже обсуждалась: http://www.gossamer-threads.com/lists/python/bugs/89529, http://python.6.x6.nabble.com/issue9334-argparse-does-not-accept-options-taking-arguments-beginning-with-dash-regression-from-optp-td578790.html. Это только в 2.7, а не в optparse.

EDIT4: Текущий отчет об ошибке: http://bugs.python.org/issue9334

4b9b3361

Ответ 1

Вы можете запустить аргумент с пробелом python tst.py -e ' -e blah' как очень простой способ обхода. Просто lstrip() возможность вернуть его в нормальное состояние, если хотите.

Или, если первый "вспомогательный аргумент" также не является допустимым аргументом исходной функции, вам не нужно ничего делать вообще. То есть единственная причина, по которой python tst.py -e '-s hi -e blah' не работает, состоит в том, что -s является допустимой опцией tst.py.

Кроме того, модуль optparse, теперь устаревший, работает без каких-либо проблем.

Ответ 2

Обновленный ответ:

Вы можете поместить знак равенства, когда вы его назовете:

python Application.py -env="-env"

Оригинальный ответ:

У меня тоже были проблемы, делающие то, что вы пытаетесь сделать, но в argparse есть обходное решение, которое является методом parse_known_args. Это позволит всем аргументам, которые вы не определили, пройти через парсер с предположением, что вы будете использовать их для подпроцесса. Недостатки в том, что вы не получите сообщение об ошибках с плохими аргументами, и вам нужно будет убедиться, что между вашими параметрами и вашими параметрами подпроцесса нет конфликта.

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

python Application.py -e "+s WHATEVER +e COOL STUFF"

а затем вы поменяете "+" на "-" в пост-обработке перед тем, как перейти к вашему подпроцессу.

Ответ 3

Эта проблема подробно обсуждается в http://bugs.python.org/issue9334. Большая часть активности была в 2011 году. Я добавил патч в прошлом году, но там довольно отставание от argparse патчей.

Возникает потенциальная двусмысленность в строке типа '--env' или "-s WHATEVER -e COOL STUFF", когда она следует за опцией, которая принимает аргумент.

optparse выполняет простой анализ слева направо. Первый --env - это флаг опции, который принимает один аргумент, поэтому он потребляет следующий, независимо от того, как он выглядит. argparse, с другой стороны, дважды проходит строки. Сначала он классифицирует их как "O" или "A" (флаг или аргумент опций). Во втором цикле он потребляет их, используя сопоставление типа re, подходящее для обработки значений переменной nargs. В этом случае мы видим, что у нас есть OO, два флага и никаких аргументов.

Решение при использовании argparse состоит в том, чтобы убедиться, что строка аргумента не будет путаться для флажка параметра. Возможности, которые были показаны здесь (и в проблеме с ошибкой), включают:

--env="--env"  # clearly defines the argument.

--env " --env"  # other non - character
--env "--env "  # space after

--env "--env one two"  # but not '--env "-env one two"'

Сам по себе '--env' выглядит как флаг (даже при цитировании, см. sys.argv), но если следовать за другими строками, это не так. Но "-env one two" имеет проблемы, потому что он может быть проанализирован как ['-e','nv one two'], флаг `-e ', за которым следует строка (или даже больше параметров).

-- и nargs=argparse.PARSER также могут использоваться, чтобы заставить argparse просматривать все следующие строки в качестве аргументов. Но они работают только в конце списка аргументов.

В выпуске 9334 есть предлагаемый патч для добавления режима args_default_to_positional=True. В этом режиме анализатор только классифицирует строки как флаги опций, если он может четко соответствовать им с определенными аргументами. Таким образом, "-one" в "--env -one" будет классифицирован как аргумент. Но второй '--env' в '--env --env' по-прежнему будет классифицироваться как флаг опции.


Расширение на связанном случае в

Использование argparse с значениями аргументов, начинающимися с тире ( "-" )

parser = argparse.ArgumentParser(prog="PROG")
parser.add_argument("-f", "--force", default=False, action="store_true")
parser.add_argument("-e", "--extra")
args = parser.parse_args()
print(args)

производит

1513:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra='--foo one', force=False)
1513:~/mypy$ python3 stack16174992.py --extra "-foo one"
usage: PROG [-h] [-f] [-e EXTRA]
PROG: error: argument -e/--extra: expected one argument
1513:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra='-bar one', force=False)
1514:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra='one', force=True)

Случай "-foo one" терпит неудачу, потому что -foo интерпретируется как флаг -f плюс неуказанные дополнения. Это то же самое действие, которое позволяет -fe интерпретироваться как ['-f','-e'].

Если я изменяю nargs на REMAINDER (не PARSER), все после -e интерпретируется как аргументы для этого флага:

parser.add_argument("-e", "--extra", nargs=argparse.REMAINDER)

Все дела работают. Обратите внимание, что это список. И цитаты не нужны:

1518:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra=['--foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-foo one"
Namespace(extra=['-foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra=['-bar one'], force=False)
1519:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra=['one'], force=True)
1520:~/mypy$ python3 stack16174992.py --extra --foo one
Namespace(extra=['--foo', 'one'], force=False)
1521:~/mypy$ python3 stack16174992.py --extra -foo one
Namespace(extra=['-foo', 'one'], force=False)

argparse.REMAINDER похож на '*', за исключением того, что он принимает все, что следует, независимо от того, выглядит он как флаг или нет. argparse.PARSER больше похож на "+", так как он сначала ожидает один аргумент positional. Это nargs, который использует subparsers.

Используется REMAINDER, https://docs.python.org/3/library/argparse.html#nargs