我正在编写一个我想使用Setuptools分发的脚本。我已将此脚本添加到entry_points
。{/ p>中的setup.py
部分
从setuptools docs:
您指定的函数不带参数调用,并且它们的返回值传递给sys.exit(),因此您可以返回错误级别或消息以打印到stderr 。
由于该方法将返回而不是退出,因此它变得更加可测试。出于可测试性目的,我接受方法中的参数默认为sys.argv
。到目前为止一切都很好。
当将argparse添加到混合中时会出现问题。当argparse无法解析args时,它会调用sys.exit
。现在我真的更喜欢argparse没有这样做,因为这是由setuptools包装器处理的。我能想到的第一件事就是覆盖argparse.ArgumentParser
,但后来我看到了:
# ===============
# Exiting methods
# ===============
def exit(self, status=0, message=None):
if message:
self._print_message(message, _sys.stderr)
_sys.exit(status)
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
If you override this in a subclass, it should not return -- it
should either exit or raise an exception.
"""
self.print_usage(_sys.stderr)
self.exit(2, _('%s: error: %s\n') % (self.prog, message))
因此文档字符串指出我不应该返回并坚持提出异常。我该怎么解决这个问题?
如果我没有彻底解释它的主要方法:
def main(args=sys.argv):
parser = ArgumentParser(prog='spam')
# parser is configured here
parsed = parser.parse_args(args)
# Parsed args are used here
答案 0 :(得分:2)
您不希望来自return
error
的原因是解析器将继续解析。在结尾附近会产生一些错误(例如关于未解析的字符串),但其他错误可能会提前发生(例如第一个参数字符串的错误类型)。如果从error方法返回,则parse_args
的行为是不可预测的。通常,您希望解析器退出并返回对代码的控制。
您要做的是将parse_args()
调用包装在try: except SystemExit:
块中。我经常使用这样的测试脚本:
for test in ['-o FILE',
...
]:
print(test)
try:
print(parser.parse_args(test.split()))
except SystemExit:
pass
您可以使用error
和/或exit
返回其他类型的例外情况。他们还可以绕过使用信息。但是在某种程度上你需要在你的包装器中捕获异常。
答案 1 :(得分:0)
如果您正在开始一个新项目或有时间进行重构,那么您可以考虑使用Click库。点击同时包含setuptools integration和“testability”作为功能以及其他注意事项 - 这里是文档中的示例test-snippet,它们都创建了一个迷你命令行界面,然后立即对其进行测试:
import click
from click.testing import CliRunner
def test_hello_world():
@click.command()
@click.argument('name')
def hello(name):
click.echo('Hello %s!' % name)
runner = CliRunner()
result = runner.invoke(hello, ['Peter'])
assert result.exit_code == 0
assert result.output == 'Hello Peter!\n'