Deprecate TAL package and make it a facade of zope.tal.

parent 7544aa4b
......@@ -13,238 +13,13 @@
##############################################################################
"""
Dummy TALES engine so that I can test out the TAL implementation.
"""
import re
import sys
from TALDefs import NAME_RE, TALESError, ErrorInfo
from ITALES import ITALESCompiler, ITALESEngine
from DocumentTemplate.DT_Util import ustr
class _Default:
pass
Default = _Default()
name_match = re.compile(r"(?s)(%s):(.*)\Z" % NAME_RE).match
class CompilerError(Exception):
pass
class DummyEngine:
position = None
source_file = None
__implements__ = ITALESCompiler, ITALESEngine
def __init__(self, macros=None):
if macros is None:
macros = {}
self.macros = macros
dict = {'nothing': None, 'default': Default}
self.locals = self.globals = dict
self.stack = [dict]
self.translationService = DummyTranslationService()
def getCompilerError(self):
return CompilerError
def getCompiler(self):
return self
def setSourceFile(self, source_file):
self.source_file = source_file
def setPosition(self, position):
self.position = position
def compile(self, expr):
return "$%s$" % expr
def uncompile(self, expression):
assert (expression.startswith("$") and expression.endswith("$"),
expression)
return expression[1:-1]
def beginScope(self):
self.stack.append(self.locals)
def endScope(self):
assert len(self.stack) > 1, "more endScope() than beginScope() calls"
self.locals = self.stack.pop()
def setLocal(self, name, value):
if self.locals is self.stack[-1]:
# Unmerge this scope's locals from previous scope of first set
self.locals = self.locals.copy()
self.locals[name] = value
def setGlobal(self, name, value):
self.globals[name] = value
def evaluate(self, expression):
assert (expression.startswith("$") and expression.endswith("$"),
expression)
expression = expression[1:-1]
m = name_match(expression)
if m:
type, expr = m.group(1, 2)
else:
type = "path"
expr = expression
if type in ("string", "str"):
return expr
if type in ("path", "var", "global", "local"):
return self.evaluatePathOrVar(expr)
if type == "not":
return not self.evaluate(expr)
if type == "exists":
return self.locals.has_key(expr) or self.globals.has_key(expr)
if type == "python":
try:
return eval(expr, self.globals, self.locals)
except:
raise TALESError("evaluation error in %s" % `expr`)
if type == "position":
# Insert the current source file name, line number,
# and column offset.
if self.position:
lineno, offset = self.position
else:
lineno, offset = None, None
return '%s (%s,%s)' % (self.source_file, lineno, offset)
raise TALESError("unrecognized expression: " + `expression`)
def evaluatePathOrVar(self, expr):
expr = expr.strip()
if self.locals.has_key(expr):
return self.locals[expr]
elif self.globals.has_key(expr):
return self.globals[expr]
else:
raise TALESError("unknown variable: %s" % `expr`)
def evaluateValue(self, expr):
return self.evaluate(expr)
def evaluateBoolean(self, expr):
return self.evaluate(expr)
def evaluateText(self, expr):
text = self.evaluate(expr)
if text is not None and text is not Default:
text = ustr(text)
return text
def evaluateStructure(self, expr):
# XXX Should return None or a DOM tree
return self.evaluate(expr)
def evaluateSequence(self, expr):
# XXX Should return a sequence
return self.evaluate(expr)
def evaluateMacro(self, macroName):
assert (macroName.startswith("$") and macroName.endswith("$"),
macroName)
macroName = macroName[1:-1]
file, localName = self.findMacroFile(macroName)
if not file:
# Local macro
macro = self.macros[localName]
else:
# External macro
import driver
program, macros = driver.compilefile(file)
macro = macros.get(localName)
if not macro:
raise TALESError("macro %s not found in file %s" %
(localName, file))
return macro
def findMacroDocument(self, macroName):
file, localName = self.findMacroFile(macroName)
if not file:
return file, localName
import driver
doc = driver.parsefile(file)
return doc, localName
def findMacroFile(self, macroName):
if not macroName:
raise TALESError("empty macro name")
i = macroName.rfind('/')
if i < 0:
# No slash -- must be a locally defined macro
return None, macroName
else:
# Up to last slash is the filename
fileName = macroName[:i]
localName = macroName[i+1:]
return fileName, localName
def setRepeat(self, name, expr):
seq = self.evaluateSequence(expr)
return Iterator(name, seq, self)
def createErrorInfo(self, err, position):
return ErrorInfo(err, position)
def getDefault(self):
return Default
def translate(self, domain, msgid, mapping, default=None):
return self.translationService.translate(domain, msgid, mapping,
default=default)
class Iterator:
# This is not an implementation of a Python iterator. The next()
# method returns true or false to indicate whether another item is
# available; if there is another item, the iterator instance calls
# setLocal() on the evaluation engine passed to the constructor.
def __init__(self, name, seq, engine):
self.name = name
self.seq = seq
self.engine = engine
self.nextIndex = 0
def next(self):
i = self.nextIndex
try:
item = self.seq[i]
except IndexError:
return 0
self.nextIndex = i+1
self.engine.setLocal(self.name, item)
return 1
class DummyDomain:
def translate(self, msgid, mapping=None, context=None,
target_language=None, default=None):
# This is a fake translation service which simply uppercases non
# ${name} placeholder text in the message id.
#
# First, transform a string with ${name} placeholders into a list of
# substrings. Then upcase everything but the placeholders, then glue
# things back together.
# simulate an unknown msgid by returning None
text = msgid
if msgid == "don't translate me":
if default is not None:
text = default
else:
text = msgid.upper()
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.dummyengine', '2.12')
def repl(m, mapping=mapping):
return ustr(mapping[m.group(m.lastindex).lower()])
cre = re.compile(r'\$(?:(%s)|\{(%s)\})' % (NAME_RE, NAME_RE))
return cre.sub(repl, text)
from zope.tal.dummyengine import DummyTranslationDomain as DummyDomain
class DummyTranslationService:
......
This diff is collapsed.
"""Interface that a TALES engine provides to the METAL/TAL implementation."""
try:
from Interface import Interface
from Interface.Attribute import Attribute
except:
# Before 2.7
class Interface: pass
def Attribute(*args): pass
import zope.deferredimport
zope.deferredimport.deprecatedFrom(
"The TAL implementation has moved to zope.tal. Import expression "
"interfaces from zope.tal.interfaces. The old references will be "
"gone in Zope 2.12.",
'zope.tal.interfaces'
'ITALExpressionCompiler', 'ITALExpressionEngine', 'ITALExpressionErrorInfo'
)
class ITALESCompiler(Interface):
"""Compile-time interface provided by a TALES implementation.
The TAL compiler needs an instance of this interface to support
compilation of TALES expressions embedded in documents containing
TAL and METAL constructs.
"""
def getCompilerError():
"""Return the exception class raised for compilation errors.
"""
def compile(expression):
"""Return a compiled form of 'expression' for later evaluation.
'expression' is the source text of the expression.
The return value may be passed to the various evaluate*()
methods of the ITALESEngine interface. No compatibility is
required for the values of the compiled expression between
different ITALESEngine implementations.
"""
class ITALESEngine(Interface):
"""Render-time interface provided by a TALES implementation.
The TAL interpreter uses this interface to TALES to support
evaluation of the compiled expressions returned by
ITALESCompiler.compile().
"""
def getCompiler():
"""Return an object that supports ITALESCompiler."""
def getDefault():
"""Return the value of the 'default' TALES expression.
Checking a value for a match with 'default' should be done
using the 'is' operator in Python.
"""
def setPosition((lineno, offset)):
"""Inform the engine of the current position in the source file.
This is used to allow the evaluation engine to report
execution errors so that site developers can more easily
locate the offending expression.
"""
def setSourceFile(filename):
"""Inform the engine of the name of the current source file.
This is used to allow the evaluation engine to report
execution errors so that site developers can more easily
locate the offending expression.
"""
def beginScope():
"""Push a new scope onto the stack of open scopes.
"""
def endScope():
"""Pop one scope from the stack of open scopes.
"""
def evaluate(compiled_expression):
"""Evaluate an arbitrary expression.
No constraints are imposed on the return value.
"""
def evaluateBoolean(compiled_expression):
"""Evaluate an expression that must return a Boolean value.
"""
def evaluateMacro(compiled_expression):
"""Evaluate an expression that must return a macro program.
"""
def evaluateStructure(compiled_expression):
"""Evaluate an expression that must return a structured
document fragment.
The result of evaluating 'compiled_expression' must be a
string containing a parsable HTML or XML fragment. Any TAL
markup cnotained in the result string will be interpreted.
"""
def evaluateText(compiled_expression):
"""Evaluate an expression that must return text.
The returned text should be suitable for direct inclusion in
the output: any HTML or XML escaping or quoting is the
responsibility of the expression itself.
"""
def evaluateValue(compiled_expression):
"""Evaluate an arbitrary expression.
No constraints are imposed on the return value.
"""
def createErrorInfo(exception, (lineno, offset)):
"""Returns an ITALESErrorInfo object.
The returned object is used to provide information about the
error condition for the on-error handler.
"""
def setGlobal(name, value):
"""Set a global variable.
The variable will be named 'name' and have the value 'value'.
"""
def setLocal(name, value):
"""Set a local variable in the current scope.
The variable will be named 'name' and have the value 'value'.
"""
def setRepeat(name, compiled_expression):
"""
"""
def translate(domain, msgid, mapping, default=None):
"""
See ITranslationService.translate()
"""
class ITALESErrorInfo(Interface):
type = Attribute("type",
"The exception class.")
value = Attribute("value",
"The exception instance.")
lineno = Attribute("lineno",
"The line number the error occurred on in the source.")
offset = Attribute("offset",
"The character offset at which the error occurred.")
......@@ -13,179 +13,16 @@
##############################################################################
"""
Common definitions used by TAL and METAL compilation an transformation.
"""
from types import ListType, TupleType
from ITALES import ITALESErrorInfo
TAL_VERSION = "1.5"
XML_NS = "http://www.w3.org/XML/1998/namespace" # URI for XML namespace
XMLNS_NS = "http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
ZOPE_TAL_NS = "http://xml.zope.org/namespaces/tal"
ZOPE_METAL_NS = "http://xml.zope.org/namespaces/metal"
ZOPE_I18N_NS = "http://xml.zope.org/namespaces/i18n"
# This RE must exactly match the expression of the same name in the
# zope.i18n.simpletranslationservice module:
NAME_RE = "[a-zA-Z_][-a-zA-Z0-9_]*"
KNOWN_METAL_ATTRIBUTES = [
"define-macro",
"use-macro",
"define-slot",
"fill-slot",
"slot",
]
KNOWN_TAL_ATTRIBUTES = [
"define",
"condition",
"content",
"replace",
"repeat",
"attributes",
"on-error",
"omit-tag",
"tal tag",
]
KNOWN_I18N_ATTRIBUTES = [
"translate",
"domain",
"target",
"source",
"attributes",
"data",
"name",
]
class TALError(Exception):
def __init__(self, msg, position=(None, None)):
assert msg != ""
self.msg = msg
self.lineno = position[0]
self.offset = position[1]
self.filename = None
def setFile(self, filename):
self.filename = filename
def __str__(self):
result = self.msg
if self.lineno is not None:
result = result + ", at line %d" % self.lineno
if self.offset is not None:
result = result + ", column %d" % (self.offset + 1)
if self.filename is not None:
result = result + ', in file %s' % self.filename
return result
class METALError(TALError):
pass
class TALESError(TALError):
pass
class I18NError(TALError):
pass
class ErrorInfo:
__implements__ = ITALESErrorInfo
def __init__(self, err, position=(None, None)):
if isinstance(err, Exception):
self.type = err.__class__
self.value = err
else:
self.type = err
self.value = None
self.lineno = position[0]
self.offset = position[1]
import re
_attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S)
_subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S)
del re
def parseAttributeReplacements(arg, xml):
dict = {}
for part in splitParts(arg):
m = _attr_re.match(part)
if not m:
raise TALError("Bad syntax in attributes: " + `part`)
name, expr = m.group(1, 2)
if not xml:
name = name.lower()
if dict.has_key(name):
raise TALError("Duplicate attribute name in attributes: " + `part`)
dict[name] = expr
return dict
def parseSubstitution(arg, position=(None, None)):
m = _subst_re.match(arg)
if not m:
raise TALError("Bad syntax in substitution text: " + `arg`, position)
key, expr = m.group(1, 2)
if not key:
key = "text"
return key, expr
def splitParts(arg):
# Break in pieces at undoubled semicolons and
# change double semicolons to singles:
arg = arg.replace(";;", "\0")
parts = arg.split(';')
parts = [p.replace("\0", ";") for p in parts]
if len(parts) > 1 and not parts[-1].strip():
del parts[-1] # It ended in a semicolon
return parts
def isCurrentVersion(program):
version = getProgramVersion(program)
return version == TAL_VERSION
def getProgramMode(program):
version = getProgramVersion(program)
if (version == TAL_VERSION and isinstance(program[1], TupleType) and
len(program[1]) == 2):
opcode, mode = program[1]
if opcode == "mode":
return mode
return None
def getProgramVersion(program):
if (len(program) >= 2 and
isinstance(program[0], TupleType) and len(program[0]) == 2):
opcode, version = program[0]
if opcode == "version":
return version
return None
import re
_ent1_re = re.compile('&(?![A-Z#])', re.I)
_entch_re = re.compile('&([A-Z][A-Z0-9]*)(?![A-Z0-9;])', re.I)
_entn1_re = re.compile('&#(?![0-9X])', re.I)
_entnx_re = re.compile('&(#X[A-F0-9]*)(?![A-F0-9;])', re.I)
_entnd_re = re.compile('&(#[0-9][0-9]*)(?![0-9;])')
del re
def attrEscape(s):
"""Replace special characters '&<>' by character entities,
except when '&' already begins a syntactically valid entity."""
s = _ent1_re.sub('&amp;', s)
s = _entch_re.sub(r'&amp;\1', s)
s = _entn1_re.sub('&amp;#', s)
s = _entnx_re.sub(r'&amp;\1', s)
s = _entnd_re.sub(r'&amp;\1', s)
s = s.replace('<', '&lt;')
s = s.replace('>', '&gt;')
s = s.replace('"', '&quot;')
return s
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.taldefs', '2.12')
import zope.deferredimport
zope.deferredimport.deprecated(
"TALESError has been renamed TALExpressionError and should be "
"imported from zope.tal.taldefs. This reference will be gone in "
"Zope 2.12.",
TALESError = 'zope.tal.taldefs.TALExpressionError'
)
This diff is collapsed.
This diff is collapsed.
......@@ -13,131 +13,8 @@
##############################################################################
"""
Parse XML and compile to TALInterpreter intermediate code.
"""
from XMLParser import XMLParser
from TALDefs import XML_NS, ZOPE_I18N_NS, ZOPE_METAL_NS, ZOPE_TAL_NS
from TALGenerator import TALGenerator
class TALParser(XMLParser):
ordered_attributes = 1
def __init__(self, gen=None): # Override
XMLParser.__init__(self)
if gen is None:
gen = TALGenerator()
self.gen = gen
self.nsStack = []
self.nsDict = {XML_NS: 'xml'}
self.nsNew = []
def getCode(self):
return self.gen.getCode()
def getWarnings(self):
return ()
def StartNamespaceDeclHandler(self, prefix, uri):
self.nsStack.append(self.nsDict.copy())
self.nsDict[uri] = prefix
self.nsNew.append((prefix, uri))
def EndNamespaceDeclHandler(self, prefix):
self.nsDict = self.nsStack.pop()
def StartElementHandler(self, name, attrs):
if self.ordered_attributes:
# attrs is a list of alternating names and values
attrlist = []
for i in range(0, len(attrs), 2):
key = attrs[i]
value = attrs[i+1]
attrlist.append((key, value))
else:
# attrs is a dict of {name: value}
attrlist = attrs.items()
attrlist.sort() # For definiteness
name, attrlist, taldict, metaldict, i18ndict \
= self.process_ns(name, attrlist)
attrlist = self.xmlnsattrs() + attrlist
self.gen.emitStartElement(name, attrlist, taldict, metaldict, i18ndict)
def process_ns(self, name, attrlist):
taldict = {}
metaldict = {}
i18ndict = {}
fixedattrlist = []
name, namebase, namens = self.fixname(name)
for key, value in attrlist:
key, keybase, keyns = self.fixname(key)
ns = keyns or namens # default to tag namespace
item = key, value
if ns == 'metal':
metaldict[keybase] = value
item = item + ("metal",)
elif ns == 'tal':
taldict[keybase] = value
item = item + ("tal",)
elif ns == 'i18n':
i18ndict[keybase] = value
item = item + ('i18n',)
fixedattrlist.append(item)
if namens in ('metal', 'tal', 'i18n'):
taldict['tal tag'] = namens
return name, fixedattrlist, taldict, metaldict, i18ndict
def xmlnsattrs(self):
newlist = []
for prefix, uri in self.nsNew:
if prefix:
key = "xmlns:" + prefix
else:
key = "xmlns"
if uri in (ZOPE_METAL_NS, ZOPE_TAL_NS, ZOPE_I18N_NS):
item = (key, uri, "xmlns")
else:
item = (key, uri)
newlist.append(item)
self.nsNew = []
return newlist
def fixname(self, name):
if ' ' in name:
uri, name = name.split(' ')
prefix = self.nsDict[uri]
prefixed = name
if prefix:
prefixed = "%s:%s" % (prefix, name)
ns = 'x'
if uri == ZOPE_TAL_NS:
ns = 'tal'
elif uri == ZOPE_METAL_NS:
ns = 'metal'
elif uri == ZOPE_I18N_NS:
ns = 'i18n'
return (prefixed, name, ns)
return (name, name, None)
def EndElementHandler(self, name):
name = self.fixname(name)[0]
self.gen.emitEndElement(name)
def DefaultHandler(self, text):
self.gen.emitRawText(text)
def test():
import sys
p = TALParser()
file = "tests/input/test01.xml"
if sys.argv[1:]:
file = sys.argv[1]
p.parseFile(file)
program, macros = p.getCode()
from TALInterpreter import TALInterpreter
from DummyEngine import DummyEngine
engine = DummyEngine(macros)
TALInterpreter(program, macros, engine, sys.stdout, wrap=0)()
if __name__ == "__main__":
test()
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.talparser', '2.12')
......@@ -13,29 +13,9 @@
##############################################################################
"""Translation context object for the TALInterpreter's I18N support.
The translation context provides a container for the information
needed to perform translation of a marked string from a page template.
BBB 2005/05/01 -- to be removed after 12 months
$Id$
"""
DEFAULT_DOMAIN = "default"
class TranslationContext:
"""Information about the I18N settings of a TAL processor."""
def __init__(self, parent=None, domain=None, target=None, source=None):
if parent:
if not domain:
domain = parent.domain
if not target:
target = parent.target
if not source:
source = parent.source
elif domain is None:
domain = DEFAULT_DOMAIN
self.parent = parent
self.domain = domain
self.target = target
self.source = source
import zope.deprecation
zope.deprecation.moved('zope.tal.translationcontext', '2.12')
......@@ -13,75 +13,11 @@
##############################################################################
"""
Generic expat-based XML parser base class.
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.xmlparser', '2.12')
import xml.parsers.expat
from logging import getLogger
LOG = getLogger('TAL')
XMLParseError = xml.parsers.expat.ExpatError
class XMLParser:
ordered_attributes = 0
handler_names = [
"StartElementHandler",
"EndElementHandler",
"ProcessingInstructionHandler",
"CharacterDataHandler",
"UnparsedEntityDeclHandler",
"NotationDeclHandler",
"StartNamespaceDeclHandler",
"EndNamespaceDeclHandler",
"CommentHandler",
"StartCdataSectionHandler",
"EndCdataSectionHandler",
"DefaultHandler",
"DefaultHandlerExpand",
"NotStandaloneHandler",
"ExternalEntityRefHandler",
"XmlDeclHandler",
"StartDoctypeDeclHandler",
"EndDoctypeDeclHandler",
"ElementDeclHandler",
"AttlistDeclHandler"
]
def __init__(self, encoding=None):
self.parser = p = self.createParser()
if self.ordered_attributes:
try:
self.parser.ordered_attributes = self.ordered_attributes
except AttributeError:
LOG.info("Can't set ordered_attributes")
self.ordered_attributes = 0
for name in self.handler_names:
method = getattr(self, name, None)
if method is not None:
try:
setattr(p, name, method)
except AttributeError:
LOG.error("Can't set expat handler %s" % name)
def createParser(self, encoding=None):
return xml.parsers.expat.ParserCreate(encoding, ' ')
def parseFile(self, filename):
self.parseStream(open(filename))
def parseString(self, s):
self.parser.Parse(s, 1)
def parseURL(self, url):
import urllib
self.parseStream(urllib.urlopen(url))
def parseStream(self, stream):
self.parser.ParseFile(stream)
def parseFragment(self, s, end=0):
self.parser.Parse(s, end)
......@@ -34,165 +34,11 @@ Options:
Leave TAL/METAL attributes in output
-i
Leave I18N substitution strings un-interpolated.
"""
import os
import sys
import getopt
if __name__ == "__main__":
import setpath # Local hack to tweak sys.path etc.
# Import local classes
import TALDefs
from DummyEngine import DummyEngine
from DummyEngine import DummyTranslationService
FILE = "tests/input/test01.xml"
class TestTranslations(DummyTranslationService):
def translate(self, domain, msgid, mapping=None, context=None,
target_language=None, default=None):
if msgid == 'timefmt':
return '%(minutes)s minutes after %(hours)s %(ampm)s' % mapping
elif msgid == 'jobnum':
return '%(jobnum)s is the JOB NUMBER' % mapping
elif msgid == 'verify':
s = 'Your contact email address is recorded as %(email)s'
return s % mapping
elif msgid == 'mailto:${request/submitter}':
return 'mailto:bperson@dom.ain'
elif msgid == 'origin':
return '%(name)s was born in %(country)s' % mapping
return DummyTranslationService.translate(self, domain, msgid,
mapping, context,
target_language,
default=default)
class TestEngine(DummyEngine):
def __init__(self, macros=None):
DummyEngine.__init__(self, macros)
self.translationService = TestTranslations()
def evaluatePathOrVar(self, expr):
if expr == 'here/currentTime':
return {'hours' : 6,
'minutes': 59,
'ampm' : 'PM',
}
elif expr == 'context/@@object_name':
return '7'
elif expr == 'request/submitter':
return 'aperson@dom.ain'
return DummyEngine.evaluatePathOrVar(self, expr)
# This is a disgusting hack so that we can use engines that actually know
# something about certain object paths. TimeEngine knows about
# here/currentTime.
ENGINES = {'test23.html': TestEngine,
'test24.html': TestEngine,
'test26.html': TestEngine,
'test27.html': TestEngine,
'test28.html': TestEngine,
'test29.html': TestEngine,
'test30.html': TestEngine,
'test31.html': TestEngine,
'test32.html': TestEngine,
}
def usage(code, msg=''):
# Python 2.1 required
print >> sys.stderr, __doc__
if msg:
print >> sys.stderr, msg
sys.exit(code)
def main():
macros = 0
mode = None
showcode = 0
showtal = -1
strictinsert = 1
i18nInterpolate = 1
try:
opts, args = getopt.getopt(sys.argv[1:], "hHxlmsti",
['help', 'html', 'xml'])
except getopt.error, msg:
usage(2, msg)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
if opt in ('-H', '--html'):
if mode == 'xml':
usage(1, '--html and --xml are mutually exclusive')
mode = "html"
if opt == '-l':
strictinsert = 0
if opt == '-m':
macros = 1
if opt == '-n':
versionTest = 0
if opt in ('-x', '--xml'):
if mode == 'html':
usage(1, '--html and --xml are mutually exclusive')
mode = "xml"
if opt == '-s':
showcode = 1
if opt == '-t':
showtal = 1
if opt == '-i':
i18nInterpolate = 0
if args:
file = args[0]
else:
file = FILE
it = compilefile(file, mode)
if showcode:
showit(it)
else:
# See if we need a special engine for this test
engine = None
engineClass = ENGINES.get(os.path.basename(file))
if engineClass is not None:
engine = engineClass(macros)
interpretit(it, engine=engine,
tal=(not macros), showtal=showtal,
strictinsert=strictinsert,
i18nInterpolate=i18nInterpolate)
def interpretit(it, engine=None, stream=None, tal=1, showtal=-1,
strictinsert=1, i18nInterpolate=1):
from TALInterpreter import TALInterpreter
program, macros = it
assert TALDefs.isCurrentVersion(program)
if engine is None:
engine = DummyEngine(macros)
TALInterpreter(program, macros, engine, stream, wrap=0,
tal=tal, showtal=showtal, strictinsert=strictinsert,
i18nInterpolate=i18nInterpolate)()
def compilefile(file, mode=None):
assert mode in ("html", "xml", None)
if mode is None:
ext = os.path.splitext(file)[1]
if ext.lower() in (".html", ".htm"):
mode = "html"
else:
mode = "xml"
if mode == "html":
from HTMLTALParser import HTMLTALParser
p = HTMLTALParser()
else:
from TALParser import TALParser
p = TALParser()
p.parseFile(file)
return p.getCode()
def showit(it):
from pprint import pprint
pprint(it)
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.driver', '2.12')
if __name__ == "__main__":
main()
This diff is collapsed.
......@@ -14,138 +14,11 @@
##############################################################################
"""
Driver program to run METAL and TAL regression tests.
"""
import sys
import os
from cStringIO import StringIO
import glob
import traceback
if __name__ == "__main__":
import setpath # Local hack to tweak sys.path etc.
import driver
import tests.utils
def showdiff(a, b):
import ndiff
cruncher = ndiff.SequenceMatcher(ndiff.IS_LINE_JUNK, a, b)
for tag, alo, ahi, blo, bhi in cruncher.get_opcodes():
if tag == "equal":
continue
print nicerange(alo, ahi) + tag[0] + nicerange(blo, bhi)
ndiff.dump('<', a, alo, ahi)
if a and b:
print '---'
ndiff.dump('>', b, blo, bhi)
def nicerange(lo, hi):
if hi <= lo+1:
return str(lo+1)
else:
return "%d,%d" % (lo+1, hi)
def main():
opts = []
args = sys.argv[1:]
quiet = 0
unittesting = 0
if args and args[0] == "-q":
quiet = 1
del args[0]
if args and args[0] == "-Q":
unittesting = 1
del args[0]
while args and args[0].startswith('-'):
opts.append(args[0])
del args[0]
if not args:
prefix = os.path.join("tests", "input", "test*.")
if tests.utils.skipxml:
xmlargs = []
else:
xmlargs = glob.glob(prefix + "xml")
xmlargs.sort()
htmlargs = glob.glob(prefix + "html")
htmlargs.sort()
args = xmlargs + htmlargs
if not args:
sys.stderr.write("No tests found -- please supply filenames\n")
sys.exit(1)
errors = 0
for arg in args:
locopts = []
if arg.find("metal") >= 0 and "-m" not in opts:
locopts.append("-m")
if not unittesting:
print arg,
sys.stdout.flush()
if tests.utils.skipxml and arg.endswith(".xml"):
print "SKIPPED (XML parser not available)"
continue
save = sys.stdout, sys.argv
try:
try:
sys.stdout = stdout = StringIO()
sys.argv = [""] + opts + locopts + [arg]
driver.main()
finally:
sys.stdout, sys.argv = save
except SystemExit:
raise
except:
errors = 1
if quiet:
print sys.exc_type
sys.stdout.flush()
else:
if unittesting:
print
else:
print "Failed:"
sys.stdout.flush()
traceback.print_exc()
continue
head, tail = os.path.split(arg)
outfile = os.path.join(
head.replace("input", "output"),
tail)
try:
f = open(outfile)
except IOError:
expected = None
print "(missing file %s)" % outfile,
else:
expected = f.readlines()
f.close()
stdout.seek(0)
if hasattr(stdout, "readlines"):
actual = stdout.readlines()
else:
actual = readlines(stdout)
if actual == expected:
if not unittesting:
print "OK"
else:
if unittesting:
print
else:
print "not OK"
errors = 1
if not quiet and expected is not None:
showdiff(expected, actual)
if errors:
sys.exit(1)
def readlines(f):
L = []
while 1:
line = f.readline()
if not line:
break
L.append(line)
return L
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.runtest', '2.12')
if __name__ == "__main__":
main()
#!/usr/bin/env python
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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.
#
##############################################################################
"""Program to extract internationalization markup from Page Templates.
Once you have marked up a Page Template file with i18n: namespace tags, use
this program to extract GNU gettext .po file entries.
Usage: talgettext.py [options] files
Options:
-h / --help
Print this message and exit.
-o / --output <file>
Output the translation .po file to <file>.
-u / --update <file>
Update the existing translation <file> with any new translation strings
found.
"""
import sys
import time
import getopt
import traceback
from TAL.HTMLTALParser import HTMLTALParser
from TAL.TALInterpreter import TALInterpreter
from TAL.DummyEngine import DummyEngine
from ITALES import ITALESEngine
from TAL.TALDefs import TALESError
__version__ = '$Revision: 1.1.2.1 $'
pot_header = '''\
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\\n"
"POT-Creation-Date: %(time)s\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=CHARSET\\n"
"Content-Transfer-Encoding: ENCODING\\n"
"Generated-By: talgettext.py %(version)s\\n"
'''
NLSTR = '"\n"'
try:
True
except NameError:
True=1
False=0
def usage(code, msg=''):
# Python 2.1 required
print >> sys.stderr, __doc__
if msg:
print >> sys.stderr, msg
sys.exit(code)
class POTALInterpreter(TALInterpreter):
def translate(self, msgid, default, i18ndict=None, obj=None):
# XXX is this right?
if i18ndict is None:
i18ndict = {}
if obj:
i18ndict.update(obj)
# XXX Mmmh, it seems that sometimes the msgid is None; is that really
# possible?
if msgid is None:
return None
# XXX We need to pass in one of context or target_language
return self.engine.translate(msgid, self.i18nContext.domain, i18ndict,
position=self.position, default=default)
class POEngine(DummyEngine):
__implements__ = ITALESEngine
def __init__(self, macros=None):
self.catalog = {}
DummyEngine.__init__(self, macros)
def evaluate(*args):
return '' # who cares
def evaluatePathOrVar(*args):
return '' # who cares
def evaluateSequence(self, expr):
return (0,) # dummy
def evaluateBoolean(self, expr):
return True # dummy
def translate(self, msgid, domain=None, mapping=None, default=None,
# XXX position is not part of the ITALESEngine
# interface
position=None):
if domain not in self.catalog:
self.catalog[domain] = {}
domain = self.catalog[domain]
# ---------------------------------------------
# only non-empty msgids are added to dictionary
# (changed by heinrichbernd - 2004/09/07)
# ---------------------------------------------
if msgid:
if msgid not in domain:
domain[msgid] = []
domain[msgid].append((self.file, position))
return 'x'
class UpdatePOEngine(POEngine):
"""A slightly-less braindead POEngine which supports loading an existing
.po file first."""
def __init__ (self, macros=None, filename=None):
POEngine.__init__(self, macros)
self._filename = filename
self._loadFile()
self.base = self.catalog
self.catalog = {}
def __add(self, id, s, fuzzy):
"Add a non-fuzzy translation to the dictionary."
if not fuzzy and str:
# check for multi-line values and munge them appropriately
if '\n' in s:
lines = s.rstrip().split('\n')
s = NLSTR.join(lines)
self.catalog[id] = s
def _loadFile(self):
# shamelessly cribbed from Python's Tools/i18n/msgfmt.py
# 25-Mar-2003 Nathan R. Yergler (nathan@zope.org)
# 14-Apr-2003 Hacked by Barry Warsaw (barry@zope.com)
ID = 1
STR = 2
try:
lines = open(self._filename).readlines()
except IOError, msg:
print >> sys.stderr, msg
sys.exit(1)
section = None
fuzzy = False
# Parse the catalog
lno = 0
for l in lines:
lno += True
# If we get a comment line after a msgstr, this is a new entry
if l[0] == '#' and section == STR:
self.__add(msgid, msgstr, fuzzy)
section = None
fuzzy = False
# Record a fuzzy mark
if l[:2] == '#,' and l.find('fuzzy'):
fuzzy = True
# Skip comments
if l[0] == '#':
continue
# Now we are in a msgid section, output previous section
if l.startswith('msgid'):
if section == STR:
self.__add(msgid, msgstr, fuzzy)
section = ID
l = l[5:]
msgid = msgstr = ''
# Now we are in a msgstr section
elif l.startswith('msgstr'):
section = STR
l = l[6:]
# Skip empty lines
if not l.strip():
continue
# XXX: Does this always follow Python escape semantics?
l = eval(l)
if section == ID:
msgid += l
elif section == STR:
msgstr += '%s\n' % l
else:
print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \
'before:'
print >> sys.stderr, l
sys.exit(1)
# Add last entry
if section == STR:
self.__add(msgid, msgstr, fuzzy)
def evaluate(self, expression):
try:
return POEngine.evaluate(self, expression)
except TALESError:
pass
def evaluatePathOrVar(self, expr):
return 'who cares'
def translate(self, msgid, domain=None, mapping=None, default=None,
position=None):
if msgid not in self.base:
POEngine.translate(self, msgid, domain, mapping, default, position)
return 'x'
def main():
try:
opts, args = getopt.getopt(
sys.argv[1:],
'ho:u:',
['help', 'output=', 'update='])
except getopt.error, msg:
usage(1, msg)
outfile = None
engine = None
update_mode = False
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-o', '--output'):
outfile = arg
elif opt in ('-u', '--update'):
update_mode = True
if outfile is None:
outfile = arg
engine = UpdatePOEngine(filename=arg)
if not args:
print 'nothing to do'
return
# We don't care about the rendered output of the .pt file
class Devnull:
def write(self, s):
pass
# check if we've already instantiated an engine;
# if not, use the stupidest one available
if not engine:
engine = POEngine()
# process each file specified
for filename in args:
try:
engine.file = filename
p = HTMLTALParser()
p.parseFile(filename)
program, macros = p.getCode()
POTALInterpreter(program, macros, engine, stream=Devnull(),
metal=False)()
except: # Hee hee, I love bare excepts!
print 'There was an error processing', filename
traceback.print_exc()
# Now output the keys in the engine. Write them to a file if --output or
# --update was specified; otherwise use standard out.
if (outfile is None):
outfile = sys.stdout
else:
outfile = file(outfile, update_mode and "a" or "w")
catalog = {}
for domain in engine.catalog.keys():
catalog.update(engine.catalog[domain])
messages = catalog.copy()
try:
messages.update(engine.base)
except AttributeError:
pass
if '' not in messages:
print >> outfile, pot_header % {'time': time.ctime(),
'version': __version__}
msgids = catalog.keys()
# XXX: You should not sort by msgid, but by filename and position. (SR)
msgids.sort()
for msgid in msgids:
positions = catalog[msgid]
for filename, position in positions:
outfile.write('#: %s:%s\n' % (filename, position[0]))
outfile.write('msgid "%s"\n' % msgid)
outfile.write('msgstr ""\n')
outfile.write('\n')
# BBB 2005/05/01 -- to be removed after 12 months
import zope.deprecation
zope.deprecation.moved('zope.tal.talgettext', '2.12')
if __name__ == '__main__':
main()
......@@ -14,44 +14,11 @@
##############################################################################
"""
Helper program to time compilation and interpretation
"""
import sys
import time
import getopt
from cPickle import dumps, loads
from cStringIO import StringIO
from driver import FILE, compilefile, interpretit
def main():
count = 10
try:
opts, args = getopt.getopt(sys.argv[1:], "n:")
except getopt.error, msg:
print msg
sys.exit(2)
for o, a in opts:
if o == "-n":
count = int(a)
if not args:
args = [FILE]
for file in args:
print file
dummyfile = StringIO()
it = timefunc(count, compilefile, file)
timefunc(count, interpretit, it, None, dummyfile)
def timefunc(count, func, *args):
sys.stderr.write("%-14s: " % func.__name__)
sys.stderr.flush()
t0 = time.clock()
for i in range(count):
result = func(*args)
t1 = time.clock()
sys.stderr.write("%6.3f secs for %d calls, i.e. %4.0f msecs per call\n"
% ((t1-t0), count, 1000*(t1-t0)/count))
return result
BBB 2005/05/01 -- to be removed after 12 months
"""
import zope.deprecation
zope.deprecation.moved('zope.tal.timer', '2.12')
if __name__ == "__main__":
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment