views:

1408

answers:

2

So I have some Python scripts, and I've got a BaseHTTPServer to serve up their responses. If the requested file is a .py then I'll run that script using execfile(script.py).

The question is this: are there any special rules about imports? One script needs to run just once, and it would be good to keep the objects it creates alive between requests. Can I trust that that will happen?

Does script run via execfile() run any differently, or have any scope access issues?

+2  A: 

The documentation for the execfile method is here. Since no particular version of python was specified, I'm going to assume we're talking about 2.6.2.

The documentation for execfile specifies it takes three arguments: the filename, a dictionary (to act as the local variables), and a second dictionary (to act as the global variables). If you omit the second and third arguments, the file's contents are run in their own scope (like a module) that captures local variables but exposes global variables to the parent scope. So if the file creates local variables, they won't be retained, but global variables will be retained.

However, running execfile without local and global contexts specified means that the file sees the locals and globals of the calling function. For code that you don't trust, this should be considered a security hole. It may generally be wise to create two dictionaries for locals and globals and pass those in as the second and third arguments to execfile. If you keep those dictionaries somewhere (such as in another dictionary keyed by the filename), then you could re-use those dictionaries the next time the file is served, which will keep the objects created by the file alive.

So in short: execfile isn't exactly like import. But you can retain dictionaries of the locals and globals to keep the results of an execfile call around to be used again.

fixermark
+1  A: 

I recommend not using execfile. Instead, you can dynamically import the python file they request as a module using the builtin __import__ function. Here's a complete, working example that I just wrote and tested:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()

        filename = self.path.lstrip("/")
        self.wfile.write("You requested " + filename + "\n\n")
        if filename.endswith(".py"):
            pyname = filename.replace("/", ".")[:-3]
            module = __import__(pyname)
            self.wfile.write( module.do_work() )

HTTPServer(("",8080), Handler).serve_forever()

So in this case, if someone visits http://localhost:8080/some_page then "You requested some_page" will be printed.

But if you request http://localhost:8080/some_module.py then the file some_module.py will be imported as a Python module and the do_work function in that module will be called. So if that module contains the code

def do_work():
    return "Hello World!"

and you make that request, then the resulting page will be

You requested some_module.py

Hello World!

This should be a good starting point for dealing with such things. As an aside, if you find yourself wanting a more advanced web server, I highly recommend CherryPy.

Eli Courtwright