[albatross-users] PATCH: page module loading changes (was: pagination with al-for)
Andrew McNamara
andrewm at object-craft.com.au
Thu Jan 8 12:36:08 EST 2004
>Even getting it to work with my "synthetic holding module" approach
>will not be straighforward - I'll have to somehow hook the unpickler's
>import requests.
Here's a patch that implements option 2 (loading page modules into a
synthetic namespace). It's worked on the small number of (moderately
complex) albatross apps I tried so far. In theory, you can now have a
hierarchy of page modules ("admin.foo", "admin.bah"), although I haven't
tested this yet.
There are a number of changes from the old behaviour:
* page module names were previously allowed to contain path components -
now they are dot-delimited. So "admin/foo" becomes "admin.foo"
(untested).
* the page module cache implemented by the PageModuleMixin is gone - we
now rely on sys.modules for caching. The magic to auto-reload when the
module file was touched is also removed (it was broken anyway).
* page modules are saved into sys.modules prepended with a synthetic
__alpage__ module - so "login" becomes "__alpage__.login".
Index: app.py
===================================================================
RCS file: /usr/local/cvsroot/object-craft/albatross/albatross/app.py,v
retrieving revision 1.84
diff -u -r1.84 app.py
--- app.py 10 Nov 2003 00:35:04 -0000 1.84
+++ app.py 8 Jan 2004 01:23:53 -0000
@@ -7,7 +7,6 @@
import os
import sys
-import stat
import imp
import urlparse
@@ -346,10 +345,17 @@
'''Caching module loader
'''
+ mod_holder_name = '__alpage__'
+
def __init__(self, base_dir, start_page):
self.__base_dir = base_dir
self.__start_page = start_page
- self.__cache = {}
+ try:
+ self.__mod_holder = sys.modules[self.mod_holder_name]
+ except KeyError:
+ self.__mod_holder = imp.new_module(self.mod_holder_name)
+ sys.modules[self.mod_holder_name] = self.__mod_holder
+ globals()[self.mod_holder_name] = self.__mod_holder
def module_path(self):
return self.__base_dir
@@ -365,35 +371,33 @@
ctx.set_page(name)
self.load_page_module(ctx, name)
+ def is_page_module(self, name):
+ return name.startswith(self.mod_holder_name)
+
def load_page_module(self, ctx, name):
- if self.__base_dir == '.':
- path = name
- else:
- path = os.path.join(self.__base_dir, name)
- page = self.__cache.get(path)
- if page:
- mtime = os.stat(page.__file__)[stat.ST_MTIME]
- if mtime > page.__mtime__:
- reload(page)
- page.__mtime__ = mtime
- if not page:
- dirname, name = os.path.split(path)
- file, filepath, desc = imp.find_module(name, [dirname])
- page = sys.modules.get(name)
- if not page or not page.__file__.startswith(filepath):
- try:
- page = imp.load_module(name, file, filepath, desc)
- finally:
- if file:
- file.close()
- if not (hasattr(page, 'page_enter') or
- hasattr(page, 'page_leave') or
- hasattr(page, 'page_process') or
- hasattr(page, 'page_display')):
- raise ApplicationError('module "%s" does not define one of page_enter, page_leave, page_process or page_display' % (name))
- page.__mtime__ = os.stat(page.__file__)[stat.ST_MTIME]
- self.__cache[path] = page
+ if name.startswith(self.mod_holder_name):
+ name = name[len(self.mod_holder_name)+1:]
+ filename = os.path.join(self.__base_dir, name.replace('.', os.path.sep))
+ filename = os.path.normpath(filename)
+ dirname, filename = os.path.split(filename)
+ module_name = self.mod_holder_name + '.' + name
+ try:
+ page = sys.modules[module_name]
+ except KeyError:
+ f, filepath, desc = imp.find_module(name, [dirname])
+ try:
+ page = imp.load_module(module_name, f, filepath, desc)
+ finally:
+ if f:
+ f.close()
+ if not (hasattr(page, 'page_enter') or
+ hasattr(page, 'page_leave') or
+ hasattr(page, 'page_process') or
+ hasattr(page, 'page_display')):
+ raise ApplicationError('module "%s" does not define one of page_enter, page_leave, page_process or page_display' % (name))
+ setattr(self.__mod_holder, name, page)
ctx.page = page
+ return page
def page_enter(self, ctx, args):
if hasattr(ctx.page, 'page_enter'):
@@ -423,8 +427,8 @@
self.__start_page = start_page
self.__page_objects = {}
- def module_path(self):
- pass
+ def is_page_module(self, name):
+ return False
def start_page(self):
return self.__start_page
Index: context.py
===================================================================
RCS file: /usr/local/cvsroot/object-craft/albatross/albatross/context.py,v
retrieving revision 1.93
diff -u -r1.93 context.py
--- context.py 21 Sep 2003 04:40:31 -0000 1.93
+++ context.py 8 Jan 2004 01:23:54 -0000
@@ -10,6 +10,7 @@
import stat
import re
import cPickle
+import __builtin__
try:
import zlib
@@ -564,9 +565,13 @@
self.clear_locals()
def decode_session(self, text):
- module_path = self.app.module_path()
- if module_path:
- sys.path.insert(0, module_path)
+ def imp_hook(name, globals, locals, fromlist):
+ if self.app.is_page_module(name):
+ return self.app.load_page_module(self, name)
+ else:
+ return real_imp(name, globals, locals, fromlist)
+
+ real_imp, __builtin__.__import__ = __builtin__.__import__, imp_hook
try:
try:
vars = cPickle.loads(text)
@@ -577,8 +582,7 @@
for name in vars.keys():
self.__vars[name] = 1
finally:
- if module_path:
- sys.path.remove(module_path)
+ __builtin__.__import__ = real_imp
def encode_session(self):
vars = {}
--
Andrew McNamara, Senior Developer, Object Craft
http://www.object-craft.com.au/
More information about the Albatross-users
mailing list