[mod_python] Trouble with multiple class objects in publisher model

Graham Dumpleton grahamd at dscpl.com.au
Wed Nov 8 17:21:00 EST 2006

For starters, you are mixing up mod_python basic handlers and
mod_python.publisher published functions. They are not the same
thing. See my recent comment on mailing list about this:


BTW, which version of mod_python are you using?

A few more things pointed out below.

Martin Stoufer wrote ..
> I am moving a set of python classes out of the Apache CGI model and into
> mod_python. There is both inheritance and composition going on among 
> these classes. A few factory classes as well. It seems that when it 
> comes time to pull the generated content from the hierarchy of classes,
> the string object returned to the initial class end up 'None'.
> I have stripped down my work as an example. If there is some larger 
> example of how this class structure should work, I would love to see it.
> from mod_python import apache
> class Dom:
>     def __call__(self, req):
>         from DomProdLibOutput import Html
>         self.form = req.form
>         self.output = Html('modPython')
>         self.host = self.form['host'].value
>         self.sortBy = self.form['sortby'].value
>         self.mode = self.form['mode'].value
>         if self.form.has_key('term'):
>            self.term=self.form['term'].value
>         else:
>            self.term = ""
>         req.content_type = "text/html"
>         req.send_http_header()

Only need to call req.send_http_header() if using mod_python 2.7.X.

>         result = self.generate()
>         req.write(result)
>         return apache.OK

You shouldn't be returning an Apache status code like this when using
publisher. Status codes are for mod_python basic handlers, not publisher.
Publisher needs to return the content, or if you have used req.write()
it should return None (if mod_python 3.2 or later), or a string consisting
of a singe space (prior to mod_python 3.2, to get around bug).

Also, because publisher will automatically detect and set content type
to 'text/html' when appropriate if returning the content, you don't need to
set it yourself. Thus you can just have:

        return self.generate()

and not worry about setting content, flush headers or explicitly
writing back content.

>     def generate(self):
>         result = self.output.generate()
>         return result
> dom = Dom()

Although you have specified a __call__() method so URL can just be '/.../dom',
you are also exposing all the member data and member functions of your
object as well and they can be access directly, which is really bad for this
example. To hide member functions and data you don't want automatically
accessible via a URL request, precede them with an underscore. Ie., use
_generate() not generate() and store data like self._form and not self.form.

> In the DomProdLibOutput file in the same dir:
> class Html:
>     def __init__(self, destination='screen'):
>         self.output = HtmlOutputFactory(destination).getOutput()
>         return
>     def generate(self):
>         #result = "Foo in Html"
>         result = self.output.generate()
>         return result
> class HtmlModPython:
>     def __init__(self):
>         self.content = """Empty content in HtmlModPython"""
>         return
>     def update(self, content):
>         self.content += content
>         return
>     def generate(self):
>         return "Foo in HtmlModPython"
>         #return self.content
> class HtmlOutputFactory:
>     def __init__(self, destination):
>         self.dest = destination
>         return
>     def getOutput(self):
>         if self.dest == 'screen': return HtmlScreen()
>         elif self.dest == 'modPython': return HtmlModPython()
>         elif self.dest == 'file': return HtmlFile()
>         else:
>             raise InvalidHtmlOutputDest, \
>         "%s is not a supported output" % self.dest
>         return
> As an interesting side note, if I have the generate() in Html return 
> just the string, things work fine. Its when I try and resolve the string
> stored by the HtmlModPython class instance that the resulting string 
> comes back 'None' irregardless of what the deepest generate() returns.

Lost me there. I would very much suggest to track through what is
happening that you use req.log_error() to log progress messages to
the Apache error log file.

> Do all these classes have to define __call__ as well?

The __call__() method is only required for the Dom instance if you want
URL to use the instance variable name only.


More information about the Mod_python mailing list