Trevor Shaw Trevor Shaw - 4 years ago 107
Python Question

Calling a function that was defined by exec() from an object in another class. Python

I'm new to Python, and would appreciate some help getting out of the namespace hell I've created for myself...

Background:
Using web.py on a Raspberry Pi to receive user generated code from a blockly web-app.

Code is then executed in a function that is a member of the iforge class using exec()

User code can often contain functions.

User code can also spawn threads using the myThread class.

So... If user code defines a function and then spawns a thread, and that thread wants to call the user-defined function, I need to fingure out how to pass a pointer to that function into the thread object. Now when I do it, it says it doesn't recognize the name.

Here is the class that receives the user code and executes it:

class iforge:
def GET(self):
return "You have found the code executor function"

def POST(self):
global _shutdown,GPIO,time
cleanup()
web.header('Access-Control-Allow-Origin', '*')
web.header('Content-Type', 'application/json')
request=web.input()
code=request.code
exec (code,globals(),locals())
reply={'message':'now running your code on rPi'}
return json.dumps(reply)


Here is the code that handles the thread creation:

class myThread (threading.Thread):
def __init__(self, threadName, code, caller):
threading.Thread.__init__(self)
self.name = threadName
self.code = code
self.shutdown = False
self.caller= caller
def run(self):
from iforge import *
global _shutdown,GPIO,time
print "Starting thread"
l=dir(self.caller.POST)
print "printing debug info"
print self.caller
print dir(self.caller.POST)
method=getattr(self.caller, self.code[:-2])
while not _shutdown:
pass
exec(method(), globals(),locals())
print "Exiting thread"


Here is a sample of the user code that would get sent to iforge.POST:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(1, GPIO.OUT)
def do_something():
GPIO.output(1, GPIO.HIGH)
thread1 = myThread('if_myThread','''do_something()''',self)
thread1.start()

Answer Source

I was able to get this to work by passing the globals() functon to exec as BOTH the globals and locals argument to exec.

So in the Post() function when I call exec, I use exec (code,globals(),globals())

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download