2

I need to be able to run a large amount of python code from a string. Simply using exec doesn't seem to work, as, while the code runs perfectly in a normal setting, doing it this way seems to throw an error. I also don't think I can just import it as it it hosted on the internet. Here is the code:

import urllib.request URL = "https://dl.dropboxusercontent.com/u/127476718/instructions.txt" def main(): instructions = urllib.request.urlopen(URL) exec(instructions.read().decode()) if __name__ == "__main__": main() 

This is the error I've been getting:

Traceback (most recent call last): File "C:\Python33\rc.py", line 12, in <module> main() File "C:\Python33\rc.py", line 9, in main exec(instructions.read().decode()) File "<string>", line 144, in <module> File "<string>", line 120, in main NameError: global name 'Player' is not defined 

The code I'm trying to run is available in the link in the first code snippet.

If you have any questions I'll answer them. Thank you.

5
  • 3
    You might want to give some thought to the security implications of this design. Commented Apr 14, 2013 at 9:01
  • On NPE's point, it may be useful to consider PyPy's sandboxing feature. Commented Apr 14, 2013 at 9:09
  • Adding on to NPE's point, note this from the urllib docs: When opening HTTPS URLs, it does not attempt to validate the server certificate. Use at your own risk! In other words, man-in-the-middle attacks are possible, and this design would allow an attacker to execute arbitrary code on your system. Commented Apr 14, 2013 at 9:11
  • Is it still an issue given that the way I intend to use this is to write the code it links to myself, host it on dropbox and give this code out as an executable. (Thus making updating the code much easier). Commented Apr 14, 2013 at 9:19
  • That ought to work. What's the error you're getting? Commented Apr 14, 2013 at 10:36

3 Answers 3

3

Without specifying globals, the exec function (Python/bltinmodule.c) uses PyEval_GetGlobals() and PyEval_GetLocals(). For the execution frame of a function, the latter creates a new f_locals dict, which will be the target for the IMPORT_NAME, STORE_NAME, LOAD_NAME ops in the compiled code.

At the module level in Python the normal state of affairs is globals() == locals(). In that case STORE_NAME is using the module's globals, which is what a function defined within the module will use as its global namespace. However, using separate dicts for globals and locals obviously breaks that assumption.

The solution is to to manually supply globals, which exec will also use as locals:

def main(): instructions = urllib.request.urlopen(URL) exec(instructions.read().decode(), globals()) 

You could also use a new dict that has __name__ defined:

def main(): instructions = urllib.request.urlopen(URL) g = {'__name__': '__main__'} exec(instructions.read().decode(), g) 

I see in the source that the current directory will need a sound file named "pickup.wav", else you'll just get another error.

Of course, the comments about the security problems with using exec like this still apply. I'm only addressing the namespace technicality.

Sign up to request clarification or add additional context in comments.

Comments

1

First I thought you might try __import__ with a StringIO object. Might look something like StackOverflow: Local Import Statements in Python.

... but that's not right.

Then I thought of using the imp module but that doesn't seen to work either.

Then I looked at: Alex Martelli's answer to Use of Eval in Python --- and tried to use it on a silly piece of code myself.

I can get the ast object, and the results of the compile() from that (though it also seems that one can simply call compile(some_string_containing_python_source, 'SomeName', 'exec') without going through the ast.parse() intermediary step if you like. From what I gather you'd use ast if you wanted to then traverse the resulting syntax tree, inspecting and possibly modifying nodes, before you compiled it.

At the end it seems that you'll need to exec() the results of your compile() before you have resulting functions, classes or variables defined in your execution namespace.

2 Comments

__import__ takes module name as argument. The question you link to uses StringIO as an example of a module to import.
Yep, I see that now; hoping to fix that soon (using the imp module).
0

You can use pipe to put all strings into a child process of python and get output result from it.

Google os.popen or subprocess.Popen

2 Comments

This just seems to throw a different error FileNotFoundError: [WinError 2] The system cannot find the file specified
You don't have to put code strings into a file. you just need to start a python sub-process and write code strings to its pipe.stdin.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.