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

Roundup Issue Tracker: http://roundup-tracker.org/