Python: переход с optparse на argparse

После перехода с optparse на argparse возникают странные ошибки. Argparse анализирует аргументы, только если не оставлять пробелов:

myScript.py -oOpt

или поставить знак равенства:

myScript.py -o=Opt

и это не работает обычным способом:

myScript.py -o Opt

Вот моя инициализация argparse:

#!/usr/bin/env python
# to get description use the -h flag

import argparse, os, sys


# ======================
# Python2.7 is expected:

if sys.version_info[0] != 2 or sys.version_info[1] < 7:
    sys.exit('This program needs Python2.7+')


# ==========
# preambule:

desc = """Enter dirs in the current dir and makes gro out of state.cpt there."""
# parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description=desc, version='2.3', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-w', '--workWith',
                    help = 'to specify a Gromacs exec suffix', 
                    dest = 'wW',
                    action = 'store',
                    default = '-4.5.5-single',
                    )
parser.add_argument('-g', '--gro',
                    help = '.gro postfix: <nameOfTheDir><postfix>.gro', 
                    dest = 'myGroPostfix',
                    action = 'store',
                    default = "_membrane",
                    )
parser.add_argument('-H', '--here',
                    help = 'toggles - single (current) dir behaviour (the output will be state.gro)', 
                    dest = 'Here',
                    action = 'store_true',
                    )
parser.add_argument('-D', '--dirs',
                    help = 'include these dirs (python\'s rgxp in SINGLE quotes), defaults to \'\'', 
                    dest = 'inclDirs',
                    action = 'store',
                    default = '',
                    )

args = parser.parse_args()


print args.wW

Изменить:

Даже больше:

 gmx_bk-simulate-mems.py -j bk-runs-mpi.bash -p 1 -w="-4.5.5-double_non-parallel_gcc" 2&> ../`date +%Y-%b-%d-%H%M%S`.log &

дает:

 gmx_bk-simulate-mems.py: error: unrecognized arguments: 2

похоже, что argparse рассматривает 2&> как вариант (или 2&> и ../date +%Y-%b-%d-%H%M%S.log как варианты)!

Редактировать 2:

Итак, подведем итог:

  • Для argparse - "-4.5.5-double_non-parallel_gcc" это плохое имя варианта - поэтому и требуется писать is как -w="-4.5.5-double_non-parallel_gcc". Для optparse и bash (!) это нормально. bash даже выдает ошибку на -w="-4.5.5-double_non-parallel_gcc" - думает, что аргумент ="-4.5.5-double_non-parallel_gcc" (!);

  • Нет такой вещи, как 2&>. 2> можно использовать, и это не дает ошибок;

  • Это shell, который разбивает строку на аргументы, а не python;

  • argparse намного лучше, чем optparse.


person Adobe    schedule 09.04.2012    source источник
comment
Поместите ваш код в tmp.py, и python tmp.py -w3, и python tmp.py -w 3 напечатают для меня "3".   -  person chepner    schedule 09.04.2012
comment
@chepner: да, это так ... На самом деле проблема дает строку 75 в gmx_bk-get-results.bash: если удалить = из этой строки - скрипт выдает ошибку - как будто я не даю ему "$wW". Для воспроизведения необходимо также получить bk -copies-from-dirs.py и gmx_bk -cpt2gmx.py... На optparse все работало нормально. Я надеюсь, что кто-то увидит проблему теоретически.   -  person Adobe    schedule 09.04.2012
comment
Педантичный комментарий: вам не нужна проверка версий. Если вы используете Python 3, оператор печати внизу вызовет синтаксическую ошибку, и скрипт даже не будет загружен. Если вы используете Python 2.6 или ниже, сценарий завершится ошибкой при импорте argparse еще до того, как вы доберетесь до проверки версии.   -  person HardlyKnowEm    schedule 11.04.2012
comment
Тем не менее, это был очень интересный вопрос, и размышления над ним открыли мне кое-что новое о argparse. Спасибо, что поделились!   -  person HardlyKnowEm    schedule 11.04.2012


Ответы (1)


Во-первых, необходимо сделать небольшое различие. Модуль argparse не анализирует ваши аргументы командной строки, это делает оболочка. Оболочка отвечает за преобразование строки, которую вы вводите в оболочке, в токены, которые затем передаются в sys.argv, массив/последовательность аргументов командной строки Python. Модуль argparse просто имеет смысл того, что появляется в sys.argv.

Это различие прояснит обе «ошибки», которые вы заметили. Сначала рассмотрим -w "-4.5.5-double_non-parallel_gcc" (обратите внимание на отсутствие знака равенства). Оболочка анализирует эти две лексемы как -w и -4.5.5-double_non-parallel_gcc, и обе эти строки передаются в sys.argv. Без знака равенства получается два варианта: -w (без аргумента) и -4 с .5.5-double_non-parallel_gcc в качестве аргумента. Вам нужен знак равенства, чтобы все анализировалось как один токен.

ОТРЕДАКТИРОВАННЫЙ РАЗДЕЛ

Что касается 2&>, argparse не может контролировать, рассматривается ли данный токен как аргумент или нет. Если что-то появляется в sys.argv, это означает, что ваша оболочка рассматривает это как аргумент.

Контрольным знаком здесь является сообщение об ошибке. Обратите внимание, что сообщение не unrecognized arguments: 2&>, а unrecognized arguments: 2. Ваша оболочка распознает «&>» как перенаправление вывода и соответственно анализирует остальную часть строки (включая файл журнала). Единственный передаваемый аргумент — «2», потому что 2&> не является реальным типом перенаправления. (&> уже охватывает как stderr, так и stdout, так что же 2 добавит к нему?)

В комментарии вы утверждали, что optparse может "обработать" "2&>". На самом деле это не так. Модуль optparse делал именно то, что делает argparse, но optparse не проверяет позиционные аргументы, как это делает argparse. На самом деле, optparse позволяет реальной ошибке программирования (в данном случае, используя 2&> как тип перенаправления оболочки) проскользнуть незамеченной! Вы должны опубликовать исходный код optparse, но я подозреваю, что вы проанализировали свои аргументы следующим образом:

opt, args = parser.parse_args()

Ваш сценарий не принимает позиционных аргументов, поэтому я полагаю, что вы больше ничего не делали с args впоследствии. Но если бы вы проверили args, вы бы обнаружили, что 2 считалось позиционным аргументом!

В общем, если сценарий не принимает позиционных аргументов и вы используете optparse, рекомендуется убедиться, что вы не получаете позиционных аргументов, например:

opt, args = parser.parse_args()
if args:
    parser.error("script takes no positional arguments")

Модуль argparse делает это за вас, поэтому он намного опережает optparse (помимо других причин).

person HardlyKnowEm    schedule 11.04.2012
comment
Все работало нормально с optparse. Но похоже, что "-4.5.5-double_non-parallel_gcc" — это плохое имя опции, и если optparse выходит из кавычек, то argparse нет — отсюда и ошибка. А как насчет части 2&>? Он отлично работал с optparse. Он отлично работает с номером 2: &>. Я могу так жить - но разве это не странно? Это должно быть решено. Это должно работать и с 2&>. - person Adobe; 11.04.2012
comment
Я отредактировал свой ответ выше, чтобы решить вашу проблему. Опять же, 2&> не является настоящим флагом перенаправления; 2> есть, и &> есть, и даже 2>&1 есть, но не 2&>. Если не верите, попробуйте со встроенной оболочкой: ls 2&> tmp.txt. &> захватывает stderr, поэтому вы не увидите его сразу, но если вы посмотрите на tmp.txt, вы увидите сообщение об ошибке. - person HardlyKnowEm; 11.04.2012