[mod_python] the req object

Jim Gallacher jpg at jgassociates.ca
Wed Jun 13 16:15:38 EDT 2007


Hi David,

David Bear wrote:
> When is the req object made available?
> 
> I'm trying something simple like this.
> 
> import sys
> try:
>    from mod_python import apache
> except:
>    print "import error"
>    sys.exit(1)
> try:
>    import dummymodule
> except:
>    req.content_type = 'text/plain'
>    req.write('error importing dummy')
>    return apache.OK
> 
> when the import dummymodule fails, the req object is not available to
> it. Without the req object, how does one send output anywhere?

That's a strange bit of code you have there. ;) Your code would only get 
executed by mod_python once, when the module is first loaded.

Read the following treatise and see if things make a bit more sense.

The mod_python request object is a pythonic wrapper around the apache 
request_rec structure and is associated with a *specific* request. It is 
not a global variable and it's not available outside the context of that 
request.

When apache services a new request it fills out the request_rec data 
structure (which is a C struct). In the event that mod_python is invoked 
by a configuration directive (PythonHandler helloworld, for example), 
apache passes this data structure to mod_python. Mod_python creates a 
python object, with a number of methods and attributes which allow you 
to access the contents of the request_rec in a pythonic way. By 
convention we call this object "req" in the documentation and mailing 
lists, but the name has no special meaning beyond that. It is not a 
global variable as your code above would seem to suggest.

For the sake of argument, just assume that your code will be read, 
parsed, compiled and evaluated once when it is first imported. (This is 
not strictly true, but it's close enough for our purposes here). Code at 
the module scope will be executed once.

So, how do you get at the request object and how is the request 
processed? Why, through your handler method of course! The request 
object will be passed as the first parameter to your handler method. 
Think of the handler method as the entry point into your code for each 
request.

Consider the simplest possible handler as an example:

AddHandler mod_python .py
PythonHandler helloworld


helloworld.py
-------------

from mod_python import apache

MSG = 'Hello world'
my_sum = 10 + 10

def handler(req):
     req.content_type = 'text/plain'
     req.write(MSG)
     return apache.OK

Note that the statement my_sum = 10 + 10 is only executed once, not 
every time a new request arrives. Same for MSG and our initial import 
statement.

The AddHandler directive tells apache that mod_python is going to handle 
the content generation phase of the request. The PythonHandler directive 
tells mod_python that the handler is in the helloworld module. 
Mod_python imports that module if it is not already loaed and looks for 
a method named "handler", which is the default method name.

You can actually specify a different method in your apache configuration:

AddHandler mod_python .py
PythonHandler helloworld2::alternate_thingy

helloworld2.py
-------------

from mod_python import apache

def handler(req):
     # This will never be called since we are specifying
     # a different handler method name in our PythonHandler directive.
     req.content_type = 'text/plain'
     req.write('Hello world')
     return apache.OK

def alternate_thingy(req):
     # this is the handler that will get called.
     req.content_type = 'text/plain'
     req.write('Hello world - from the alternate_thingy method')
     return apache.OK

The default method that mod_python will look for depends on the 
particular directive used (and each directive will get invoked in a 
different phase the request processing):

Configurate Directive Name           default mod_python method
----------------------------         ---------------------------
PythonPostReadRequestHandler         postreadrequesthandler(req)
PythonTransHandler                   transhandler(req)
PythonHeaderParserHandler            headerparserhandler(req)
PythonInitHandler                    inithandler(req)
PythonAccessHandler                  accesshandler(req)
PythonAuthenHandler                  authenhandler(req)
PythonAuthzHandler                   authzhandler(req)
PythonTypeHandler                    typehandler(req)
PythonFixupHandler                   fixuphandler(req)
PythonHandler                        handler(req)
PythonLogHandler                     loghandler(req)

(hint: the method name is a lowercase version of the Directive the 
"python" prefix stripped off)

So what about the Publisher handler? Publisher is an example of a 
content handler (it's invoked with PythonHandler) that evaluates the 
request URI and derives the handler method name from that URI. It's 
dynamically doing what we did with a static directive in the helloworld2 
example. Just like any other handler, in any other phase, it calls the 
method with the request object as the first parameter.

I think I know what you're trying to accomplish with your code snippet 
above, but it really is not the way to go. Trying to make your 
mod_python code usable (as far as handlers are concerned) outside of 
mod_python is a loosing proposition. You might want to take a look at 
the source code and dig into the way we do unit testing. I know it's not 
as nice as firing up a command line interpreter, but it is possible to 
write robust code without it.

Jim








More information about the Mod_python mailing list