[albatross-users] page module import magic

Andrew McNamara andrewm at object-craft.com.au
Mon Jan 12 23:07:05 EST 2004


Is this getting too ugly? Much of the messiness comes from supporting
hierarchies of page modules (app.login.help, etc) - dummy parent modules
have to be created. I've written a bunch of tests, and it looks like
the modification works well, but maybe we should only support a flat page
module namespace?

Index: app.py
===================================================================
RCS file: /usr/local/cvsroot/object-craft/albatross/albatross/app.py,v
retrieving revision 1.87
diff -u -r1.87 app.py
--- app.py	9 Jan 2004 12:38:27 -0000	1.87
+++ app.py	12 Jan 2004 12:02:26 -0000
@@ -7,7 +7,6 @@
 
 import os
 import sys
-import stat
 import imp
 import urlparse
 
@@ -374,10 +373,13 @@
     '''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 = {}
+        if not sys.modules.has_key(self.mod_holder_name):
+            self.create_module_holder(self.mod_holder_name)
 
     def module_path(self):
         return self.__base_dir
@@ -393,35 +395,49 @@
             ctx.set_page(name)
         self.load_page_module(ctx, name)
 
+    def is_page_module(self, name):
+        return name.startswith(self.mod_holder_name)
+
+    def create_module_holder(self, name):
+        sys.modules[name] = module = imp.new_module(name)
+        return module
+
+    def get_module_holder(self, name):
+        path = name.split('.')[:-1]
+        parent_name = '.'.join(path)
+        try:
+            return sys.modules[parent_name]
+        except KeyError:
+            parent_parent = self.get_module_holder(parent_name)
+            module = self.create_module_holder(parent_name)
+            setattr(parent_parent, path[-1], module)
+            return module
+
     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 name.startswith(self.mod_holder_name):
+            name = self.mod_holder_name + '.' + name
+        try:
+            page = sys.modules[name]
+        except KeyError:
+            modpath = os.path.join(self.__base_dir, *name.split('.')[1:])
+            modpath, modname = os.path.split(os.path.normpath(modpath))
+            try:
+                f, filepath, desc = imp.find_module(modname, [modpath])
+            except ImportError, e:
+                raise ApplicationError('%s (in %s)' % (e, modpath))
+            try:
+                page = imp.load_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))
-            page.__mtime__ = os.stat(page.__file__)[stat.ST_MTIME]
-            self.__cache[path] = page
+            setattr(self.get_module_holder(name), modname, page)
         ctx.page = page
+        return ctx.page
 
     def page_enter(self, ctx, args):
         if hasattr(ctx.page, 'page_enter'):
@@ -451,8 +467,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	12 Jan 2004 12:02:28 -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