import sys import config for path in config.path: sys.path.append(path) import os import sapt __author__ = 'Guido Wesdorp' __version__ = '0.1' __copyright__ = '(c) 2006 Guido Wesdorp' class ZPTool(object): """Stand-alone ZPT engine builds an environment using a dict of provided vars (for headers, environment variables, etc) and some additional stuff: * scripts - a special object that provides access to scripts in the 'scripts' subdirectory of the environment directory * templates - a special object that provides access to other pagetemplates, read from the 'templates' subdirectory of the environment directory The object should be instantiated with the path to the environment directory as its only argument, and has one basic method that is interesting, which is 'render'. See the docstring of that method for a description. """ def __init__(self, envdir): if envdir.endswith(os.path.sep): envdir = envdir[:-1] self._envdir = envdir def render(self, path, env): """Render a template path is an absolute path to the pagetemplate to render env is a dictionary that is used as the environment for the pagetemplate, and should be filled with environment data (HTTP headers, environment variables, etc) from the calling code """ if not os.path.exists(path): return self.render_404(path, env) elif os.path.isdir(path): return self.render_dir(path, env) elif not os.path.isfile(path): raise SystemError, '%s is not a normal file' % path env.update(globals()) env['modules'] = Importer(self._envdir, env) env['templates'] = TemplateProvider(self._envdir, env) env['meta'] = { 'author': __author__, 'version': __version__, 'copyright': __copyright__, 'app': 'ZPTool %s, %s' % (__version__, __copyright__), } fp = open(path) try: data = fp.read() finally: fp.close() p = sapt.PageTemplate() p.pt_edit(data, None) return p.pt_render(env) def render_error_page(self, exc, e, tb, env): import traceback path = os.path.join(self._envdir, 'templates', 'exception.zpt') traceback = ''.join(traceback.format_tb(tb)) env.update({'exception': exc, 'value': e, 'traceback': traceback}) return self.render(path, env) def render_404(self, path, env): path = os.path.join(self._envdir, 'templates', '404.zpt') return self.render(path, env) def render_dir(self, path, env): if not config.default_indexes: # XXX should do render_dir_listing_not_allowed() or something return self.render_404(path, env) for default in config.default_indexes: newpath = os.path.join(path, default) if os.path.isfile(newpath): return self.render(newpath) # no custom index, render the default one path = os.path.join(self._envdir, 'templates', 'index.zpt') return self.render(path, env) class Importer(object): """Access point to scripts in the 'scripts' subdirectory of the envdir scripts are imported with the env variable provided to the template """ def __init__(self, envdir, env): self._envdir = envdir self._env = env def __getitem__(self, name): """return the return value of a script""" g = Container() g.update(globals().copy()) g['env'] = self._env fpath = '%s.py' % (os.path.join(self._envdir, name),) if not os.path.isfile(fpath): return __import__(name, g, {}) # XXX note that we do a shallow copy here, might be interesting for # caches and such, but also a bit scary... we may want to change this execfile(fpath, g) return g __getattr__ = __getitem__ class TemplateProvider(object): """Access points to page templates (for macros) in the 'templates' env dir templates get the same env dict passed to them as the main template """ def __init__(self, envdir, env): self._envdir = envdir self._env = env def __getitem__(self, name): """return the unrendered page template""" for ext in config.handler_extensions: fpath = '%s%s' % (os.path.join(self._envdir, name), ext) if os.path.exists(fpath): break fp = open(fpath) try: data = fp.read() finally: fp.close() p = sapt.PageTemplate() p.pt_edit(data, None) return p __getattr__ = __getitem__ class Container(dict): def __getattr__(self, name): try: return self[name] except KeyError: raise NameError, name