2

Calling the imported function helpers.test_func(...) succeeds when called directly in the code block.

But fails with this exception:

  File "<string>", line 11, in <module>
  File "<string>", line 8, in z
NameError: name 'helpers' is not defined

when called indirectly, via the function z(), also defined in the block

code = """        
from my_proj import helpers

helpers.test_func("a")    

def y():
    print("b")

def z():
    helpers.test_func("c")

y()
z()    
"""

def test_func(v1):    
    print("--->{}".format(v1))

def test():
    exec(code)

if __name__ == '__main__':
    test()

The output of the code is

--->a
b

File "<string>", line 11, in <module>
File "<string>", line 8, in z
NameError: name 'helpers' is not defined

Why is the helpers module gone when the unction z is called ?

Why would I even want to do this ?

I'm trying to implement a tool, that loads function files (a_file.py), in which functions are defined, and I want to invoke the functions from the tool. Something like this :

_locals = {}
_globals = {}
eval(code_of_file, _globals, _locals)

f = _locals["func_defined_in_scope_of_file"]

f()  # <---- this fails with the same NameError as above

The example above is simpler, and if fails, I'm gessing that if I can solve the above problem, I will be able to use the same solution.

Less than ideal workadound:

adding from dry_pipe import helpers in the body of function z solves the problem, but it's not elegant

code = """        
from dry_pipe import helpers 

helpers.test_func("a")    
def y():
    print("b")

def z():
    from dry_pipe import helpers    
    helpers.test_func("c")

y()
z()    
"""
Max L.
  • 9,774
  • 15
  • 56
  • 86

1 Answers1

0

You have a scope problem. The exec function runs in the "current" scope so you should pass the globals() to exec function as second parameter (to see the global attributes). I have written a working example, please see it below. ((I have to say the exec function is not really recommended to use))

my_proj.py:

class Helper:
    @classmethod
    def test_func(cls, a):
        print("TEST FUNC - {}".format(a))

test.py:

code = """
from my_proj import Helper as helpers

helpers.test_func("a")

def y():
    print("b")

def z():
    helpers.test_func("c")

y()
z()
"""

def test_func(v1):
    print("--->{}".format(v1))

def test():
    exec(code, globals())

if __name__ == '__main__':
    test()

Output:

>>> python3 test.py 
TEST FUNC - a
b
TEST FUNC - c
milanbalazs
  • 4,811
  • 4
  • 23
  • 45