[mod_python] Building a web application using Cheetah and mod_python

Graham Dumpleton grahamd at dscpl.com.au
Sat Oct 28 19:10:35 EDT 2006


On 29/10/2006, at 4:12 AM, Dirk van Oosterbosch, IR labs wrote:

> Hi,
>
> I am also working on a "cms"-like website system, using mod_python  
> and Cheetah, though I've not yet tied these both up together, to be  
> fully functional. Still working on the smaller subparts of the system.
> So I follow this subject with great interest.
>
> It feels like the core of this discussion is about making sure the  
> cheetah modules gets reloaded when they change. I didn't conduct  
> any tests yet, still trying to grasp the exact mechanisms underneath.
>
>>> [...]
>>> Is this the best way to import template modules and then evaluate  
>>> them?
>>
>> No, in as much as you are having to create a parallel hierarchy of  
>> publisher
>> handlers for each Cheetah page. You would be better off using a  
>> custom
>> handler which does the dispatch direct to the compiled Cheetah  
>> template
>> classes.
>
> I'm not sure if this helps, but I've got a similar setup. There is  
> one handler in a main.py that handles all requests. This main  
> connects to a database, to find out which Cheetah template to use,  
> and loads and fills this template. Also I've got a directory which  
> hold all the python files directly necessary for the system (/var/ 
> www/python) and an other directory to hold my templates. (/var/www/ 
> python/templates)
>
> If inside this main.py I would use an `apache.import_module 
> (fooTemplate)` instead of just `from fooTemplate import  
> fooTemplate`, that would mean that the fooTemplate is reloaded if  
> it changed, doesn't it?

Probably not. See issue 8 in:

   http://www.dscpl.com.au/wiki/ModPython/Articles/ 
ModuleImportingIsBroken

> But would it also mean that all the other templates which are  
> imported through their inheritance would be reloaded if they are  
> changed?

Again, probably not, for same reason.

> Most of my templates are inheriting parent-templates using the  
> Cheetah standard
> #from bar import bar
> #extends bar
>
> It's easy to create a whole directory with fresh modules, using the  
> shell `cheetah compile *.tmpl`. But is there also a way to ensure  
> me that apache is reloading them, if I do that? (i.e. an other way  
> than restarting apache, which I have to do frequently while  
> debugging this system :-(

Using current versions of mod_python available there is no way of  
doing it except
perhaps by using the Vampire extensions for mod_python.  
Alternatively, use
version 3.3 of mod_python out of Subversion repository or wait until  
it is released.

Both Vampire and the new mod_python 3.3 implement a module importer  
which
tracks child imports and will correctly import parent modules when a  
child changes.
In fact it is the Vampire module importer which was used as basis for  
3.3 version.

This works even if 'from bar import bar' is used as they intercept  
the 'import'
statement and when an import is performed from inside a module which was
already imported using the module importer, it will use the module  
importer for
the 'import' as well. Ie., no need to use apache.import_module()  
explicitly. If the
module being imported using 'import' is in another directory though,  
it is necessary
to specify an option declaring the search path for the modules. This  
is a path which
is distinct from PythonPath as new importer will not use any module  
in PythonPath
as a candidate for reloading as that causes lots of problems.

Anyway, end result is that with these module importers, you can  
update a base
class template, regenerate Cheetah Python class and anything which  
extends
from it will be automatically reloaded along with the base class.

> And sometimes I am not importing a compiled template in main, but  
> create a new template from a text/tmpl file
> `t = Template(file = "foobar.tmpl", searchList = [dict, obj])`
> What does creating a template on the fly like this, mean for  
> reloading a changed inherited template?

Not sure. Does Cheetah use a caching system of its own for this so  
that it isn't
loading them from disk all the time and does it reload the tmpl file  
if it has changed
on disk. I can't remember what it does and it may have changed since  
when I
was more actively looking at it.

>>> This second file only works if I add /var/www/app/templates to my
>>> PythonPath.  And, due to (2) above, I then also have to add
>>> /var/www/app to PythonPath.  Is this really necessary?=
>>
>> With the version of mod_python you are using, yes it is necessary.
>
> I am also adding the templates directory to my PythonPath, but  
> since I am not yet running my code from Apache, I haven't yet  
> discovered problems with loading the rest of my python modules from  
> my /var/www/python. But if I hit those issues, I'll now know how to  
> fix them, ;-)

With new importers, you don't want to be setting PythonPath if you  
want modules
to be reloadable. You will need to set the module importers own  
search path.

> BTW, (OT)
>
>>>    templateModule = apache.import_module("templates/myTemplate")
>>
>> Using '/' in the module name like this is not portable and is  
>> dependent
>> on peculiarities of the behaviour of Python on a specific  
>> platform. It will
>> not for example work on Mac OS X and also possibly not on Windows.
>
> I am working on a mac and also using slashes `/` to delimit my  
> paths, so no problems there. (Didn't try from mod_python though &  
> dunno what will happen on Windows).

What version of Python are you using? I know for sure it didn't work  
with
Python (2.3) on Panther. I also don't think it worked with Python  
(2.3.5)
on Tiger. If you are using Python 2.4 or later which you installed  
yourself,
it is entirely possible it may work.

> However I know of portability issues, so I am only using paths/with/ 
> slashes in my configuration files, if I need to create a path in  
> code I'm using os.path.join()

Depending on the source of the path, one should actually use  
posixpath functions
sometimes instead of os.path. This is especially the case of working  
on req.uri and
sometimes on req.filename. This is because Apache supplies both of  
them as
POSIXish style paths and using os.path functions on Windows can screw  
things
up as it introduces back slashes.

>> Things are a bit easier to manage and easier to predict when  
>> mod_python 3.3
>> can be used. Version 3.3 of mod_python hasn't been released yet,  
>> but is quite
>> close.
>
> I am eagerly awaiting :-)
> best
>
> dirk
>
>
>
> -----------------------------
> Dirk van Oosterbosch
> de Wittenstraat 225
> 1052 AT Amsterdam
> the Netherlands
>
> http://labs.ixopusada.com
> -----------------------------
>
>
> On 28-okt-2006, at 5:32, Graham Dumpleton wrote:
>
>>
>> On 28/10/2006, at 7:44 AM, Sebastian Celis wrote:
>>
>>> Hello,
>>>
>>> I am new to this list and have just recently begun to work on a
>>> project where I wish to use mod_python.publisher and cheetah to  
>>> drive
>>> an entire web application.  I apologize if the following topics have
>>> been discussed to death recently, but I have read through the
>>> documentation on both sites and have searched through the mailing- 
>>> list
>>> archives and while I have seen similar discussions, I have yet to  
>>> find
>>> definitive answers.  I am able to get most things to work, however I
>>> can't help but feel that there are better ways of approaching  
>>> some of
>>> my situations.
>>>
>>> First, I'll quickly describe my directory structure:
>>>
>>> /var/www/app -- The base directory to the web application.  This  
>>> will
>>> directly contain most of the python files that correspond  
>>> directly to
>>> URLs.  For example, index.py, login.py, etc.  In this directory.
>>> /var/www/app/templates -- Contains all of my cheetah templates.
>>> /var/www/app/include -- Contains the python utility modules I am
>>> writing specifically for this application.
>>>
>>> Now, onto the questions.
>>>
>>>
>>> 1) Importing compiled cheetah templates
>>>
>>> Assume I have code like the following in /var/www/app/test1.py
>>>
>>> ######################################
>>> from mod_python import apache
>>> from Cheetah.Template import Template
>>>
>>> def index(req):
>>>    req.content_type = "text/html"
>>>
>>>    dict = {'title': 'My Title!', 'message': 'Hello world!'}
>>>    templateModule = apache.import_module("templates/myTemplate")
>>
>> Using '/' in the module name like this is not portable and is  
>> dependent
>> on peculiarities of the behaviour of Python on a specific  
>> platform. It will
>> not for example work on Mac OS X and also possibly not on Windows.
>>
>>>    t = getattr(templateModule, "myTemplate")()
>>>    searchList = t.searchList()
>>>    searchList.insert(0, dict)
>>>
>>>    return(t.respond())
>>> ######################################
>>>
>>> Is this the best way to import template modules and then evaluate  
>>> them?
>>
>> No, in as much as you are having to create a parallel hierarchy of  
>> publisher
>> handlers for each Cheetah page. You would be better off using a  
>> custom
>> handler which does the dispatch direct to the compiled Cheetah  
>> template
>> classes. See the mod_python handler described in:
>>
>>   http://wiki.cheetahtemplate.org/cheetah-recipes.html
>>
>>> 2) Modifying PythonPath prevents modules from being imported
>>>
>>> Inside file /var/www/app/test2.py, I have the following code:
>>>
>>> import config
>>> (or)
>>> config = apache.import_module("config")
>>>
>>> Both of these commands load /var/www/app/config.py, and seem to work
>>> fine.  However, if I add
>>>
>>> PythonPath "['/var/www/app/templates']+sys.path"
>>>
>>> to my apache configuration, I get an error next time I run test2.py.
>>>
>>> ###
>>> Mod_python error: "PythonHandler mod_python.publisher"
>>>
>>> Traceback (most recent call last):
>>>
>>>  File "/usr/lib/python2.4/site-packages/mod_python/apache.py", line
>>> 299, in HandlerDispatch
>>>    result = object(req)
>>>
>>>  File "/usr/lib/python2.4/site-packages/mod_python/publisher.py",
>>> line 213, in handler
>>>    published = publish_object(req, object)
>>>
>>>  File "/usr/lib/python2.4/site-packages/mod_python/publisher.py",
>>> line 412, in publish_object
>>>    return publish_object(req,util.apply_fs_data(object, req.form,  
>>> req=req))
>>>
>>>  File "/usr/lib/python2.4/site-packages/mod_python/util.py", line
>>> 439, in apply_fs_data
>>>    return object(**args)
>>>
>>>  File "/var/www/app/test2.py", line 8, in index
>>>    config = apache.import_module("config")
>>>
>>>  File "/usr/lib/python2.4/site-packages/mod_python/apache.py", line
>>> 461, in import_module
>>>    f, p, d = imp.find_module(parts[i], path)
>>>
>>> ImportError: No module named config
>>> ###
>>>
>>> Why does this initially work but then stop working once I add a
>>> directory to my path?  I can fix it by adding '/var/www/app' to my
>>> PythonPath as well, but I don't understand why it didn't work before
>>> that.
>>
>> That is just how mod_python has always worked. Setting PythonPath
>> stops mod_python looking in the directory the handler was specified
>> for. Yes it is a pain. FWIW, this behaviour changes in mod_python 3.3
>> where the whole issue of module importing is dealt with a bit  
>> differently
>> and is much more consistent and predictable.
>>
>> Current versions of mod_python have a lot of issues when it comes
>> to the module importer. You should really have a read of:
>>
>>   http://www.dscpl.com.au/wiki/ModPython/Articles/ 
>> ModuleImportingIsBroken
>>
>>> 3) Cheetah and #include
>>>
>>> I have read a lot about why mod_python sets the current working
>>> directory to '/', but this seems to be causing some larger problems
>>> when cheetah comes into play.  (3) and (4) discuss two issues that I
>>> am having trouble with.
>>>
>>> Here is /var/www/app/templates/testPage.tmpl:
>>> ###
>>> #include 'header_include.tmpl'
>>> <head>
>>> <title>$title</title>
>>> </head>
>>> <body>
>>> <p>$message</p>
>>> </body>
>>> #include 'footer_include.tmpl'
>>> ###
>>>
>>> However, as this actually tries to load /header_include.tmpl and
>>> /footer_include.tmpl instead of the ones located in my templates
>>> directory, this will not work.
>>
>> If you are going to use compiled templates, you are possibly  
>> better off using
>> a site page base class and have specific pages extend that page.  
>> These
>> common blocks are then accessible through the base class. This  
>> means you
>> get the benefit of compiled code for the included blocks as well,  
>> instead of
>> it having to be interpreted each time.
>>
>>> I came up with two workarounds,
>>> however I don't really love either:
>>>
>>> a)
>>>
>>> ###
>>> #include os.path.join(os.path.dirname(__file__),  
>>> 'header_include.tmpl')
>>> <head>
>>> <title>$title</title>
>>> </head>
>>> <body>
>>> <p>$message</p>
>>> </body>
>>> #include os.path.join(os.path.dirname(__file__),  
>>> 'footer_include.tmpl')
>>> ###
>>>
>>> b)
>>>
>>> Actually pass $templatesDir into all of my templates and then  
>>> instead call:
>>>
>>> ###
>>> #include os.path.join(templatesDir, 'header_include.tmpl')
>>> <head>
>>> <title>$title</title>
>>> </head>
>>> <body>
>>> <p>$message</p>
>>> </body>
>>> #include os.path.join(templatesDir, 'footer_include.tmpl')
>>> ###
>>>
>>> I guess I'm leaning toward (a), but both seem cumbersome and slower
>>> than necessary.  Is there a better way to do this?
>>
>> If my memory of Cheetah is correct, then extending from a site  
>> page which
>> has reusable bits like this as I describe above is better.
>>
>>> 4) Cheetah and inheritance
>>>
>>> Assume these two files:
>>>
>>> /var/www/app/templates/overall_base.tmpl
>>> ###
>>> <?xml version="1.0" encoding="UTF-8"?>
>>> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
>>>          "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
>>> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
>>> <head>
>>>    <title>$title</title>
>>> </head>
>>> <body>
>>>    $bodyContent
>>> </body>
>>> </html>
>>> ###
>>>
>>> /var/www/app/templates/overall_base_extender.tmpl
>>> ###
>>> #overall_base = apache.import_module("overall_base")
>>> (or)
>>> #from overall_base import overall_base
>>>
>>> #extends overall_base
>>> #def title
>>> Welcome to Foo
>>> #end def
>>> #def bodyContent
>>> Hello world!
>>> #end def
>>>
>>> This second file only works if I add /var/www/app/templates to my
>>> PythonPath.  And, due to (2) above, I then also have to add
>>> /var/www/app to PythonPath.  Is this really necessary?=
>>
>> With the version of mod_python you are using, yes it is necessary.
>>
>>> #overall_base = apache.import_module("overall_base",
>>> path=[os.path.dirname(__file__)])
>>>
>>> doesn't seem to work inside the cheetah template file.  Even
>>>
>>> #sys.path.append(os.path.dirname(__file__))
>>> #overall_base = apache.import_module("overall_base")
>>
>> That one I am not sure about. You may be hitting one of the other  
>> problems
>> with PythonPath based module importing which is you can't easily  
>> have the
>> same name module in different directories and be sure you import  
>> the one
>> you want.
>>
>> In general I wouldn't recommend using apache.import_module() within
>> Cheetah templates explicitly.
>>
>>> doesn't seem to work.  Is there any way to get inheriting  
>>> templates to
>>> work without modifying PythonPath to include all the directories  
>>> where
>>> my base templates might be located?
>>
>> Not really.
>>
>>> I apologize for the huge length of this e-mail.  I am still  
>>> fairly new
>>> to mod_python and cheetah, but so far I really like what I see.  I
>>> just feel like there are a few issues I need to wrap my head around
>>> before I can really dive into developing applications.  Any pointers
>>> or help with these issues that you can provide would be greatly
>>> appreciated.
>>
>> Things are a bit easier to manage and easier to predict when  
>> mod_python 3.3
>> can be used. Version 3.3 of mod_python hasn't been released yet,  
>> but is quite
>> close. If you want to try the source for mod_python out of the  
>> Subversion
>> repository, then can suggest better ways of doing things.
>>
>> Graham
>> _______________________________________________
>> Mod_python mailing list
>> Mod_python at modpython.org
>> http://mailman.modpython.org/mailman/listinfo/mod_python
>>
>
>
>
>
>
> _______________________________________________
> Mod_python mailing list
> Mod_python at modpython.org
> http://mailman.modpython.org/mailman/listinfo/mod_python


More information about the Mod_python mailing list