Python的argh库:在帮助信息中保留文档字符串格式
在我寻找更快的方式来解析命令行参数时,我发现了一个叫做 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 个回答
关于在帮助信息中显示默认值的问题,这段 argparse
脚本结合了两种格式化类。
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)
为了在帮助信息中显示默认值,我需要在原始帮助信息中加入一些文字(这里是'test')。
在 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')
感谢你对Argh库的关注。这里讨论的解决方案会在下一个版本中加入(argh ≥ 0.25)。你也可以查看一下第64个问题(已经修复了)。
在@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)
最终在执行脚本时使用-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 (default: 1)
-b, --bar (default: True)
我对 argh
不是很熟悉,但听说它是 argparse
的一个封装工具。我的猜测是,它会把你的函数的文档字符串 __doc__
作为解析器的 description
,比如:
parser = argparse.ArgumentParser(description=func.__doc__)
https://docs.python.org/2.7/library/argparse.html#argparse.RawDescriptionHelpFormatter
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)