3.2 So what Exactly does Mod-python do?

Let's pretend we have the following configuration:

<Directory /mywebdir>
    AddHandler python-program .py
    PythonHandler myscript

NB: /mywebdir is an absolute physical path.

And let's say that we have a python program (windows users: substitute forward slashes for backslashes) /mywedir/myscript.py that looks like this:

    from mod_python import apache

    def handler(req):

        req.content_type = "text/plain"
        req.write("Hello World!")

        return apache.OK

Here is what's going to happen: The AddHandler directive tells Apache that any request for any file ending with .py in the /mywebdir directory or a subdirectory thereof needs to be processed by mod_python.

When such a request comes in, Apache starts stepping through its request processing phases calling handlers in mod_python. The mod_python handlers check if a directive for that handler was specified in the configuration. (Remember, it acts as a dispatcher.) In our example, no action will be taken by mod_python for all handlers except for the generic handler. When we get to the generic handler, mod_python will notice "PythonHandler myscript" directive and do the following:

  1. If not already done, prepend the directory in which the PythonHandler directive was found to sys.path.

  2. Attempt to import a module by name myscript. (Note that if myscript was in a subdirectory of the directory where PythonHandler was specified, then the import would not work because said subdirectory would not be in the sys.path. One way around this is to use package notation, e.g. "PythonHandler subdir.myscript".)

  3. Look for a function called handler in myscript.

  4. Call the function, passing it a Request object. (More on what a Request object is later)

  5. At this point we're inside the script:

    • from mod_python import apache

      This imports the apache module which provides us the interface to Apache. With a few rare exceptions, every mod_python program will have this line.

    • def handler(req):

       This is our handler function declaration. It is called "handler" because mod_python takes the name of the directive, converts it to lower case and removes the word "python". Thus "PythonHandler" becomes "handler". You could name it something else, and specify it explicitly in the directive using the special "::" notation. For example, if the handler function was called "spam", then the directive would be "PythonHandler myscript::spam".

      Note that a handler must take one argument - the mysterious Request object. There is really no mystery about it though. The Request object is an object that provides all of the information about this particular request - such as the IP of client, the headers, the URI, etc. The communication back to the client is also done via the Request object, i.e. there is no "response" object.

    •     req.content_type = "text/plain"

      This sets the content type to "text/plain". The default is usually "text/html", but since our handler doesn't produce any html, "text/plain" is more appropriate.

    •     req.send_http_header()

      This function sends the HTTP headers to the client. You can't really start writing to the client without sending the headers first. Note that one of the headers is "Content-Type". So if you want to set custom content-types, you better do it before you call req.send_http_header().

    •     req.write("Hello Wordl!")

      This writes the "Hello World!" string to the client. (Did I really have to explain this one?)

    •     return apache.OK

      This tells Apache that everything went OK and that the request has been processed. If things did not go OK, that line could be return apache.HTTP_INTERNAL_SERVER_ERROR or return apache.HTTP_FORBIDDEN. When things do not go OK, Apache will log the error and generate an error message for the client.

Some food for thought: If you were paying attention, you noticed that nowhere did it say that in order for all of the above to happen, the URL needs to refer to myscript.py. The only requirement was that it refers to a .py file. In fact the name of the file doesn't matter, and the file referred to in the URL doesn't have to exist. So, given the above configuration, "http://myserver/mywebdir/myscript.py" and "http://myserver/mywebdir/montypython.py" would give the exact same result.

At this point, if you didn't understand the above paragraph, go back and read it again, until you do.

What is this????