If I import a module that uses exec or eval, is it possible to give it access to the main program?
myExec.py
def myExec(code):
exec(code)
main.py
import myExec
def test():
print("ok")
myExec.myExec("test()")
Yes!
exec has a few optional parameters, globals and locals. These basically tell it what global and local variables its allowed to use, in the form of a dictionary. Calling globals() or locals() functions returns the dictionary with all the global and local variables where you are calling from, so you can use:
myExec.py:
def myExec(code, globals_=None, locals_=None): # the trailing underscore is so that there are no name conflicts
exec(code, globals_, locals_)
main.py:
import myExec
def test():
print("ok")
myExec.myExec("test()", globals())
Related
The function:
def thefunction():
exec("x = 'text'")
return x
print(thefunction())
and it doesnt work...
this is for python 3
Give it a dict as a storage for variables.
def thefunction():
vars = {}
exec("x = 'text'", vars)
return vars['x']
print(thefunction())
In any case, read the documentation and warnings about exec.
you need to pass in your locals or it will only be local to that ...
def thefunction():
my_locals = locals()
exec("x = 'text'",globals(),my_locals)
return my_locals['x']
print(thefunction())
you can make it a little safer by sending in an isolated environment... but the bottom line is that its not safe to exec untrusted input
I have a file named file.py containing the following script:
def b():
print("b")
def proc():
print("this is main")
b()
proc()
And I have another file named caller.py, which contains this script:
text = open('file.py').read()
exec(text)
When I run it, I get the expected output:
this is main
b
However, if I change caller.py to this:
def main():
text = open('file.py').read()
exec(text)
main()
I get the following error:
this is main
Traceback (most recent call last):
File "./caller.py", line 7, in <module>
main()
File "./caller.py", line 5, in main
exec(text)
File "<string>", line 10, in <module>
File "<string>", line 8, in main
NameError: global name 'b' is not defined
How is function b() getting lost? It looks to me like I'm not violating any scope rules. I need to make something similar to the second version of caller.py work.
exec(text) executes text in the current scope, but modifying that scope (as def b does via the implied assignment) is undefined.
The fix is simple:
def main():
text = open('file.py').read()
exec(text, {})
This causes text to run in an empty global scope (augmented with the default __builtins object), the same way as in a regular Python file.
For details, see the exec documentation. It also warns that modifying the default local scope (which is implied when not specifying any arguments besides text) is unsound:
The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.
Would it work for you if you imported and called the function instead?
myfile.py
def b():
print("b")
def proc():
print("this is main")
b()
caller.py
import myfile
myfile.proc()
I want to replace some builtin functions inside the code that I run with exec. It is possible by passing it as a dictionary entry in the second exec argument. But when I try to import a module inside the executed code, the functions are as in original bultins, when called inside imported module.
This is the example of what I'm trying to achieve:
from inspect import cleandoc
def new_print(val):
print('Hello', val)
code_inner = cleandoc("""
def bar():
print('Inner')
""")
with open('inner.py', 'w') as f:
f.write(code_inner)
code_outer = cleandoc("""
import inner
print('Outer')
inner.bar()
""")
exec(code_outer, {'print': new_print}, {})
This is the response that I receive:
Hello Outer
Inner
And this is what I would like to have:
Hello Outer
Hello Inner
Is there any way to pass new globals, or builtins, or maybe variable list to the module beeing imported?
I'm not sure if it's quite what you want, but passing a dictionary parameter to the function and updating its modules globals works.
code_inner = cleandoc("""
def bar(d):
globals().update(d)
print('Inner')
""")
code_outer = cleandoc("""
import inner
print('Outer')
inner.bar({'print': print})
""")
Alternatively, without modification of the bar function you can pass its module a global like so:
code_outer = cleandoc("""
import inner
inner.print = print
print('Outer')
inner.bar()
""")
I'm very new to python. Here is the problem Im having.
I have hooked the builtin._import_ with my custom hook which loads a module from a string.
def import_hook(name, globals=None, locals=None, fromlist=None):
if name in sys.modules:
obj = sys.modules[name]
return obj
#Make sure we hook only for modules which start with ajay
if name.startswith("ajay"):
statement = '''
print 'inside the ajay module'
def ajay_func():
print 'inside the func'
'''
mod = imp.new_module(name)
mod.__file__ = name
compiled = compile(statement, '<string>', 'exec')
exec compiled in mod.__dict__
sys.modules[name] = mod
return mod
return original_import(name, globals, locals, fromlist)
Then I use this hook in function which is loading a module and calling its function in exec statement.
original_import = __builtin__.__import__
def test(request):
statement = '''
import sys
import ajay
def ILessons_1(request):
ajay.ajay_func()
'''
try:
__builtin__.__import__ = import_hook
compiled = compile(statement, '<string>', 'exec')
exec (compiled, globals(), locals()) #in statement_module.__dict__
ajay.ajay_func()
return ILessons_1(request);
finally:
__builtin__.__import__ = original_import
pass
When I run this code I get error "global name 'ajay' is not defined"in line "return ILessons_1(request);". Interesting thing is python is able to resolve ajay in line just above this line. Im pretty sure Im making some mistake in exec statement but have not been able to figure out.
Can some please help me solve this problem.
Thanks
Noted few issues here:
1) globals and locals are built-in function names, You should not use them as variable names.
2) Possibly a bug? (tested with python 2.7.1 under ubuntu)
Consider following code (note the exec statement):
def outer_function():
foo = "foobar"
statement = '''
def inner_function():
print foo
'''
#exec statement in globals(), locals()
exec statement in globals().update(locals())
inner_function()
outer_function()
Here commented string (exec with 2 arguments after in) will not work as described at in the documentation and result in:
NameError: global name 'foo' is not defined
But one may manually combine globals+locals an pass them to exec (next string after comment in my example). Looks like a workaround to me.
I have two files, one is in the webroot, and another is a bootstrap located one folder above the web root (this is CGI programming by the way).
The index file in the web root imports the bootstrap and assigns a variable to it, then calls a a function to initialize the application. Everything up to here works as expected.
Now, in the bootstrap file I can print the variable, but when I try to assign a value to the variable an error is thrown. If you take away the assignment statement no errors are thrown.
I'm really curious about how the scoping works in this situation. I can print the variable, but I can't asign to it. This is on Python 3.
index.py
# Import modules
import sys
import cgitb;
# Enable error reporting
cgitb.enable()
#cgitb.enable(display=0, logdir="/tmp")
# Add the application root to the include path
sys.path.append('path')
# Include the bootstrap
import bootstrap
bootstrap.VAR = 'testVar'
bootstrap.initialize()
bootstrap.py
def initialize():
print('Content-type: text/html\n\n')
print(VAR)
VAR = 'h'
print(VAR)
Thanks.
Edit: The error message
UnboundLocalError: local variable 'VAR' referenced before assignment
args = ("local variable 'VAR' referenced before assignment",)
with_traceback = <built-in method with_traceback of UnboundLocalError object at 0x00C6ACC0>
try this:
def initialize():
global VAR
print('Content-type: text/html\n\n')
print(VAR)
VAR = 'h'
print(VAR)
Without 'global VAR' python want to use local variable VAR and give you "UnboundLocalError: local variable 'VAR' referenced before assignment"
Don't declare it global, pass it instead and return it if you need to have a new value, like this:
def initialize(a):
print('Content-type: text/html\n\n')
print a
return 'h'
----
import bootstrap
b = bootstrap.initialize('testVar')