从子进程

时间:2018-04-20 06:04:13

标签: python subprocess

我正在尝试从纯粹的stderr或拦截脚本并捕获其异常来获取python堆栈跟踪和错误的属性。无论哪种方式都没关系。这可能是一个XY问题,因此欢迎替代方案。

我目前正在编写一个程序,重定向参数以调用另一个python脚本:

import sys, subprocess
pyargs = sys.argv[1:] # Suppose pyargs is something like ["a.py", "123"]
result = subprocess.run(["python"] + pyargs, stdout=subprocess.PIPE, 
    stderr=subprocess.PIPE)
error = result.stderr # do something with this

方法1:解析转储

我不确定是否有任何现有方法支持这两个计划中的任何一个。我知道python错误转储以非常公式化的方式显示:

import sys, traceback
exc_type, exc_value, exc_traceback = sys.exc_info() # shows formatting
traceback.print_exc() # prints the stderr of what we wanted.

所以我想也许我们可以解析stderr并看看会发生什么。

方法2:捕捉异常

我知道我们可以使用subprocess.run(..., check=True)运行子进程来获取subprocess.SubprocessError,但由于子进程可以是任何东西(不仅仅是python进程),我们实际上无法拦截发生了实际的异常。

将python文件作为模块加载到此文件中的一个问题是我们无法提供必要的参数,除非我们能以某种方式欺骗从底层脚本运行的sys.argv[]argparse 。可能有if __name__ == "__main__":的脚本也不会执行,除非我们也这样做。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

我更喜欢方法#2。我尽可能避免使用subprocesssystem从Python调用Python。

更改sys.argv的值很简单 - 您只需使用常规分配覆盖它。

欺骗__name__ == "__main__"条件更难。不幸的是,这可能意味着您无法以通常的方式导入模块。根据{{​​3}},您可以使用runpy模块执行您的模块并提供您喜欢的任何__name__值。

import runpy
import sys
sys.argv = ["C:/", "foo", "bar"]
try:
    runpy.run_module("yourmodulename", {}, "__main__")
except Exception as e:
    print("caught exception:", e)

现在您可以捕获模块抛出的任何未捕获的异常,并在except内按照您的喜好处理它们。