我已经编写了以下示例代码来演示我的问题。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--version', action='version',
version='%(prog)s 1.0')
parser.parse_args()
这会产生以下帮助信息。
$ python foo.py --help
usage: foo.py [-h] [-v]
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
我想自定义此帮助输出,以便将所有短语和句子大写,并将句点放在句子之后。换句话说,我希望像这样生成帮助消息。
$ python foo.py --help
Usage: foo.py [-h] [-v]
Optional arguments:
-h, --help Show this help message and exit.
-v, --version Show program's version number and exit.
这是我可以使用argparse API控制的东西。如果是这样,怎么样?能否请您提供一个小例子,说明如何做到这一点?
答案 0 :(得分:28)
首先:将这些短语大写在常规面前,并且argparse
并不真正能够帮助您轻松更改这些字符串。这里有三个不同类别的字符串:来自帮助格式化程序的样板文本,部分标题和每个特定选项的帮助文本。所有这些字符串都可以本地化;您可以通过gettext()
module support为所有这些字符串提供“大写”翻译。也就是说,如果你足够坚定并read the source code a little,你可以进入并替换所有这些字符串。
version
操作包含默认的help
文本,但您可以通过设置help
参数来提供自己的文本。这同样适用于help
行动;如果您将add_help
argument设置为False
,则可以手动添加该操作:
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-v', '--version', action='version',
version='%(prog)s 1.0', help="Show program's version number and exit.")
parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS,
help='Show this help message and exit.')
接下来,optional arguments
消息是组标题;每个解析器都有两个默认组,一个用于位置参数,另一个用于可选。您可以通过_positionals
和_optionals
属性来访问这些属性,这两个属性都具有title
属性:
parser._positionals.title = 'Positional arguments'
parser._optionals.title = 'Optional arguments'
警告,通过访问以下划线开头的名称,您将冒险进入模块的未记录的私有API,并且您的代码可能会在将来的更新中中断。
最后,要更改usage
字符串,您必须继承帮助格式化程序;将子类作为formatter_class
argument传递:
class CapitalisedHelpFormatter(argparse.HelpFormatter):
def add_usage(self, usage, actions, groups, prefix=None):
if prefix is None:
prefix = 'Usage: '
return super(CapitalisedHelpFormatter, self).add_usage(
usage, actions, groups, prefix)
parser = argparse.ArgumentParser(formatter_class=CapitalisedHelpFormatter)
演示,将这些全部放在一起:
>>> import argparse
>>> class CapitalisedHelpFormatter(argparse.HelpFormatter):
... def add_usage(self, usage, actions, groups, prefix=None):
... if prefix is None:
... prefix = 'Usage: '
... return super(CapitalisedHelpFormatter, self).add_usage(
... usage, actions, groups, prefix)
...
>>> parser = argparse.ArgumentParser(add_help=False, formatter_class=CapitalisedHelpFormatter)
>>> parser._positionals.title = 'Positional arguments'
>>> parser._optionals.title = 'Optional arguments'
>>> parser.add_argument('-v', '--version', action='version',
... version='%(prog)s 1.0', help="Show program's version number and exit.")
_VersionAction(option_strings=['-v', '--version'], dest='version', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help="Show program's version number and exit.", metavar=None)
>>> parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS,
... help='Show this help message and exit.')
_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='Show this help message and exit.', metavar=None)
>>> print(parser.format_help())
Usage: [-v] [-h]
Optional arguments:
-v, --version Show program's version number and exit.
-h, --help Show this help message and exit.
答案 1 :(得分:3)
Martijn提供了一些想到的修复 - 提供help
参数和自定义Formatter类。
另一个部分修复是在创建参数后修改帮助字符串。 add_argument
创建并返回包含参数和默认值的Action
对象。您可以保存链接,并修改Action
。您还可以获取这些操作的列表,并对其采取相应措施。
让我举例说明,对于一个带有默认帮助和另一个参数的简单解析器,操作列表是:
In [1064]: parser._actions
Out[1064]:
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
_StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]
我可以查看和修改其中任何一个的help
属性:
In [1065]: parser._actions[0].help
Out[1065]: 'show this help message and exit'
In [1066]: parser._actions[0].help='Show this help message and exit.'
产生这个帮助:
In [1067]: parser.parse_args(['-h'])
usage: ipython3 [-h] [-f FOO]
optional arguments:
-h, --help Show this help message and exit.
-f FOO, --foo FOO
使用parser._actions
列表会使用'私有'属性,有些人认为是不明智的。但在Python中,公共/私人的区别并不严格,可以小心打破。 Martijn通过访问parser._positionals.title
来做到这一点。
更改该组标题的另一种方法是使用自定义参数组
ogroup=parser.add_argument_group('Correct Optionals Title')
ogroup.add_argument('-v',...)
ogroup.add_argument('-h',...)
答案 2 :(得分:3)
编辑:如果此后对此进行了重大扩展,并将继续在GitHub上进行。为了保持一致,我将在此处保留我的答案。
这不是依赖于内部API(如有更改,恕不另行通知),这是仅使用公共API的替代方法。可以说它比较复杂,但是反过来,您可以最大程度地控制打印内容:
class ArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(ArgumentParser, self).__init__(*args, **kwargs)
self.program = { key: kwargs[key] for key in kwargs }
self.options = []
def add_argument(self, *args, **kwargs):
super(ArgumentParser, self).add_argument(*args, **kwargs)
option = {}
option["flags"] = [ item for item in args ]
for key in kwargs:
option[key] = kwargs[key]
self.options.append(option)
def print_help(self):
# use self.program/self.options to produce custom help text
工作原理:
argparse.ArgumentParser
的构造函数以捕获和存储程序信息(例如,描述,用法)argparse.ArgumentParser.add_argument()
以捕获和存储添加的参数(例如标志,帮助,默认值)argparse.ArgumentParser.print_help()
并使用先前存储的程序信息/参数生成帮助文本这是一个涵盖一些常见用例的完整示例。请注意,它绝不是完整的(例如,不支持位置参数或具有多个参数的选项),但是应该给人一种可能的印象:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import argparse
import textwrap
class ArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(ArgumentParser, self).__init__(*args, **kwargs)
self.program = { key: kwargs[key] for key in kwargs }
self.options = []
def add_argument(self, *args, **kwargs):
super(ArgumentParser, self).add_argument(*args, **kwargs)
option = {}
option["flags"] = [ item for item in args ]
for key in kwargs:
option[key] = kwargs[key]
self.options.append(option)
def print_help(self):
wrapper = textwrap.TextWrapper(width=80)
# Print usage
if "usage" in self.program:
print("Usage: %s" % self.program["usage"])
else:
usage = []
for option in self.options:
usage += [ "[%s %s]" % (item, option["metavar"]) if "metavar" in option else "[%s %s]" % (item, option["dest"].upper()) if "dest" in option else "[%s]" % item for item in option["flags"] ]
wrapper.initial_indent = "Usage: %s " % os.path.basename(sys.argv[0])
wrapper.subsequent_indent = len(wrapper.initial_indent) * " "
output = str.join(" ", usage)
output = wrapper.fill(output)
print(output)
print()
# Print description
if "description" in self.program:
print(self.program["description"])
print()
# Print options
print("Options:")
maxlen = 0
for option in self.options:
option["flags2"] = str.join(", ", [ "%s %s" % (item, option["metavar"]) if "metavar" in option else "%s %s" % (item, option["dest"].upper()) if "dest" in option else item for item in option["flags"] ])
if len(option["flags2"]) > maxlen:
maxlen = len(option["flags2"])
for option in self.options:
template = " %-" + str(maxlen) + "s "
wrapper.initial_indent = template % option["flags2"]
wrapper.subsequent_indent = len(wrapper.initial_indent) * " "
if "help" in option and "default" in option:
output = option["help"]
output += " (default: '%s')" % option["default"] if isinstance(option["default"], str) else " (default: %s)" % str(option["default"])
output = wrapper.fill(output)
elif "help" in option:
output = option["help"]
output = wrapper.fill(output)
elif "default" in option:
output = "Default: '%s'" % option["default"] if isinstance(option["default"], str) else "Default: %s" % str(option["default"])
output = wrapper.fill(output)
else:
output = wrapper.initial_indent
print(output)
# Main
if (__name__ == "__main__"):
#parser = argparse.ArgumentParser(description="Download program based on some library.", argument_default=argparse.SUPPRESS, allow_abbrev=False, add_help=False)
#parser = argparse.ArgumentParser(usage="%s [OPTION]..." % os.path.basename(sys.argv[0]), description="Download program based on some library.", argument_default=argparse.SUPPRESS, allow_abbrev=False, add_help=False)
#parser = ArgumentParser(usage="%s [OPTION]..." % os.path.basename(sys.argv[0]), description="Download program based on some library.", argument_default=argparse.SUPPRESS, allow_abbrev=False, add_help=False)
parser = ArgumentParser(description="Download program based on some library.", argument_default=argparse.SUPPRESS, allow_abbrev=False, add_help=False)
parser.add_argument("-c", "--config-file", action="store", dest="config_file", metavar="file", type=str, default="config.ini")
parser.add_argument("-d", "--database-file", action="store", dest="database_file", metavar="file", type=str, help="SQLite3 database file to read/write", default="database.db")
parser.add_argument("-l", "--log-file", action="store", dest="log_file", metavar="file", type=str, help="File to write log to", default="debug.log")
parser.add_argument("-f", "--data-file", action="store", dest="data_file", metavar="file", type=str, help="Data file to read", default="data.bin")
parser.add_argument("-t", "--threads", action="store", dest="threads", type=int, help="Number of threads to spawn", default=3)
parser.add_argument("-p", "--port", action="store", dest="port", type=int, help="TCP port to listen on for access to the web interface", default="12345")
parser.add_argument("--max-downloads", action="store", dest="max_downloads", metavar="value", type=int, help="Maximum number of concurrent downloads", default=5)
parser.add_argument("--download-timeout", action="store", dest="download_timeout", metavar="value", type=int, help="Download timeout in seconds", default=120)
parser.add_argument("--max-requests", action="store", dest="max_requests", metavar="value", type=int, help="Maximum number of concurrent requests", default=10)
parser.add_argument("--request-timeout", action="store", dest="request_timeout", metavar="value", type=int, help="Request timeout in seconds", default=60)
parser.add_argument("--main-interval", action="store", dest="main_interval", metavar="value", type=int, help="Main loop interval in seconds", default=60)
parser.add_argument("--thread-interval", action="store", dest="thread_interval", metavar="value", type=int, help="Thread loop interval in milliseconds", default=500)
parser.add_argument("--console-output", action="store", dest="console_output", metavar="value", type=str.lower, choices=["stdout", "stderr"], help="Output to use for console", default="stdout")
parser.add_argument("--console-level", action="store", dest="console_level", metavar="value", type=str.lower, choices=["debug", "info", "warning", "error", "critical"], help="Log level to use for console", default="info")
parser.add_argument("--logfile-level", action="store", dest="logfile_level", metavar="value", type=str.lower, choices=["debug", "info", "warning", "error", "critical"], help="Log level to use for log file", default="info")
parser.add_argument("--console-color", action="store", dest="console_color", metavar="value", type=bool, help="Colorized console output", default=True)
parser.add_argument("--logfile-color", action="store", dest="logfile_color", metavar="value", type=bool, help="Colorized log file output", default=False)
parser.add_argument("--log-template", action="store", dest="log_template", metavar="value", type=str, help="Template to use for log lines", default="[%(created)d] [%(threadName)s] [%(levelname)s] %(message)s")
parser.add_argument("-h", "--help", action="help", help="Display this message")
args = parser.parse_args(["-h"])
产生的输出:
Usage: argparse_custom_usage.py [-c file] [--config-file file] [-d file]
[--database-file file] [-l file] [--log-file
file] [-f file] [--data-file file] [-t THREADS]
[--threads THREADS] [-p PORT] [--port PORT]
[--max-downloads value] [--download-timeout
value] [--max-requests value] [--request-timeout
value] [--main-interval value] [--thread-
interval value] [--console-output value]
[--console-level value] [--logfile-level value]
[--console-color value] [--logfile-color value]
[--log-template value] [-h] [--help]
Download program based on some library.
Options:
-c file, --config-file file Default: 'config.ini'
-d file, --database-file file SQLite3 database file to read/write (default:
'database.db')
-l file, --log-file file File to write log to (default: 'debug.log')
-f file, --data-file file Data file to read (default: 'data.bin')
-t THREADS, --threads THREADS Number of threads to spawn (default: 3)
-p PORT, --port PORT TCP port to listen on for access to the web
interface (default: '12345')
--max-downloads value Maximum number of concurrent downloads
(default: 5)
--download-timeout value Download timeout in seconds (default: 120)
--max-requests value Maximum number of concurrent requests (default:
10)
--request-timeout value Request timeout in seconds (default: 60)
--main-interval value Main loop interval in seconds (default: 60)
--thread-interval value Thread loop interval in milliseconds (default:
500)
--console-output value Output to use for console (default: 'stdout')
--console-level value Log level to use for console (default: 'info')
--logfile-level value Log level to use for log file (default: 'info')
--console-color value Colorized console output (default: True)
--logfile-color value Colorized log file output (default: False)
--log-template value Template to use for log lines (default:
'[%(created)d] [%(threadName)s] [%(levelname)s]
%(message)s')
-h, --help Display this message