轻松捕获当前进程及其子进程的stdout和stderr
项目描述
capturer软件包使得捕获当前进程及其子进程的stdout和stderr流变得非常容易。输出可以实时发送到终端,同时也可以供Python程序进行进一步处理。目前已在cPython 2.7、3.5+和PyPy(2.7)上进行了测试。它在Linux和Mac OS X上进行了测试,可能在其他Unix系统上也能工作,但在Windows上肯定不行(因为使用了平台相关的pty模块)。有关使用说明,请参阅文档。
状态
《捕捉器》包是在周末开发的一个概念验证,因为我很好奇它是否能可靠地完成。经过周末的大量测试,它似乎工作得相当好,所以我将其作为版本1.0发布初始版本。然而,我仍然认为这是一个概念验证,因为我还没有用它进行广泛的“生产”经验。希望它在实际应用中也能像测试期间那样工作得好 :-)。
安装
《捕捉器》包可在PyPI上找到,这意味着安装应该和以下一样简单:
$ pip install capturer
安装Python包实际上有无数种方法(例如,例如按用户站点包目录,虚拟环境或仅全局安装)我没有意图在这里深入讨论这个问题,所以如果你感到害怕,在返回这些说明之前先了解你的选项 ;-)。
入门
捕获输出的最简单方法是使用上下文管理器
import subprocess
from capturer import CaptureOutput
with CaptureOutput() as capturer:
# Generate some output from Python.
print "Output from Python"
# Generate output from a subprocess.
subprocess.call(["echo", "Output from a subprocess"])
# Get the output in each of the supported formats.
assert capturer.get_bytes() == b'Output from Python\r\nOutput from a subprocess\r\n'
assert capturer.get_lines() == [u'Output from Python', u'Output from a subprocess']
assert capturer.get_text() == u'Output from Python\nOutput from a subprocess'
上下文管理器(with语句)确保在适当的时间启用和禁用输出捕获,无论是否发生异常中断正常处理流程。
请注意,第一次调用get_bytes(),get_lines()或get_text()将默认停止捕获输出。这被设计为合理的默认值,以防止部分读取(在没有经验的情况下,这可能会让人非常困惑)。因此,我们只需使用print来显示结果,而不会导致递归的“捕获输出被打印并被再次捕获”循环。可以使用可选的partial=True关键字参数来禁用此行为(请参阅文档以获取详细信息)。
设计选择
已经有现成的方法可以捕获(Python)进程的stdout和stderr流。创建《捕捉器》包是为了满足一个非常具体的用例,而现有的解决方案(我能找到的)并没有解决这个用例。本节记录了指导《捕捉器》包开发的决策设计
拦截低级文件描述符的写入
像capture和iocapture这样的库将Python的sys.stdout和sys.stderr文件对象更改为模拟文件对象(使用StringIO)。这使得可以从同一Python进程捕获(大多数)写入stdout和stderr流的输出,但是子进程的任何输出都不会受到影响,也不会被捕获。
相反,《捕捉器》包拦截对低级文件描述符的写入(类似于并受到pytest如何做的启发)。这使得可以捕获同一Python进程以及任何子进程写入标准输出和错误流的输出。
使用伪终端来模拟真实终端
《 capturer》 包使用通过 pty.openpty() 创建的伪终端来捕获输出。这意味着子进程会使用 ANSI 转义序列,因为它们认为自己连接到了一个终端。在当前实现中,您无法选择退出此功能,但欢迎提交功能请求来更改此功能:-)。这确实有一些缺点。
使用 pty.openpty() 意味着您需要在类似 UNIX 的环境中运行才能使 capturer 工作(Windows 明确不支持)。
默认情况下,所有捕获的输出都通过 stderr 流中继,因此捕获改变了您程序的含义。这有多重要显然取决于您的使用场景。对于触发我创建 capturer 的使用场景来说,这并不重要,这就是为什么它是默认模式的原因。
存在对分别捕获 stdout 和 stderr 并将捕获的输出中继到适当原始流的实验性支持。基本上,您调用 CaptureOutput(merged=False),然后使用 CaptureOutput 对象的 stdout 和 stderr 属性来访问每个流上捕获的输出。
我说实验性,因为这种捕获方式可能会无意中改变捕获输出发出的顺序,以避免在 stdout 和 stderr 流上交错输出(这很可能会导致难以理解的输出)。基本上,输出在每行后分别中继到每个流上。这意味着不会显示在读取标准输入时阻塞且不发出换行符的交互式提示(直到为时已晚 ;-)。
继电器实时输出到端子
《 capturer》 的主要用途是捕获 Python 代码片段的所有输出(包括子进程的任何输出),但同时也将输出实时中继到终端。这有几个有用的特性
接触
《 capturer》 的最新版本可在 PyPI 和 GitHub 上获得。文档托管在 Read the Docs 上,包括 变更日志。有关错误报告,请在 GitHub 上创建问题。如果您有任何疑问、建议等,请随时通过电子邮件发送给我 peter@peterodding.com。
许可证
本软件根据 MIT 许可证 许可。
© 2020 Peter Odding。
衷心感谢pytest的开发者,因为pytest捕获子进程输出的机制为capturer包的设计提供了灵感。没有复制任何代码,但两个项目都是MIT许可,所以这并不重要 :-).
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。