P.G.
P.G.

Reputation: 653

Scope in functions defined in code executed with exec()

I have a simple test bench implemented in python.

The test runner exposes a set of functions to the test. This may be considered as a domain specific language for writing tests. Most test cases form simple sequences of calls to these functions, sometimes involving control flow statements, but nothing more complicated than that.

Now a few test cases have become too complex and would benefit from being refactored using functions. This is where I run into problems. From within the functions I cannot access local symbols defined inside the test case. I can also not access the functions exposed by the runner (log and verify).

''' Testing variable scopes in exec()'''

PRG_1 = '''
a = 42
log('Testing a = ' + str(a))
verify(a, 42)
'''

PRG_2 = '''
a = 42
def f():
    c = a  # Error 'a' not defined
    log(c) # Error 'log' not defined

f()
'''

class TestRunner():
    def __init__(self, prg):
        self.prg = prg

    def log(self, msg):
        print(msg)

    def verify(self, a, b):
        print('PASSED' if a == b else 'FAILED')

    def run(self):
        # Bring methods into local scope to avoid having 'self.' in DSL
        log = self.log
        verify = self.verify

        # Execute test
        exec(self.prg)

r = TestRunner(PRG_1)
r.run()

r = TestRunner(PRG_2)
r.run()

Any idea on how I can get this to work? Maybe there is a different (and better way) to accomplish this, that I as a C++ developer do not see.

$ python3 test.py
Testing a = 42
PASSED
Traceback (most recent call last):
  File "test.py", line 42, in <module>
    r.run()
  File "test.py", line 35, in run
    exec(self.prg)
  File "<string>", line 7, in <module>
  File "<string>", line 4, in f
NameError: name 'a' is not defined

Upvotes: 1

Views: 93

Answers (1)

FujiApple
FujiApple

Reputation: 826

If you do:

def run(self):
    exec(self.prg, {'log': self.log, 'verify': self.verify})

Produces:

42

Generally a good idea to avoid dynamic code execution like this anyway!

Upvotes: 2

Related Questions