1 # Joe Presbrey <presbrey@mit.edu>
3 import os, sys, types, time
5 from pyinotify import WatchManager, Notifier, EventsCodes
6 from Cheetah.Template import Template as _Template
8 __all__ = ['Templates']
10 class Template(object):
11 def __init__(self, name, ns={}, path=['templates']):
12 self._name, self._ns, self._path = name, ns, path+[name]
13 assert self._template()
16 return sys.modules['.'.join(self._path)]
18 def __getattr__(self, name):
19 return Template(name, self._ns, self._path)
21 def __call__(self, **kw):
22 namespaces = self._ns.copy()
24 return getattr(self._template(),
25 self._name)(namespaces=namespaces).respond()
27 class Templates(object):
29 _mask = EventsCodes.ALL_FLAGS['IN_CREATE'] \
30 | EventsCodes.ALL_FLAGS['IN_MODIFY'] \
31 | EventsCodes.ALL_FLAGS['IN_DELETE'] \
32 | EventsCodes.ALL_FLAGS['IN_ATTRIB']
41 def __init__(self, template_path, global_namespace={}):
42 self._base = os.path.abspath(template_path)
44 self._assert_module('templates', [template_path])
45 self._globals = global_namespace
47 self._thread = threading.Thread(target=self.loop)
48 self._thread.setDaemon(True)
51 def _tree_walk(self, tree, path, func):
57 return self._tree_walk(tree[x], path, func)
59 return func(tree, path[0])
61 def _tree_add(self, tree, path, value):
65 print self._tree_walk(tree, path, _add)
67 def _assert_module(self, name, path=None):
68 if not name in self._modules:
69 self._modules[name] = types.ModuleType(name)
71 self._modules[name].__path__ = path
72 sys.modules[name] = self._modules[name]
74 def _get_template_path(self, template_file):
75 r = template_file.startswith(self._base) \
76 and template_file[len(self._base)+1:].split(os.path.sep) or []
77 if r[-1].endswith('.tmpl'):
81 def _compile(self, template_path):
82 template = _Template.compile(file=self._files[template_path],
84 moduleName='.'.join(['templates']+list(template_path)),
85 className=template_path[-1],
87 compilerSettings={'useStackFrames':False})
90 def add(self, template_file):
91 template_path = self._get_template_path(template_file)
92 template_name = '.'.join(['templates']+list(template_path))
93 template_pkg = '.'.join(['templates']+list(template_path[:-1]))
94 template_py = os.path.join(os.path.dirname(template_file), '%s.py' % template_path[-1])
95 self._assert_module(template_pkg, [os.path.dirname(template_file)])
96 self._files[template_path] = template_file
97 code = self._compile(template_path)
98 f_code = file(template_py, 'w')
101 if self._loaded and \
102 template_name in sys.modules:
103 reload(sys.modules[template_name])
105 def remove(self, template_file):
106 #print 'removing', template_file
109 def _walk_load(self, args, dname, fnames):
111 if fname.endswith('.tmpl'):
112 template_file = os.path.join(dname, fname)
113 self.add(template_file)
117 os.path.walk(self._base, self._walk_load, None)
118 for path, filename in self._files.items():
119 __import__('.'.join(['templates']+list(path)))
122 def _event_handler(self, event):
123 if event.name.endswith('.tmpl') and not event.name.startswith('.'):
124 if event.maskname == 'IN_DELETE':
125 self.remove(event.pathname)
128 self.add(event.pathname)
131 def _event_init(self):
132 self._watch_manager = WatchManager()
133 self._watch_manager.add_watch(self._base,
138 self._notifier = Notifier(self._watch_manager)
144 self._notifier.process_events()
145 if self._notifier.check_events():
146 self._notifier.read_events()
147 except KeyboardInterrupt:
148 self._notifier.stop()
151 def __getattr__(self, key):
152 return Template(key, self._globals)
154 if __name__ == '__main__':
155 t = Templates('/home/joe/templates')