代码之家  ›  专栏  ›  技术社区  ›  Miro Samek

如何在没有副作用的情况下执行外部python脚本?

  •  0
  • Miro Samek  · 技术社区  · 8 年前

    我正在尝试用Python3构建一个简单的DSL(领域特定语言),用于一种特殊的测试。DSL基础设施将定义一些用于测试的命令,然后它将运行根据这些命令编写的外部Python脚本,但也可能包含任何其他有效的Python。

    第一个问题是独立运行外部脚本,当脚本在循环中执行时,不会从一个脚本累积到另一个脚本的副作用。

    第二个问题是执行功能(例如。, on_setup() )在外部脚本本身中定义。这些功能需要在DSL解释器级别执行。

    下面是测试框架的框架代码(“cutest.py”):

    # DSL command
    def test(title):
        print("test:", title)
        try:
            on_setup() # function from the current test
        except:
            print("on_setup() not found")
    
    # DSL command
    def expect(str):
        print("expect:", str)
    
    # other DSL commands...
    
    def main():
        import glob
        scripts = glob.glob("test*.py")
        for fname in scripts:
            print("*******", fname)
            try:
                exec(open(fname).read(), globals())
            except:
                print("errors in script:", fname)
    
    if __name__ == "__main__":
        main()
    

    下面是“test_1.py”脚本:

    def on_setup():
        print("test_1.py:on_setup")
    
    test("My first test")
    expect("foo")
    

    最后,这里是“test_2.py”脚本:

    test("My second test")
    expect("bar")
    

    请注意,“test_2.py”是 不 定义其 关于_setup() 作用

    现在,当我跑的时候 python cutest.py 在目录中 test_1.py 和 test_2.py ,我得到以下输出:

    ******* test_1.py
    test: My first test
    test_1.py:on_setup
    expect: foo
    ******* test_2.py
    test: My second test
    test_1.py:on_setup
    expect: bar
    

    问题是 测试2。py 显示“test_1.py:on_setup”(运行的副作用) 测试1。py ,而它应该显示“on_setup()not found”,因为 关于_setup() 未在中定义 测试2。py .

    在我的框架代码“cutest.py”中,我使用了Python exec(.., globals()) 打电话,但也许这些问题可以通过 __import__() 或者其他机制。

    1 回复  |  直到 8 年前
        1
  •  0
  •   Miro Samek    8 年前

    我找到了一种可以接受的方法来让它工作,我想知道Python大师对它的看法。

    下面是经过修改的“DSL解释器”代码(“cutest.py”):

    # DSL command
    def test(title):
        print("test:", title)
        global glb_dict
        try:
            glb_dict['on_setup']() # function from the current test
        except:
            print("on_setup() not found")
    
    # DSL command
    def expect(str):
        print("expect:", str)
    
    # other DSL commands...
    
    def main():
        import glob
        scripts = glob.glob("test*.py")
        global glb_dict
        for fname in scripts:
            glb_dict = {
                "test": test,
                "expect": expect
                # other commands...
            }
            print("*******", fname)
            try:
                exec(open(fname).read(), glb_dict)
            except:
                print("errors in script:", fname)
    
    if __name__ == "__main__":
        main()
    

    第一个变化是使用全球词典 glb_dict 而不是 globals() 这个 glb_dict 为每个测试脚本初始化字典,以便从上一次运行中删除任何副作用。

    第二个变化是调用特定于测试的 on_setup() 函数,现在从 glb_dict 字典,像这样: glb_dict['on_setup']() .

    修改后的 cutest.py 代码执行相同的两个测试脚本,如下所示:

    蟒蛇最可爱。py

    ******* test_1.py
    test: My first test
    test_1.py:on_setup
    expect: foo
    ******* test_2.py
    test: My second test
    on_setup() not found
    expect: bar
    

    具体来说:(1)它找到了“test_1.py:on_setup”函数;(2)它没有在test_2中找到“on_setup”函数。py(因为它不存在)。