[mod_python] Building a web application using Cheetah and mod_python

Dirk van Oosterbosch, IR labs labs at ixopusada.com
Mon Oct 30 20:14:06 EST 2006


Thanks,

> 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.
>
> [...]
>
> 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.

Then, I guess it won't do it's magic for __import__(modulename)  :-(
The way I am building my system, I'll need to call
	module = __import__(modulename, globals(), locals(), [name])
since I don't know the name of the module (and of the object) until  
runtime.
Will there be a cure for this too?

(I wouldn't have a problem so much with issuing a special command to  
make mod_python reload all modules, if it just wasn't "apachectl  
stop ... apachectl start" ;)


>>> 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.

Indeed, python 2.4.1


>> 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.

I am not planning to port, but thanks for the tip!


Thanks again ... and mod_python 3.3 will be announced on this list  
won't it? ;-)

dirk





-----------------------------
Dirk van Oosterbosch
de Wittenstraat 225
1052 AT Amsterdam
the Netherlands

http://labs.ixopusada.com
-----------------------------


On 29-okt-2006, at 1:10, Graham Dumpleton wrote:

>
> 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