Разбор пустых опций в Python - PullRequest
4 голосов
/ 04 августа 2009

У меня есть приложение, которое позволяет отправлять данные о событиях в пользовательский сценарий. Вы просто размещаете аргументы командной строки и назначаете, какие данные события идут с каким аргументом. Проблема в том, что здесь нет реальной гибкости. Будет использоваться каждый выбранный вами вариант, но не каждый параметр обязательно будет иметь данные. Поэтому, когда приложение создает строку для отправки в сценарий, некоторые из аргументов остаются пустыми, и Python OptionParser выдает ошибку «error: --someargument option требует аргумент»

Поскольку существует более 200 точек данных, я не могу написать отдельные сценарии для обработки каждой комбинации возможных аргументов (для этого потребуется 2 200 сценариев). Есть ли способ обработки пустых аргументов в optionparser python?

Ответы [ 6 ]

8 голосов
/ 05 августа 2009

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

import optparse

def optional_arg(arg_default):
    def func(option,opt_str,value,parser):
        if parser.rargs and not parser.rargs[0].startswith('-'):
            val=parser.rargs[0]
            parser.rargs.pop(0)
        else:
            val=arg_default
        setattr(parser.values,option.dest,val)
    return func

def main(args):
    parser=optparse.OptionParser()
    parser.add_option('--foo',action='callback',callback=optional_arg('empty'),dest='foo')
    parser.add_option('--file',action='store_true',default=False)
    return parser.parse_args(args)

if __name__=='__main__':
    import sys
    print main(sys.argv)



Запустив из командной строки вы увидите это:

# python parser.py
(<Values at 0x8e42d8: {'foo': None, 'file': False}>, [])

# python parser.py --foo
(<Values at 0x8e42d8: {'foo': 'empty', 'file': False}>, [])

# python parser.py --foo bar
(<Values at 0x8e42d8: {'foo': 'bar', 'file': False}>, [])
1 голос
/ 04 августа 2009

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

С optparse вы должны либо указать опцию, включая ее значение, либо не указывать обе.

0 голосов
/ 13 апреля 2013

После проверки, что команда cp понимает, например, --backup=simple но не --backup simple, я ответил на проблему так:

import sys
from optparse import OptionParser

def add_optval_option(pog, *args, **kwargs):
    if 'empty' in kwargs:
        empty_val = kwargs.pop('empty')
        for i in range(1, len(sys.argv)):
            a = sys.argv[i]
            if a in args:
                sys.argv.insert(i+1, empty_val)
                break
    pog.add_option(*args, **kwargs)

def main(args):
    parser = OptionParser()
    add_optval_option(parser,
                      '--foo', '-f',
                      default='MISSING',
                      empty='EMPTY',
                      help='"EMPTY" if given without a value. Note: '
                      '--foo=VALUE will work; --foo VALUE will *not*!')
    o, a = parser.parse_args(args)
    print 'Options:'
    print '  --foo/-f:', o.foo
    if a[1:]:
        print 'Positional arguments:'
        for arg in a[1:]:
            print ' ', arg
    else:
        print 'No positional arguments'

if __name__=='__main__':
    import sys
    main(sys.argv)

Самореклама: это часть opo модуля моего thebops пакета ...; -)

0 голосов
/ 10 ноября 2011

Решение Марка Родди будет работать, но оно требует модификации атрибута объекта синтаксического анализатора во время выполнения и не поддерживает форматирование альтернативных опций, отличное от - или -. Немного менее сложным решением является изменение массива sys.argv перед запуском optparse и вставка пустой строки ("") после переключателя, который не должен иметь аргументов. Единственным ограничением этого метода является то, что ваши параметры по умолчанию имеют предсказуемое значение, отличное от того, которое вы вставляете в sys.argv (я выбрал None для примера ниже, но это действительно не имеет значения).

Следующий код создает пример парсера и набор опций, извлекает массив разрешенных ключей из парсера (используя немного магии переменной экземпляра), а затем перебирает sys.argv и каждый раз находит Разрешенный переключатель, он проверяет, был ли он задан без каких-либо аргументов после него. Если после переключателя нет аргумента, в команду будет вставлена ​​пустая строка линия. После изменения sys.argv вызывается анализатор, и вы можете проверить параметры, значения которых равны "", и действовать соответственно.

#Instantiate the parser, and add some options; set the options' default values to None, or something predictable that
#can be checked later.
PARSER_DEFAULTVAL = None
parser = OptionParser(usage="%prog -[MODE] INPUT [options]")
#This method doesn't work if interspersed switches and arguments are allowed.
parser.allow_interspersed_args = False
parser.add_option("-d", "--delete", action="store", type="string", dest="to_delete", default=PARSER_DEFAULTVAL)
parser.add_option("-a", "--add", action="store", type="string", dest="to_add", default=PARSER_DEFAULTVAL)

#Build a list of allowed switches, in this case ['-d', '--delete', '-a', '--add'] so that you can check if something
#found on sys.argv is indeed a valid switch. This is trivial to make by hand in a short example, but if a program has
#a lot of options, or if you want an idiot-proof way of getting all added options without modifying a list yourself,
#this way is durable. If you are using OptionGroups, simply run the loop below with each group's option_list field.
allowed_switches = []
for opt in parser.option_list:
    #Add the short (-a) and long (--add) form of each switch to the list.
    allowed_switches.extend(opt._short_opts + opt._long_opts)

#Insert empty-string values into sys.argv whenever a switch without arguments is found.
for a in range(len(sys.argv)):
    arg = sys.argv[a]
    #Check if the sys.argv value is a switch
    if arg in allowed_switches:
        #Check if it doesn't have an accompanying argument (i.e. if it is followed by another switch, or if it is last
        #on the command line)
        if a == len(sys.argv) - 1 or argv[a + 1] in allowed_switches:
            sys.argv.insert(a + 1, "")

options, args = parser.parse_args()

#If the option is present (i.e. wasn't set to the default value)
if not (options.to_delete == PARSER_DEFAULTVAL):
    if options.droptables_ids_csv == "":
        #The switch was not used with any arguments.
        ...
    else:
        #The switch had arguments.
        ...
0 голосов
/ 29 июня 2010

Optparse уже позволяет передавать пустую строку в качестве аргумента опции. Поэтому, если возможно, обрабатывайте пустую строку как «без значения». Для длинных опций любая из следующих работ:

my_script --opt=   --anotheroption
my_script --opt='' --anotheroption
my_script --opt="" --anotheroption
my_script --opt '' --anotheroption
my_script --opt "" --anotheroption

Для коротких стилей вы можете использовать любой из:

my_script -o '' --anotheroption
my_script -o "" --anotheroption

Предостережение: это было протестировано в Linux и должно работать так же в других Unix-подобных системах; Windows по-разному обрабатывает кавычки командной строки и может не принять все перечисленные выше варианты.

0 голосов
/ 04 августа 2009

Да, есть аргумент для этого, когда вы добавляете параметр:

from optparse import OptionParser
parser = OptionParser()
parser.add_option("--SomeData",action="store", dest="TheData", default='')

Дайте аргументу default значение, которое вы хотите, чтобы опция имела, должно быть указано, но необязательно иметь аргумент.

...