【问题标题】:Run python program from another python program (with certain requirements)从另一个 python 程序运行 python 程序(有一定的要求)
【发布时间】:2012-07-06 14:29:20
【问题描述】:

假设我有两个 python 脚本 A.pyB.py。我正在寻找一种从 A 内部运行 B 的方法,即:

  1. B 认为它是 __main__(因此 B 中 if __name__=="__main__" 块中的代码将运行)
  2. B 实际上不是 __main__(因此它不会覆盖 sys.modules 中的 "__main__" 条目)
  3. B 中引发的异常传播到 A(即,可以使用 A 中的 except 子句捕获)。
  4. 如果未捕获这些异常,则会生成正确的回溯引用 B 中的行号。

我尝试了各种技术,但似乎没有一个能满足我的所有要求。

  • 使用子流程模块中的工具意味着 B 中的异常不会传播到 A。
  • execfile("B.py", {}) 运行 B,但它认为它不是主要的。
  • execfile("B.py", {'__name__': '__main__'}) 使 B.py 认为它是主要的,但它似乎也搞砸了异常回溯打印,因此回溯引用 A 中的行(即真正的 __main__)。
  • 使用imp.load_source__main__ 作为名称几乎可以工作,只是它实际上修改了 sys.modules,因此踩踏了__main__ 的现有值

有什么方法可以得到我想要的吗?

(我这样做的原因是因为我正在对现有库进行一些清理。这个库没有真正的测试套件,只有一组产生特定输出的“示例”脚本。我正在尝试利用这些作为测试来确保我的清理不会影响库执行这些示例的能力,所以我想从我的测试套件中运行每个示例脚本。我希望能够在测试脚本,这样测试脚本就可以报告失败的类型,而不仅仅是在示例脚本引发一些异常时报告通用的 SubprocessError。)

【问题讨论】:

    标签: python subprocess python-import execfile


    【解决方案1】:

    您的用例是有道理的,但我仍然认为您最好重构测试以便它们可以在外部运行。

    你的测试脚本有这样的东西吗?

    def test():
        pass
    
    if __name__ == '__main__':
        test()
    

    如果没有,也许您应该将您的测试转换为调用诸如test 之类的函数。然后,从您的主测试脚本中,您可以:

    import test1
    test1.test()
    import test2
    test2.test()
    

    为运行测试提供一个通用接口,测试本身使用该接口。在__main__ 检查中有一大块代码不是一件好事。

    很抱歉我没有回答你提出的问题,但我觉得这是正确的解决方案,而不会偏离原始测试代码

    【讨论】:

    • 很遗憾没有。一些测试脚本会这样做,但其他的只是将代码作为顶级模块代码。这只是奇怪案例的混合。我找出了问题并回答了我自己的问题,但感谢您的建议。我希望我能跟随它! :-)
    【解决方案2】:

    回答我自己的问题,因为结果很有趣,可能对其他人有用:

    事实证明我错了:execfile("B.py", {'__name__': '__main__'} 毕竟是要走的路。它确实正确地产生了回溯。我看到的错误行号不是异常,而是警告。这些警告是使用warnings.warn("blah", stacklevel=2) 生成的。 stacklevel=2 参数应该允许在使用已弃用的东西的地方而不是在警告调用时引发诸如弃用警告之类的事情(请参阅the documentation)。

    然而,execfile-d 文件似乎不计入此目的的“堆栈级别”,并且对于stacklevel 目的而言是不可见的。因此,如果 execfile-d 模块顶层的代码导致堆栈级别为 2 的警告,则警告不会在 execfile-d 源文件的正确行号处引发;而是在运行 execfile 的文件的相应行号处引发。

    这很不幸,但我可以忍受,因为这些只是警告,所以它们不会影响测试的实际性能。 (一开始我并没有注意到只有警告受到行号不匹配的影响,因为在测试输出中混杂了很多警告和异常。)

    【讨论】:

    • 有趣的解决方案。我怀疑(并希望..)我曾经需要它,但是 python 允许和启用的东西有点酷。
    猜你喜欢
    • 2023-03-30
    • 2021-04-17
    • 2011-10-20
    • 2018-05-17
    • 2013-02-19
    • 2018-01-15
    • 2021-09-14
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多