Mercurial > p > roundup > code
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 983:7fe79c67aaa9 | 984:a3a8ac7b8c40 |
|---|---|
| 1 ############################################################################## | |
| 2 # | |
| 3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. | |
| 4 # | |
| 5 # This software is subject to the provisions of the Zope Public License, | |
| 6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. | |
| 7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | |
| 8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | |
| 10 # FOR A PARTICULAR PURPOSE | |
| 11 # | |
| 12 ############################################################################## | |
| 13 """Page Template module | |
| 14 | |
| 15 HTML- and XML-based template objects using TAL, TALES, and METAL. | |
| 16 """ | |
| 17 | |
| 18 __version__='$Revision: 1.1 $'[11:-2] | |
| 19 | |
| 20 import sys | |
| 21 | |
| 22 from TAL.TALParser import TALParser | |
| 23 from TAL.HTMLTALParser import HTMLTALParser | |
| 24 from TAL.TALGenerator import TALGenerator | |
| 25 from TAL.TALInterpreter import TALInterpreter | |
| 26 from Expressions import getEngine | |
| 27 from string import join, strip, rstrip, split, replace, lower, find | |
| 28 from cStringIO import StringIO | |
| 29 from ExtensionClass import Base | |
| 30 from ComputedAttribute import ComputedAttribute | |
| 31 | |
| 32 | |
| 33 class PageTemplate(Base): | |
| 34 "Page Templates using TAL, TALES, and METAL" | |
| 35 | |
| 36 content_type = 'text/html' | |
| 37 expand = 0 | |
| 38 _v_errors = () | |
| 39 _v_warnings = () | |
| 40 _v_program = None | |
| 41 _v_macros = None | |
| 42 _v_cooked = 0 | |
| 43 id = '(unknown)' | |
| 44 _text = '' | |
| 45 _error_start = '<!-- Page Template Diagnostics' | |
| 46 | |
| 47 def macros(self): | |
| 48 return self.pt_macros() | |
| 49 macros = ComputedAttribute(macros, 1) | |
| 50 | |
| 51 def pt_edit(self, text, content_type): | |
| 52 if content_type: | |
| 53 self.content_type = str(content_type) | |
| 54 if hasattr(text, 'read'): | |
| 55 text = text.read() | |
| 56 self.write(text) | |
| 57 | |
| 58 def pt_getContext(self): | |
| 59 c = {'template': self, | |
| 60 'options': {}, | |
| 61 'nothing': None, | |
| 62 'request': None, | |
| 63 'modules': ModuleImporter, | |
| 64 } | |
| 65 parent = getattr(self, 'aq_parent', None) | |
| 66 if parent is not None: | |
| 67 c['here'] = parent | |
| 68 c['container'] = self.aq_inner.aq_parent | |
| 69 while parent is not None: | |
| 70 self = parent | |
| 71 parent = getattr(self, 'aq_parent', None) | |
| 72 c['root'] = self | |
| 73 return c | |
| 74 | |
| 75 def pt_render(self, source=0, extra_context={}): | |
| 76 """Render this Page Template""" | |
| 77 if not self._v_cooked: | |
| 78 self._cook() | |
| 79 | |
| 80 __traceback_supplement__ = (PageTemplateTracebackSupplement, self) | |
| 81 | |
| 82 if self._v_errors: | |
| 83 raise PTRuntimeError, 'Page Template %s has errors.' % self.id | |
| 84 output = StringIO() | |
| 85 c = self.pt_getContext() | |
| 86 c.update(extra_context) | |
| 87 | |
| 88 TALInterpreter(self._v_program, self._v_macros, | |
| 89 getEngine().getContext(c), | |
| 90 output, | |
| 91 tal=not source, strictinsert=0)() | |
| 92 return output.getvalue() | |
| 93 | |
| 94 def __call__(self, *args, **kwargs): | |
| 95 if not kwargs.has_key('args'): | |
| 96 kwargs['args'] = args | |
| 97 return self.pt_render(extra_context={'options': kwargs}) | |
| 98 | |
| 99 def pt_errors(self): | |
| 100 if not self._v_cooked: | |
| 101 self._cook() | |
| 102 err = self._v_errors | |
| 103 if err: | |
| 104 return err | |
| 105 if not self.expand: return | |
| 106 try: | |
| 107 self.pt_render(source=1) | |
| 108 except: | |
| 109 return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2]) | |
| 110 | |
| 111 def pt_warnings(self): | |
| 112 if not self._v_cooked: | |
| 113 self._cook() | |
| 114 return self._v_warnings | |
| 115 | |
| 116 def pt_macros(self): | |
| 117 if not self._v_cooked: | |
| 118 self._cook() | |
| 119 if self._v_errors: | |
| 120 __traceback_supplement__ = (PageTemplateTracebackSupplement, self) | |
| 121 raise PTRuntimeError, 'Page Template %s has errors.' % self.id | |
| 122 return self._v_macros | |
| 123 | |
| 124 def pt_source_file(self): | |
| 125 return None # Unknown. | |
| 126 | |
| 127 def write(self, text): | |
| 128 assert type(text) is type('') | |
| 129 if text[:len(self._error_start)] == self._error_start: | |
| 130 errend = find(text, '-->') | |
| 131 if errend >= 0: | |
| 132 text = text[errend + 4:] | |
| 133 if self._text != text: | |
| 134 self._text = text | |
| 135 self._cook() | |
| 136 | |
| 137 def read(self): | |
| 138 if not self._v_cooked: | |
| 139 self._cook() | |
| 140 if not self._v_errors: | |
| 141 if not self.expand: | |
| 142 return self._text | |
| 143 try: | |
| 144 return self.pt_render(source=1) | |
| 145 except: | |
| 146 return ('%s\n Macro expansion failed\n %s\n-->\n%s' % | |
| 147 (self._error_start, "%s: %s" % sys.exc_info()[:2], | |
| 148 self._text) ) | |
| 149 | |
| 150 return ('%s\n %s\n-->\n%s' % (self._error_start, | |
| 151 join(self._v_errors, '\n '), | |
| 152 self._text)) | |
| 153 | |
| 154 def _cook(self): | |
| 155 """Compile the TAL and METAL statments. | |
| 156 | |
| 157 Cooking must not fail due to compilation errors in templates. | |
| 158 """ | |
| 159 source_file = self.pt_source_file() | |
| 160 if self.html(): | |
| 161 gen = TALGenerator(getEngine(), xml=0, source_file=source_file) | |
| 162 parser = HTMLTALParser(gen) | |
| 163 else: | |
| 164 gen = TALGenerator(getEngine(), source_file=source_file) | |
| 165 parser = TALParser(gen) | |
| 166 | |
| 167 self._v_errors = () | |
| 168 try: | |
| 169 parser.parseString(self._text) | |
| 170 self._v_program, self._v_macros = parser.getCode() | |
| 171 except: | |
| 172 self._v_errors = ["Compilation failed", | |
| 173 "%s: %s" % sys.exc_info()[:2]] | |
| 174 self._v_warnings = parser.getWarnings() | |
| 175 self._v_cooked = 1 | |
| 176 | |
| 177 def html(self): | |
| 178 if not hasattr(getattr(self, 'aq_base', self), 'is_html'): | |
| 179 return self.content_type == 'text/html' | |
| 180 return self.is_html | |
| 181 | |
| 182 class _ModuleImporter: | |
| 183 def __getitem__(self, module): | |
| 184 mod = __import__(module) | |
| 185 path = split(module, '.') | |
| 186 for name in path[1:]: | |
| 187 mod = getattr(mod, name) | |
| 188 return mod | |
| 189 | |
| 190 ModuleImporter = _ModuleImporter() | |
| 191 | |
| 192 class PTRuntimeError(RuntimeError): | |
| 193 '''The Page Template has template errors that prevent it from rendering.''' | |
| 194 pass | |
| 195 | |
| 196 | |
| 197 class PageTemplateTracebackSupplement: | |
| 198 #__implements__ = ITracebackSupplement | |
| 199 | |
| 200 def __init__(self, pt): | |
| 201 self.object = pt | |
| 202 w = pt.pt_warnings() | |
| 203 e = pt.pt_errors() | |
| 204 if e: | |
| 205 w = list(w) + list(e) | |
| 206 self.warnings = w | |
| 207 |
