Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compile text as a function using AST?

I need to compile an input string (from a database) as a function and run it. This is the method I currently use:

Say I already have this function defined:

def foo():
    print "Yo foo! I am a function!"

And the string I read in from the database says I should call this function:

string_from_db = "foo()"

I then form a function (whose name I can control) which returns the function I read in from the database:

my_func_string = "def doTheFunc():\n\t return " + string_from_db

Now I compile the string, and set it to a function name I use later for processing:

exec my_func_string
processor = doTheFunc

I can call it later by running processor() which exclaims: Yo foo! I am a function!

My Question: Above this piece of code there is a comment (left by a long lost developer):

    ###############################################################
    # The following method for getting a function out of the text #
    # in the database could potentially be replaced by using      #
    # Python's ast module to obtain an abstract syntax tree and   #
    # put it inside of a function node                            #
    ###############################################################

I'd like to know more about this "potential replacement." I have taken a look at AST, but I am very confused on how it can help me do what I am already doing with the code above.

  1. How can I accomplish the same thing using AST? Or where can AST help me in this process?
  2. Is the implementation using AST better, and why?
like image 437
dinkelk Avatar asked Nov 12 '12 19:11

dinkelk


1 Answers

AST is a much safer choice when evaluating untrusted code, that could contain malicious instructions, eval or exec can execute any expression, while AST on the other hand, allows you to parse and validate the expression yourself, or execute a limited expression using ast.literal_eval, sort of like a sandbox, which allows only strings, lists, numbers and a few other things. This is just a simple example:

import ast
a = ast.literal_eval("[1,2,3,4]") //evaluate an expression safely.

Another example that parses a string into an AST:

import ast
source = '2 + 2'
node = ast.parse(source, mode='eval')
ast.dump(node)

This prints:

Expression(body=BinOp(left=Num(n=2), op=Add(), right=Num(n=2)))

There's a very good tutorial here and also the documentation

like image 178
iabdalkader Avatar answered Oct 17 '22 06:10

iabdalkader