问题描述
我正在尝试从子流程中获取异常。如果我使用.communicate
,我可以得到它,但是我想避免使用它,因为我正在从子流程中流式传输输出,并且不想等到整个子流程完成。还要假设整个子流程可能花费很长时间。想知道如何在从子流程中流式输出stdout时捕获引发的异常。
考虑下面的示例,所以我想让版本1工作,版本2可以工作,但是不要那样。
在main.py
import subprocess
class ExtProcess():
def __init__(self,*args):
self.proc = subprocess.Popen(['python',*args],stdout=subprocess.PIPE)
def __iter__(self):
return self
def __next__(self):
while True:
line = self.proc.stdout.readline()
if self.proc.returncode:
raise Exception("error here")
if not line:
raise stopiteration
return line
def run():
## version #1
reader = ExtProcess("sample_extproc.py")
for d in reader:
print(f"got: {d}")
## version #2
# proc = subprocess.Popen(['python',"sample_extproc.py"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
# output,error = proc.communicate()
# print("got:",output)
# if proc.returncode:
# raise Exception(error)
def main():
try:
print("start...")
run()
print("complete...")
except Exception as e:
print(f"Package midstream error here: {str(e)}")
finally:
print("clean up...")
if __name__ == "__main__":
main()
在sample_extproc.py
中for x in range(10):
print(x)
if x == 3:
raise RuntimeError("catch me")
start...
got: b'0\r\n'
got: b'1\r\n'
got: b'2\r\n'
got: b'3\r\n'
Package midstream error here: b'Traceback (most recent call last):\r\n File "sample_extproc.py",line 4,in <module>\r\n raise RuntimeError("catch me")\r\nRuntimeError: catch me\r\n'
clean up...
基本上,它会迭代子流程中的stdout,然后在发生异常时打印异常,然后继续执行清理。
解决方法
以下是我对以下问题的答案,它确实基于@CharlesDuffy的评论:
简而言之,请确保stderr=subprocess.PIPE
类中有ExtProcess
,然后答案在版本3中,在迭代标准输出之后,我们使用.wait()
和{{1 }}检查是否存在错误,如果出现错误,则引发异常,从returncode
抓取错误以捕获到父/主中。
stderr.read()