I’m having trouble compiling a python AST with functions that need to refer to classes. A minimal example:
from types import CodeType, FunctionType
def main():
str = """
class Node:
def __init__(self, str):
self.str = str
def fn(input):
n = Node(input)
print(n)
fn("abc")
"""
mod = compile(str, "testing", 'exec')
exec(mod)
if __name__ == "__main__":
main()
Error:
File "/Users/wvw/git/n3/fun3/python/test_compile.py", line 25, in <module>
main()
File "/Users/wvw/git/n3/fun3/python/test_compile.py", line 22, in main
exec(mod)
File "testing", line 10, in <module>
File "testing", line 7, in fn
NameError: name 'Node' is not defined. Did you mean: 'None'?
Interestingly, when I try to instantiate the class outside the function:
...
# fn("abc")
Node("abc")
"""
Then the code works fine. So, first of all, I’m wondering what the problem is?
Note that the function actually works when separately importing the “Node” class in the original Python file:
from test_node import Node # added this import
from types import CodeType, FunctionType
...
With test_node.py:
class Node:
def __init__(self, str):
self.str = str
So, what’s my problem (i.e., why not just do that)? I really need to call fn
from “outside” as that is where the input is given – i.e.,
from test_node import Node
from types import CodeType, FunctionType
def main():
str = """
class Node:
def __init__(self, str):
self.str = str
def fn(input):
n = Node(input)
print(n)
"""
mod = compile(str, "testing", 'exec')
exec(mod)
# get function to be called
for c in mod.co_consts:
if isinstance(c, CodeType) and c.co_name == "fn":
fn = FunctionType(c, {})
# call function
fn("abc")
if __name__ == "__main__":
main()
Which again gives the following error:
Traceback (most recent call last):
File "/Users/wvw/git/n3/fun3/python/test_compile.py", line 34, in <module>
main()
File "/Users/wvw/git/n3/fun3/python/test_compile.py", line 31, in main
fn("abc")
File "testing", line 7, in fn
NameError: name 'Node' is not defined. Did you mean: 'None'?
Clearly, there are some inner workings of compile
that I am unaware of. I’m hoping someone with metaprogramming experience in python will be able to shed some light.