Search code examples
python-3.xdynamicon-the-fly

Compile function from string on-the-fly in python?


I'm working on a silly project in python that effectively implements a semi-REPL in a web-browser, and I'm stuck on how to cleanly dynamically evaluate code on-the-fly.

Basically, I have a web-form where the user enters a function, which should be then executed on the server.

The expected entry is a single function, with defined parameters. The function name, however, is not specified.

What I want is to get a string, such as:

def function_for_xxx(param_1, param_2, param_3):
    <stuff goes here>
    return interesting_value

and somehow convert that into a normal python function object (e.g. object of type <class 'function'>).

I can limit the scope of the task somewhat:

  • The user is explicitly trusted, so I don't have to worry about sanitization.
  • There are a few environment functions that should be passed into the function globals, but I can explicitly specify them.
  • Enforcing the string being a single bare function is actually desireable.

Right now, I've experimented a bit with the compile() and exec() calls, but they appear to insert the exec()ed code into the current local scope, which is non ideal. I'd really like the exec to be done without side effects like that, and just return a module or the bare function.


Solution

  • Ok, I figured out a workaround that is kind of hackish, but does what I want.

    Basically, we can exploit the fact that we can specify the execution scope to exec() calls by specifying the globals parameter.

    func_container = compile(func"\n", "<dynamic_functions_xxx>", "exec")
    
    scope = {
        <objects made available to the dynamic function>
    }
    exec(func_container, scope)
    

    Objects defined in the func string are now present in the scope variable, with no side effects to the local namespace.

    General comments apply here. If you can memoize the compile/exec process, doing so is probably a good idea (compiling is slow!).