Архивная библиотека Python: сохранение форматирования документации в сообщении помощи
При поиске более быстрых способов разбора аргументов командной строки в моих скриптах я наткнулся на библиотеку argh.
Мне действительно нравятся функции argh, но я столкнулся с одним недостатком, который мешает мне его использовать, и это связано с сообщением справки по умолчанию, которое отображается, если я вызываю опцию —help: по умолчанию строка документации функции отображается в верхней части списка аргументов. Это здорово, однако первоначальное форматирование потеряно. Смотрите, например, следующий пример сценария
import argh
def func(foo=1, bar=True):
"""Sample function.
Parameters:
foo: float
An example argument.
bar: bool
Another argument.
"""
print foo, bar
argh.dispatch_command(func, argv=['-h'])
что приведет к следующему выводу
usage: script.py [-h] [-f FOO] [-b]
Sample function. Parameters: foo: float An example argument. bar: bool Another
argument.
optional arguments:
-h, --help show this help message and exit
-f FOO, --foo FOO
-b, --bar
Есть ли (простой) способ получить результат, подобный следующему?
usage: script.py [-h] [-f FOO] [-b]
Sample function.
Parameters:
foo: float
An example argument.
bar: bool
Another argument.
optional arguments:
-h, --help show this help message and exit
-f FOO, --foo FOO
-b, --bar
Я бы предпочел не использовать аннотации для определения сообщений справки по аргументам, так как это потребовало бы от меня изменять строку документации функции и текст справки каждый раз, когда есть что-то изменить.
4 ответа
Я не знаком с argh
но, видимо, это обертка argparse
, Я думаю, что это берет на себя вашу функцию __doc__
и делая это description
парсера, например
parser = argparse.ArgumentParser(description=func.__doc__)
https://docs.python.org/2.7/library/argparse.html
argparse
имеет RawDescriptionHelpFormatter
который отображает описание как есть.
parser = argparse.ArgumentParser(description=func.__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
Итак, вопрос в том, есть ли способ получить argh
использовать этот форматер?
это argparse
Скрипт выдает помощь, которую вы хотите:
import argparse
def func(foo=1, bar=True):
"""Sample function.
Parameters:
foo: float
An example argument.
bar: bool
Another argument.
"""
print foo, bar
parser = argparse.ArgumentParser(prog='script.py',
description=func.__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-f', '--foo', type=float)
parser.add_argument('-b', '--bar', action='store_false')
parser.print_help()
В argh/dispatching.py
def dispatch_command(function, *args, **kwargs):
...
parser = argparse.ArgumentParser(formatter_class=PARSER_FORMATTER)
set_default_command(parser, function)
dispatch(parser, *args, **kwargs)
Таким образом, вы можете установить:
PARSER_FORMATTER = argparse.RawDescriptionHelpFormatter
или напишите свою собственную функцию:
def raw_dispatch_command(function, *args, **kwargs):
...
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
set_default_command(parser, function)
dispatch(parser, *args, **kwargs)
С помощью @hpaulj мне наконец удалось получить желаемое поведение. Чтобы облегчить это, я определил пользовательский декоратор, похожий на argh.arg, с целью не писать @argh.arg(‘—param’, help=“%(default)s”)
для каждого параметра отдельно, но вместо этого использовать только один @arg_custom()
декоратор по моей функции:
def arg_custom():
from argh.constants import ATTR_ARGS
from argh.assembling import _get_args_from_signature, _fix_compat_issue29
def wrapper(func):
declared_args = getattr(func, ATTR_ARGS, [])
for a in list(_get_args_from_signature(func)):
declared_args.insert(0, dict(option_strings=a['option_strings'], help="(default: %(default)s)"))
setattr(func, ATTR_ARGS, declared_args)
_fix_compat_issue29(func)
return func
return wrapper
Важным моментом здесь является то, что for
цикл заботится о том, чтобы все аргументы получили соответствующие help=“%(default)s”
вариант. Вместе с изменением соответствующих строк в argh/constants.py
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
pass
PARSER_FORMATTER = CustomFormatter
теперь мы можем удобно использовать
@arg_custom()
def func(foo=1, bar=True):
"""Sample function.
Parameters:
foo: float
An example argument.
bar: bool
Another argument.
"""
print foo, bar
argh.dispatch_command(func)
уступая наконец
usage: script.py [-h] [-f FOO] [-b]
Sample function.
Parameters:
foo: float
An example argument.
bar: bool
Another argument.
optional arguments:
-h, --help show this help message and exit
-f FOO, --foo FOO (default: 1)
-b, --bar (default: True)
при выполнении сценария с -h
вариант.
Спасибо за ваш интерес к библиотеке Argh. Обсуждаемые здесь решения будут включены в следующий выпуск (argh ≥ 0,25). Смотрите также проблему № 64 (уже исправлена).
Что касается вопроса получения значений по умолчанию в справочных линиях, это argparse
скрипт объединяет 2 класса форматера
import argparse
def func(foo=1, bar=True):
...
"""
print foo, bar
class MyFormatter(argparse.RawDescriptionHelpFormatter,
argparse.ArgumentDefaultsHelpFormatter):
pass
parser = argparse.ArgumentParser(prog='script.py',
description=func.__doc__,
formatter_class=MyFormatter)
parser.add_argument('-f', '--foo', type=float, default=1, help='test')
parser.add_argument('-b', '--bar', action='store_false', help='test')
parser.print_help()
производства
usage: script.py [-h] [-f FOO] [-b]
Sample function.
...
optional arguments:
-h, --help show this help message and exit
-f FOO, --foo FOO test (default: 1)
-b, --bar test (default: True)
Чтобы получить значения по умолчанию в справочных строках, я должен включить некоторый текст (здесь "тест") в исходную справочную строку.
В argh
Возможно, вам придется использовать аннотации, чтобы дать ему текст справки.
Если вы используете аннотации, вы даете $(default)s
:
parser = argparse.ArgumentParser(prog='script.py',
description=func.__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-f', '--foo', type=float, default=1, help='default: %(default)s')
parser.add_argument('-b', '--bar', action='store_false', help='default: %(default)s')