Skip to content

Commit ebdb167

Browse files
author
Richard Jones
committed
beginning getting ZPT up to date: TAL first
1 parent e6c74ed commit ebdb167

File tree

12 files changed

+1386
-254
lines changed

12 files changed

+1386
-254
lines changed

roundup/cgi/TAL/DummyEngine.py

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
##############################################################################
2+
#
3+
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
4+
# All Rights Reserved.
5+
#
6+
# This software is subject to the provisions of the Zope Public License,
7+
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
8+
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9+
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10+
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11+
# FOR A PARTICULAR PURPOSE.
12+
#
13+
##############################################################################
14+
# Modifications for Roundup:
15+
# 1. commented out ITALES references
16+
# 2. implemented ustr as str
17+
"""
18+
Dummy TALES engine so that I can test out the TAL implementation.
19+
"""
20+
21+
import re
22+
import sys
23+
24+
from TALDefs import NAME_RE, TALESError, ErrorInfo
25+
#from ITALES import ITALESCompiler, ITALESEngine
26+
#from DocumentTemplate.DT_Util import ustr
27+
ustr = str
28+
29+
IDomain = None
30+
if sys.modules.has_key('Zope'):
31+
try:
32+
from Zope.I18n.ITranslationService import ITranslationService
33+
from Zope.I18n.IDomain import IDomain
34+
except ImportError:
35+
pass
36+
if IDomain is None:
37+
# Before 2.7, or not in Zope
38+
class ITranslationService: pass
39+
class IDomain: pass
40+
41+
class _Default:
42+
pass
43+
Default = _Default()
44+
45+
name_match = re.compile(r"(?s)(%s):(.*)\Z" % NAME_RE).match
46+
47+
class CompilerError(Exception):
48+
pass
49+
50+
class DummyEngine:
51+
52+
position = None
53+
source_file = None
54+
55+
#__implements__ = ITALESCompiler, ITALESEngine
56+
57+
def __init__(self, macros=None):
58+
if macros is None:
59+
macros = {}
60+
self.macros = macros
61+
dict = {'nothing': None, 'default': Default}
62+
self.locals = self.globals = dict
63+
self.stack = [dict]
64+
self.translationService = DummyTranslationService()
65+
66+
def getCompilerError(self):
67+
return CompilerError
68+
69+
def getCompiler(self):
70+
return self
71+
72+
def setSourceFile(self, source_file):
73+
self.source_file = source_file
74+
75+
def setPosition(self, position):
76+
self.position = position
77+
78+
def compile(self, expr):
79+
return "$%s$" % expr
80+
81+
def uncompile(self, expression):
82+
assert (expression.startswith("$") and expression.endswith("$"),
83+
expression)
84+
return expression[1:-1]
85+
86+
def beginScope(self):
87+
self.stack.append(self.locals)
88+
89+
def endScope(self):
90+
assert len(self.stack) > 1, "more endScope() than beginScope() calls"
91+
self.locals = self.stack.pop()
92+
93+
def setLocal(self, name, value):
94+
if self.locals is self.stack[-1]:
95+
# Unmerge this scope's locals from previous scope of first set
96+
self.locals = self.locals.copy()
97+
self.locals[name] = value
98+
99+
def setGlobal(self, name, value):
100+
self.globals[name] = value
101+
102+
def evaluate(self, expression):
103+
assert (expression.startswith("$") and expression.endswith("$"),
104+
expression)
105+
expression = expression[1:-1]
106+
m = name_match(expression)
107+
if m:
108+
type, expr = m.group(1, 2)
109+
else:
110+
type = "path"
111+
expr = expression
112+
if type in ("string", "str"):
113+
return expr
114+
if type in ("path", "var", "global", "local"):
115+
return self.evaluatePathOrVar(expr)
116+
if type == "not":
117+
return not self.evaluate(expr)
118+
if type == "exists":
119+
return self.locals.has_key(expr) or self.globals.has_key(expr)
120+
if type == "python":
121+
try:
122+
return eval(expr, self.globals, self.locals)
123+
except:
124+
raise TALESError("evaluation error in %s" % `expr`)
125+
if type == "position":
126+
# Insert the current source file name, line number,
127+
# and column offset.
128+
if self.position:
129+
lineno, offset = self.position
130+
else:
131+
lineno, offset = None, None
132+
return '%s (%s,%s)' % (self.source_file, lineno, offset)
133+
raise TALESError("unrecognized expression: " + `expression`)
134+
135+
def evaluatePathOrVar(self, expr):
136+
expr = expr.strip()
137+
if self.locals.has_key(expr):
138+
return self.locals[expr]
139+
elif self.globals.has_key(expr):
140+
return self.globals[expr]
141+
else:
142+
raise TALESError("unknown variable: %s" % `expr`)
143+
144+
def evaluateValue(self, expr):
145+
return self.evaluate(expr)
146+
147+
def evaluateBoolean(self, expr):
148+
return self.evaluate(expr)
149+
150+
def evaluateText(self, expr):
151+
text = self.evaluate(expr)
152+
if text is not None and text is not Default:
153+
text = ustr(text)
154+
return text
155+
156+
def evaluateStructure(self, expr):
157+
# XXX Should return None or a DOM tree
158+
return self.evaluate(expr)
159+
160+
def evaluateSequence(self, expr):
161+
# XXX Should return a sequence
162+
return self.evaluate(expr)
163+
164+
def evaluateMacro(self, macroName):
165+
assert (macroName.startswith("$") and macroName.endswith("$"),
166+
macroName)
167+
macroName = macroName[1:-1]
168+
file, localName = self.findMacroFile(macroName)
169+
if not file:
170+
# Local macro
171+
macro = self.macros[localName]
172+
else:
173+
# External macro
174+
import driver
175+
program, macros = driver.compilefile(file)
176+
macro = macros.get(localName)
177+
if not macro:
178+
raise TALESError("macro %s not found in file %s" %
179+
(localName, file))
180+
return macro
181+
182+
def findMacroDocument(self, macroName):
183+
file, localName = self.findMacroFile(macroName)
184+
if not file:
185+
return file, localName
186+
import driver
187+
doc = driver.parsefile(file)
188+
return doc, localName
189+
190+
def findMacroFile(self, macroName):
191+
if not macroName:
192+
raise TALESError("empty macro name")
193+
i = macroName.rfind('/')
194+
if i < 0:
195+
# No slash -- must be a locally defined macro
196+
return None, macroName
197+
else:
198+
# Up to last slash is the filename
199+
fileName = macroName[:i]
200+
localName = macroName[i+1:]
201+
return fileName, localName
202+
203+
def setRepeat(self, name, expr):
204+
seq = self.evaluateSequence(expr)
205+
return Iterator(name, seq, self)
206+
207+
def createErrorInfo(self, err, position):
208+
return ErrorInfo(err, position)
209+
210+
def getDefault(self):
211+
return Default
212+
213+
def translate(self, domain, msgid, mapping, default=None):
214+
return self.translationService.translate(domain, msgid, mapping,
215+
default=default)
216+
217+
218+
class Iterator:
219+
220+
# This is not an implementation of a Python iterator. The next()
221+
# method returns true or false to indicate whether another item is
222+
# available; if there is another item, the iterator instance calls
223+
# setLocal() on the evaluation engine passed to the constructor.
224+
225+
def __init__(self, name, seq, engine):
226+
self.name = name
227+
self.seq = seq
228+
self.engine = engine
229+
self.nextIndex = 0
230+
231+
def next(self):
232+
i = self.nextIndex
233+
try:
234+
item = self.seq[i]
235+
except IndexError:
236+
return 0
237+
self.nextIndex = i+1
238+
self.engine.setLocal(self.name, item)
239+
return 1
240+
241+
class DummyDomain:
242+
__implements__ = IDomain
243+
244+
def translate(self, msgid, mapping=None, context=None,
245+
target_language=None, default=None):
246+
# This is a fake translation service which simply uppercases non
247+
# ${name} placeholder text in the message id.
248+
#
249+
# First, transform a string with ${name} placeholders into a list of
250+
# substrings. Then upcase everything but the placeholders, then glue
251+
# things back together.
252+
253+
# simulate an unknown msgid by returning None
254+
if msgid == "don't translate me":
255+
text = default
256+
else:
257+
text = msgid.upper()
258+
259+
def repl(m, mapping=mapping):
260+
return ustr(mapping[m.group(m.lastindex).lower()])
261+
cre = re.compile(r'\$(?:(%s)|\{(%s)\})' % (NAME_RE, NAME_RE))
262+
return cre.sub(repl, text)
263+
264+
class DummyTranslationService:
265+
__implements__ = ITranslationService
266+
267+
def translate(self, domain, msgid, mapping=None, context=None,
268+
target_language=None, default=None):
269+
return self.getDomain(domain).translate(msgid, mapping, context,
270+
target_language,
271+
default=default)
272+
273+
def getDomain(self, domain):
274+
return DummyDomain()

roundup/cgi/TAL/HTMLParser.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""A parser for HTML and XHTML."""
2-
__docformat__ = 'restructuredtext'
32

43
# This file is based on sgmllib.py, but the API is slightly different.
54

@@ -11,7 +10,6 @@
1110

1211
import markupbase
1312
import re
14-
import string
1513

1614
# Regular expressions used for parsing
1715

@@ -261,7 +259,7 @@ def parse_starttag(self, i):
261259
match = tagfind.match(rawdata, i+1)
262260
assert match, 'unexpected call to parse_starttag()'
263261
k = match.end()
264-
self.lasttag = tag = string.lower(rawdata[i+1:k])
262+
self.lasttag = tag = rawdata[i+1:k].lower()
265263

266264
while k < endpos:
267265
m = attrfind.match(rawdata, k)
@@ -274,16 +272,16 @@ def parse_starttag(self, i):
274272
attrvalue[:1] == '"' == attrvalue[-1:]:
275273
attrvalue = attrvalue[1:-1]
276274
attrvalue = self.unescape(attrvalue)
277-
attrs.append((string.lower(attrname), attrvalue))
275+
attrs.append((attrname.lower(), attrvalue))
278276
k = m.end()
279277

280-
end = string.strip(rawdata[k:endpos])
278+
end = rawdata[k:endpos].strip()
281279
if end not in (">", "/>"):
282280
lineno, offset = self.getpos()
283281
if "\n" in self.__starttag_text:
284-
lineno = lineno + string.count(self.__starttag_text, "\n")
282+
lineno = lineno + self.__starttag_text.count("\n")
285283
offset = len(self.__starttag_text) \
286-
- string.rfind(self.__starttag_text, "\n")
284+
- self.__starttag_text.rfind("\n")
287285
else:
288286
offset = offset + len(self.__starttag_text)
289287
self.error("junk characters in start tag: %s"
@@ -340,7 +338,7 @@ def parse_endtag(self, i):
340338
match = endtagfind.match(rawdata, i) # </ + tag + >
341339
if not match:
342340
self.error("bad end tag: %s" % `rawdata[i:j]`)
343-
tag = string.lower(match.group(1))
341+
tag = match.group(1).lower()
344342
if ( self.cdata_endtag is not None
345343
and tag != self.cdata_endtag):
346344
# Should be a mismatched end tag, but we'll treat it
@@ -396,9 +394,9 @@ def unknown_decl(self, data):
396394
def unescape(self, s):
397395
if '&' not in s:
398396
return s
399-
s = string.replace(s, "&lt;", "<")
400-
s = string.replace(s, "&gt;", ">")
401-
s = string.replace(s, "&apos;", "'")
402-
s = string.replace(s, "&quot;", '"')
403-
s = string.replace(s, "&amp;", "&") # Must be last
397+
s = s.replace("&lt;", "<")
398+
s = s.replace("&gt;", ">")
399+
s = s.replace("&apos;", "'")
400+
s = s.replace("&quot;", '"')
401+
s = s.replace("&amp;", "&") # Must be last
404402
return s

0 commit comments

Comments
 (0)