[mod_python] Udate python modules without restarting Apache

Graham Dumpleton grahamd at dscpl.com.au
Thu Oct 7 19:50:21 EDT 2004

On Oct 07 17:10, Graham Dumpleton <grahamd at dscpl.com.au> wrote:
> Subject: Re: [mod_python] Udate python modules without restarting Apache
> On Oct 07 23:50, berry groenendijk <berry.groenendijk at gmail.com> wrote:
> >
> > Subject: Re: [mod_python] Udate python modules without restarting Apache
> >
> > I think the problem is in the servlet.py. Because, as soon as I touch
> > this file I get this error:
> > 
> > ValueError: index is not a subclass of Servlet (in E:/Program
> > Files/Apache Group/Apache2/htdocs/MySite/index.mps)
> > 
> > Before I touched servlet.py the index file loaded perfectly.
> > Apparently apache tried reloading the servlet file effectively
> > creating a new Servlet object in memory. Other pages that have already
> > created in memory and that are subclasses from Servlet have now
> > apparently lost their 'parent'.
> > 
> > Any suggestions how to solve this?
> Hmmm, I haven't tried MPS as yet, looks like it might be time to do so
> in order to understand it a bit better.
> One of the issues with reloading that isn't obvious is that it doesn't
> actually clean out the namespace of the existing loaded module before
> loading it again. In effect it lays the reloading module back over the top
> of the old one. You can thus still have strange things happen if you keep
> state in global variables or remove methods.
> The easiest to explain is the removal of a method from a module which
> is imported by mod_python.publisher. Even though the method is removed
> from the code file, when it reloads the code module it doesn't actually
> delete the existing method, so it still exists and can still be accessed by
> a request.

Okay, have read your email properly now and have had a little play. What
I didn't note was that you had put mod_python.servlet into your directory
and touched it. A bit more of an explaination follows, but simple answer
is that you shouldn't need to touch servlet.py anyway as that isn't going to
help in the reloading of your code. I would also recommend that servlet.py
be installed properly somewhere else and not be in your document tree.
Preferably put it somewhere where its modification time will not be changed
inadvertantly while it is being used.

Anyway, what I think is happening is that in the most low level servlet class
in your common code modules, you have an ordinary import of something
from mpservlets. To use the demo tutorial that comes with mpservlets as an
example, it has _TutorialBase.py which after accomodating that you had
servlet.py in the same directory, has:

  from servlet import HTMLPage

Now in index.mps of the tutorial, if one has modified it to use import_module()
you would have:

  #from _TutorialBase import *

  from mod_python import apache
  _TutorialBase = apache.import_module("_TutorialBase")
  TutorialBase = _TutorialBase.TutorialBase

If Apache is freshly started, all will work okay. The problem now is that if servlet.py
is touched, mod_python will reimport servlet.py the next time a request comes in.

Now, the mpservlet system has its own module import and caching system for .mps
files. In mod_python doing the reimport of servlet.py it will actually throw out the
mpservlet cache contents so when handler() is called it will need to reload index.mps
which in turn obtains _TutorialBase from the standard mod_python cache.

The problem here is that _TutorialBase used a normal "import" to get HTMLPage and
it still holds a reference to the copy that was imported before "servlet.py" got reimported
by mod_python. When the handler() method in servlet.py goes to check to see if the
servlet loaded from index.mps derives from Servlet it doesn't match. This is because
that in _TutorialBase is still using the Servlet base class from the older servlet module
obtained using "import".

In other words, there are two copies of the servlet module in memory. The handler()
method is checking against itself (ie., new copy), where as _TutorialBase is still using
the old one.

Thus, for case where using mpservlet, simply don't touch the servlet.py. If you had
changed _TutorialBase, touch index.mps as well and both will be reloaded.

Although I suggest installing servlet.py somewhere else properly, you could possibly
also use import_module() to load in "servlet.py" as well. Ie.,

  # from servlet import HTMLPage

  from mod_python import apache
  servlet = apache.import_module("servlet")
  HTMLPage = servlet.HTMLPage

BTW, mpservlet doesn't use "imp" module to do module importing of .mps files but
instead uses execfile(). By using execfile() it effectively throws away the prior module before
reimporting it. This means you don't get issues with deleted methods still showing etc.
It also means though that you can't use global variables cleverly to preserve state
across module reloads. You would have to put such magic state in a separate modules
loaded by import_module() or "import" instead. Managing such state is still tricky though.

Hope this helps.

Graham Dumpleton (grahamd at dscpl.com.au)

More information about the Mod_python mailing list