Mercurial > p > roundup > code
diff PageTemplates/PageTemplate.py @ 984:a3a8ac7b8c40
Adding PageTemplates to the dist
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Fri, 30 Aug 2002 08:27:34 +0000 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PageTemplates/PageTemplate.py Fri Aug 30 08:27:34 2002 +0000 @@ -0,0 +1,207 @@ +############################################################################## +# +# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE +# +############################################################################## +"""Page Template module + +HTML- and XML-based template objects using TAL, TALES, and METAL. +""" + +__version__='$Revision: 1.1 $'[11:-2] + +import sys + +from TAL.TALParser import TALParser +from TAL.HTMLTALParser import HTMLTALParser +from TAL.TALGenerator import TALGenerator +from TAL.TALInterpreter import TALInterpreter +from Expressions import getEngine +from string import join, strip, rstrip, split, replace, lower, find +from cStringIO import StringIO +from ExtensionClass import Base +from ComputedAttribute import ComputedAttribute + + +class PageTemplate(Base): + "Page Templates using TAL, TALES, and METAL" + + content_type = 'text/html' + expand = 0 + _v_errors = () + _v_warnings = () + _v_program = None + _v_macros = None + _v_cooked = 0 + id = '(unknown)' + _text = '' + _error_start = '<!-- Page Template Diagnostics' + + def macros(self): + return self.pt_macros() + macros = ComputedAttribute(macros, 1) + + def pt_edit(self, text, content_type): + if content_type: + self.content_type = str(content_type) + if hasattr(text, 'read'): + text = text.read() + self.write(text) + + def pt_getContext(self): + c = {'template': self, + 'options': {}, + 'nothing': None, + 'request': None, + 'modules': ModuleImporter, + } + parent = getattr(self, 'aq_parent', None) + if parent is not None: + c['here'] = parent + c['container'] = self.aq_inner.aq_parent + while parent is not None: + self = parent + parent = getattr(self, 'aq_parent', None) + c['root'] = self + return c + + def pt_render(self, source=0, extra_context={}): + """Render this Page Template""" + if not self._v_cooked: + self._cook() + + __traceback_supplement__ = (PageTemplateTracebackSupplement, self) + + if self._v_errors: + raise PTRuntimeError, 'Page Template %s has errors.' % self.id + output = StringIO() + c = self.pt_getContext() + c.update(extra_context) + + TALInterpreter(self._v_program, self._v_macros, + getEngine().getContext(c), + output, + tal=not source, strictinsert=0)() + return output.getvalue() + + def __call__(self, *args, **kwargs): + if not kwargs.has_key('args'): + kwargs['args'] = args + return self.pt_render(extra_context={'options': kwargs}) + + def pt_errors(self): + if not self._v_cooked: + self._cook() + err = self._v_errors + if err: + return err + if not self.expand: return + try: + self.pt_render(source=1) + except: + return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2]) + + def pt_warnings(self): + if not self._v_cooked: + self._cook() + return self._v_warnings + + def pt_macros(self): + if not self._v_cooked: + self._cook() + if self._v_errors: + __traceback_supplement__ = (PageTemplateTracebackSupplement, self) + raise PTRuntimeError, 'Page Template %s has errors.' % self.id + return self._v_macros + + def pt_source_file(self): + return None # Unknown. + + def write(self, text): + assert type(text) is type('') + if text[:len(self._error_start)] == self._error_start: + errend = find(text, '-->') + if errend >= 0: + text = text[errend + 4:] + if self._text != text: + self._text = text + self._cook() + + def read(self): + if not self._v_cooked: + self._cook() + if not self._v_errors: + if not self.expand: + return self._text + try: + return self.pt_render(source=1) + except: + return ('%s\n Macro expansion failed\n %s\n-->\n%s' % + (self._error_start, "%s: %s" % sys.exc_info()[:2], + self._text) ) + + return ('%s\n %s\n-->\n%s' % (self._error_start, + join(self._v_errors, '\n '), + self._text)) + + def _cook(self): + """Compile the TAL and METAL statments. + + Cooking must not fail due to compilation errors in templates. + """ + source_file = self.pt_source_file() + if self.html(): + gen = TALGenerator(getEngine(), xml=0, source_file=source_file) + parser = HTMLTALParser(gen) + else: + gen = TALGenerator(getEngine(), source_file=source_file) + parser = TALParser(gen) + + self._v_errors = () + try: + parser.parseString(self._text) + self._v_program, self._v_macros = parser.getCode() + except: + self._v_errors = ["Compilation failed", + "%s: %s" % sys.exc_info()[:2]] + self._v_warnings = parser.getWarnings() + self._v_cooked = 1 + + def html(self): + if not hasattr(getattr(self, 'aq_base', self), 'is_html'): + return self.content_type == 'text/html' + return self.is_html + +class _ModuleImporter: + def __getitem__(self, module): + mod = __import__(module) + path = split(module, '.') + for name in path[1:]: + mod = getattr(mod, name) + return mod + +ModuleImporter = _ModuleImporter() + +class PTRuntimeError(RuntimeError): + '''The Page Template has template errors that prevent it from rendering.''' + pass + + +class PageTemplateTracebackSupplement: + #__implements__ = ITracebackSupplement + + def __init__(self, pt): + self.object = pt + w = pt.pt_warnings() + e = pt.pt_errors() + if e: + w = list(w) + list(e) + self.warnings = w +
