Interpret python code within python program - python

Is there a library for interpreting python code within a python program?
Sample usage might look like this..
code = """
def hello():
return 'hello'
hello()
"""
output = Interpreter.run(code)
print(output)
which then outputs
hello

found this example from grepper
the_code = '''
a = 1
b = 2
return_me = a + b
'''
loc = {}
exec(the_code, globals(), loc)
return_workaround = loc['return_me']
print(return_workaround)
apparently you can pass global and local scope into exec. In your use case, you would just use a named variable instead of returning.

You can use the exec function. You can't get the return value from the code variable. Instead you can print it there itself.
code = """
def hello():
print('hello')
hello()
"""
exec(code)

Related

Python: monkey patch a function's source code

Can I add a prefix and suffix to the source code of functions?
I know about decorators and do not want to use them (the minimal example below doesn't make clear why, but I have my reasons).
def f():
print('world')
g = patched(f,prefix='print("Hello, ");',suffix='print("!");')
g() # Hello, world!
Here is what I have so far:
import inspect
import ast
import copy
def patched(f,prefix,suffix):
source = inspect.getsource(f)
tree = ast.parse(source)
new_body = [
ast.parse(prefix).body[0],
*tree.body[0].body,
ast.parse(suffix).body[0]
]
tree.body[0].body = new_body
g = copy.deepcopy(f)
g.__code__ = compile(tree,g.__code__.co_filename,'exec')
return g
Unfortunately, nothing happens if I use this and then call g() as above; neither world nor Hello, world! are printed.
Here is a rough version of what can be done:
import inspect
import ast
import copy
def patched(f,prefix,suffix):
source = inspect.getsource(f)
tree = ast.parse(source)
new_body = [
ast.parse(prefix).body[0],
*tree.body[0].body,
ast.parse(suffix).body[0]
]
tree.body[0].body = new_body
code = compile(tree,filename=f.__code__.co_filename,mode='exec')
namespace = {}
exec(code,namespace)
g = namespace[f.__name__]
return g
def temp():
pass
def f():
print('world',end='')
g = patched(f,prefix='print("Hello, ",end="")',suffix='print("!",end="")')
g() # Hello, world!
The call of compile compiles an entire module (represented by tree). This module is then executed in an empty namespace from which the desired function is finally extracted. (Warning: the namespace will need to be filled with some globals from where f comes from if f uses those.)
After some more work, here is a real example of what can be done with this. It uses some extended version of the principle above:
import numpy as np
from playground import graphexecute
#graphexecute(verbose=True)
def my_algorithm(x,y,z):
def SumFirstArguments(x,y)->sumxy:
sumxy = x+y
def SinOfThird(z)->sinz:
sinz = np.sin(z)
def FinalProduct(sumxy,sinz)->prod:
prod = sumxy*sinz
def Return(prod):
return prod
print(my_algorithm(x=1,y=2,z=3))
#OUTPUT:
#>>Executing part SumFirstArguments
#>>Executing part SinOfThird
#>>Executing part FinalProduct
#>>Executing part Return
#>>0.4233600241796016
The clou is that I get the exact same output if I reshuffle the parts of my_algorithm, for example like this:
#graphexecute(verbose=True)
def my_algorithm2(x,y,z):
def FinalProduct(sumxy,sinz)->prod:
prod = sumxy*sinz
def SumFirstArguments(x,y)->sumxy:
sumxy = x+y
def SinOfThird(z)->sinz:
sinz = np.sin(z)
def Return(prod):
return prod
print(my_algorithm2(x=1,y=2,z=3))
#OUTPUT:
#>>Executing part SumFirstArguments
#>>Executing part SinOfThird
#>>Executing part FinalProduct
#>>Executing part Return
#>>0.4233600241796016
This works by (1) grabbing the source of my_algorithm and turning it into an ast (2) patching each function defined within my_algorithm (e.g. SumFirstArguments) to return locals (3) deciding based on the inputs and the outputs (as defined by the type hints) in which order the parts of my_algorithm should be executed. Furthermore, a possibility that I do not have implemented yet is to execute independent parts in parallel (such as SumFirstArguments and SinOfThird). Let me know if you want the sourcecode of graphexecute, I haven't included it here because it contains a lot of stuff that is not relevant to this question.
For your problem, you don't need to recompile your functions. Just define a list of functions, you inspect for arguments and return variable name:
def FinalProduct(sumxy, sinz) -> "prod":
return sumxy * sinz
def SumFirstArguments(x, y) -> "sumxy":
return x + y
def SinOfThird(z) -> "sinz":
return np.sin(z)
def execute(funcs, **args):
result = None
while funcs:
func = funcs.pop(0)
try:
kw = {a: args[a]
for a in func.__code__.co_varnames[:func.__code__.co_argcount]
}
except KeyError:
# not all arguments found
funcs.append(func)
else:
print(func,kw)
result = func(**kw)
args[func.__annotations__['return']] = result
return result
print(execute([FinalProduct, SumFirstArguments, SinOfThird], x=1,y=2,z=3))

Is it possible to make a context-dependent function?

I have used the following script to run the script directly and just to make a bash command line for running it outside the script (e.g. job scheduler).
def qsubcommand(func):
def wrapper(*args, **kwargs):
if kwargs.get('test', False):
cmdl = ' '.join(['this.py', func.__name__, *map(str, args)])
return cmdl
else:
return func(*args, **kwargs)
return wrapper
#qsubcommand
def calculate(value1, value2):
# do something
if __name__ == '__main__':
if len(sys.argv) > 1:
func, args = sys.argv[1], sys.argv[2:]
if func in locals().keys():
locals()[func](*args)
else:
raise NotImplementedError
I have a lot of functions like 'calculate'.
I'm working with the script for running and testing a program.
# When I want to run directly:
>>> calculate(4, 5)
# When I want to just print command line:
>>> calculate(4, 5, test=True)
'this.py calculate 4 5'
However, I want to use it in a context-dependent manner like below.
# When I want to run directly:
>>> test = False
>>> calculate(4, 5)
# When I want to just print command line:
>>> test = True
>>> calculate(4, 5)
'this.py calculate 4 5'
How can I modify to let the function recognize the variable outside the scope.
Is it possible to access a variable outside the function?
Thank you for your kind answers in advance.
Just put this on the part of the function where you want to check the variable:
if 'test' in globals() and test:
# do test
else:
# do normal
Functions can always access variables which are outside the function scope, they just can't edit them if you don't use the global keyword.

Decorators code result difference in cmd versus sublime

I am trying to learn decorators by following the 'python decorators in 12 steps'. http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
I tried replicating one of the In one of the code examples:
def outer(some_func):
def inner():
print ("before some_func")
ret = some_func()
return ret + 1
return inner
def foo():
return 1
def main():
decorated = outer(foo)
decorated()
if __name__ == "__main__": main()
This results in :
before some_func
In the example under Decorators!
>>> def outer(some_func):
... def inner():
... print ("before some_func")
... ret = some_func() # 1
... return ret + 1
... return inner
>>> def foo():
... return 1
>>> decorated = outer(foo) # 2
>>> decorated()
Returns:
before some_func
2
The main difference is that in the example, they are using Python running directly from cmd and I am using the Sublime text with python build as well as using a main() function. In my mind, I feel like these are doing the exact same thing. Is there something different between running code in the cmd versus with sublime that I am not getting?
The interactive Python interpreter automatically prints the results of a line if it is not assigned to a variable. This is useful for debugging. For example, if you call foo(), it will automatically print 1. The call below would not result in any extra prints in the interactive interpreter.
>>> result = decorated()

How to return value from exec in function?

I try:
def test(w,sli):
s = "'{0}'{1}".format(w,sli)
exec(s)
return s
print test("TEST12344","[:2]")
its return 'TEST12344'[:2]
How to return value from exec in function
Think of running the following code.
code = """
def func():
print("std out")
return "expr out"
func()
"""
On Python Console
If you run func() on the python console, the output would be something like:
>>> def func():
... print("std out")
... return "expr out"
...
>>> func()
std out
'expr out'
With exec
>>> exec(code)
std out
>>> print(exec(code))
std out
None
As you can see, the return is None.
With eval
>>> eval(code)
will produce Error.
So I Made My exec_with_return()
import ast
import copy
def convertExpr2Expression(Expr):
Expr.lineno = 0
Expr.col_offset = 0
result = ast.Expression(Expr.value, lineno=0, col_offset = 0)
return result
def exec_with_return(code):
code_ast = ast.parse(code)
init_ast = copy.deepcopy(code_ast)
init_ast.body = code_ast.body[:-1]
last_ast = copy.deepcopy(code_ast)
last_ast.body = code_ast.body[-1:]
exec(compile(init_ast, "<ast>", "exec"), globals())
if type(last_ast.body[0]) == ast.Expr:
return eval(compile(convertExpr2Expression(last_ast.body[0]), "<ast>", "eval"),globals())
else:
exec(compile(last_ast, "<ast>", "exec"),globals())
exec_with_return(code)
exec() doesn't just evaluate expressions, it executes code. You would have to save a reference within the exec() call.
def test(w, sli):
exec('s = "{}"{}'.format(w, sli))
return s
If you just want to evaluate an expression, use eval(), and save a reference to the returned value:
def test(w,sli):
s = "'{0}'{1}".format(w,sli)
s = eval(s)
return s
However, I would recommend avoiding exec() and eval() in any real code whenever possible. If you use it, make sure you have a very good reason to do so.
My findings in Python 3.8 in 2020
in Eval Logic :
a="1+99"
a=eval(a)
print(a) # output: 100
in exec logic
exec ("a=33+110")
print(a) #output 143

getting the module and line that a function was called from

Is there a way to programatically get the line number and name of a function?
For example, I want to pass a list of strings to a function :
s = [calling_module, calling_function, line_number]
report(s)
Currently I just put it all in manually :
s = ["module abc", "func()", "line 22", "notes"]
report(s)
But I would like to know if there is an automatic way for python to fill in the module name (I think __name__ does that), function name and line number for me. Is there a way?
Use inspect module functions. For example,
import inspect
def b():
f = inspect.currentframe()
current = inspect.getframeinfo(f)
caller = inspect.getframeinfo(f.f_back)
#caller = inspect.getframeinfo(inspect.getouterframes(f)[1][0])
print(__name__, current.filename, current.function, current.lineno, caller.function)
def a():
b()
a()
You may want something along the lines of traceback.extract_stack():
>>> def test():
... print "In Function"
... print traceback.extract_stack()
...
>>>
>>> test()
In Function
[('<stdin>', 1, '<module>', None), ('<stdin>', 3, 'test', None)]
Though the results would need to be parsed.
from inspect import currentframe, getframeinfo, getmodulename
def report():
f = getframeinfo(currentframe().f_back)
print getmodulename(f.filename), f.lineno, f.function
Note that using
__name__
will return the name of the module containing report, while the code above will show the name of the module that called report.

Categories

Resources