Замена sys.argv на docopt
Я работаю над включением некоторых замен строк, и в настоящее время аргументы передаются в мой скрипт с помощью sys.argv[i]
, Я хотел бы заменить sys на docopt, но я до сих пор нашел документацию относительно непонятной.
Мой код работает в настоящее время
filename.py -param_to_replace new_param_value
(Я также могу включить несколько параметров для замены)
Это затем обрабатывается
if len(sys.argv) > 1:
for i in range((len(sys.argv)-1) / 2):
params[sys.argv[1+2*i].split('-')[1]] = float(sys.argv[1+2*i+1])
где params - это имя набора определенных параметров.
Я думаю, что смогу заставить это работать с docopt, но пока то, что у меня есть, больше похоже
"""Docopt test
Usage:
filename.py --param_name1 <val> --param_name2 <val>
filename -h | --help
filename --version
Options:
-h --help Show this screen.
--param_name1 Change some param we call param_name1, all other params changed in similar way
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='filename 1.0')
print(arguments)
Но это ничего не значит и похоже на конец деталей, представленных в официальной документации. Кто-нибудь, кто лучше знаком с docopt, знает, как более эффективно передавать аргументы командной строки? Или после этого заменить sys.argv на "аргументы"?
Спасибо!
4 ответа
Поэтому я подумал, что вернусь к этому, поскольку понял, что никогда не закрывал тему и не публиковал ответ. Правильный способ передачи аргументов приведен ниже:
"""Usage: filename.py [--arg1=N] [--arg2=N]
Options:
--arg1=N passes arg1
--arg2=N passes arg2
"""
from docopt import docopt
arguments = docopt(__doc__,version='')
print arguments[--arg1] #This is to print any argument or pass it through
Кажется, была только некоторая проблема с использованием, которая прояснена в коде здесь.
Я только что понял, что __doc__
делает (см. мои комментарии).
Когда модуль загружен, начальная строка в тройных кавычках присваивается его __doc__
переменная. Обычно это документация, которую могут использовать различные "справочные" пакеты. Функции и классы также имеют __doc__
, За docopt
использовать это должно моделировать help
отображение анализатора командной строки.
arguments = docopt(__doc__, version='filename 1.0')
линия проходит это__doc__
строка в docopt
функция (или класс). Это выводит, какие аргументы вы хотите принять, анализирует sys.argv
и возвращает словарь, arguments
,
В вашем примере строка использования:
filename.py --param_name1 <val> --param_name2 <val>
Я ожидаю, что если бы вы вызвали скрипт с
filename.py --param_name1 foo --param_name2 bar
тот arguments
будет словарь, который выглядит так:
{'param_name1':'foo', 'param_name2':'bar'}
а также arguments['param_name1']
должен вернуть 'Foo'
Ваш текущий код, по-видимому, пытается проанализировать ввод, как
filename.py -foo 2.323 -xxx 1.23
и выполнять
params['foo'] = 2.323
params['xxx'] = 1.23
Я ожидаю, что docopt
Версия выдаст ошибку с этим вводом, но я не знаю деталей того, насколько хорошо он обрабатывает ошибки.
Лучшее решение, чем если бы __name__ == '__main__' дважды в скрипте Python - более длинный пример использования python
docopt
,
версия argparse
Вот argparse
сценарий, который ведет себя, я думаю, как ваш sys.argv
разбор. Он определяет набор argparse
записи на основе аргументов в params
словарь и должен возвращать совместимый словарь.
import argparse
params = {'foo':None, 'bar':None, 'test':0}
parser = argparse.ArgumentParser()
for key in params:
name = '--'+key
default = params[key]
if default is None:
parser.add_argument(name)
else:
# could be more elaborate on setting type
parser.add_argument(name, default=default, type=float)
parser.print_help()
print(params)
print(vars(parser.parse_args([]))) # no arguments, should == params
args = parser.parse_args() # test the sys.argv
print(args) # namespace
print(vars(args)) # dictionary equivalent
производство:
1033:~/mypy$ python stack34956253.py --foo 124 --test 323.3
usage: stack34956253.py [-h] [--test TEST] [--foo FOO] [--bar BAR]
optional arguments:
-h, --help show this help message and exit
--test TEST
--foo FOO
--bar BAR
{'test': 0, 'foo': None, 'bar': None}
{'test': 0, 'foo': None, 'bar': None}
Namespace(bar=None, foo='124', test=323.3)
{'test': 323.3, 'foo': '124', 'bar': None}
Это может работать так же:
argparse_help = parser.format_help()
arguments = docopt(argparse_help, version='filename 1.0')
Вместо того, чтобы использовать docopt
(что в любом случае замечательно), если вы просто хотите создать -param
: value
как бы вернулся docopt, вы можете сделать это с помощью словарного понимания (я думаю, более понятным способом, чем то, что вы делаете в настоящее время):
if __name__ == '__main__':
if len(sys.argv) > 1:
args = sys.argv[1:]
assert len(args) % 2 == 0
arguments = {args[i][1:]: args[i+1] for i in range(0, len(args), 2)}
print(arguments)
Тогда проверьте это:
In [12]: runfile(
'test.py', wdir='/home/mgc',
args='-param_to_replace1 new_value1 -param_to_replace2 new_param_valu2')
{'param_to_replace2': 'new_param_valu2', 'param_to_replace1': 'new_value1'}
Похоже, у вас проблемы с вашей грамматикой докопта. Для меня это помогает разработать грамматику docopt с помощью инструмента web docopt. Установка позволяет легко выполнить итерацию по грамматике и посмотреть, будет ли она создавать структуру, полезную для моей программы.
Я положил вашу грамматику здесь с аргументами --param_name1 foo --param_name2 bar
и получил этот результат:
{
"--param_name1": "foo",
"--param_name2": true,
"<val>": "bar"
}
В первой части вы указали: Usage: filename.py --param_name1 <val> --param_name2 <val>
, Обратите внимание, что вы использовали <val>
в 2 разных позициях, что означает, что заполняется только 2-е значение. Во второй части вы снова указали: Options: --param_name1
, который является избыточным, потому что вы уже указали тот же --param_name1
в разделе использования. Аргумент должен быть в одном, но не в обоих разделах.
Вот упрощенная грамматика:
Usage:
filename --old=<old> --new=<new>
Результат разбора с --old=foo --new=bar
является:
{
"--new": "bar",
"--old": "foo"
}
Или вообще удалите имена переключателей и просто используйте позиционные аргументы. Это облегчает ожидание множества аргументов для того, что вы хотите заменить.
Usage:
filename <new> <old>...
С bar foo baz
аргументы, это проанализированная структура:
{
"<new>": "bar",
"<old>": [
"foo",
"baz"
]
}
Я только что написал в блоге о том, как сильно я люблю докопт, так что я надеюсь, что вы преодолели первоначальный барьер понимания.