Commit 82471624 authored by Philipp von Weitershausen's avatar Philipp von Weitershausen

Merge ajung-zpt-end-game branch.

parents 997aef4e d8a6bbd0
......@@ -18,6 +18,18 @@ Zope Changes
Restructuring
- Products.PageTemplates now uses the Zope 3 ZPT implementation
in zope.pagetemplate.
- The TAL package has been deprecated in favour of the TAL
engine from zope.tal.
- Products.PageTemplates.TALES has been deprecated in favour of
the TALES engine from zope.tales.
- ZTUtils.Iterator has been deprecated in favour of the TALES
iterator implementation in zope.tales.tales.
- ZCatalog: removed manage_deleteIndex(), manage_delColumns()
which were deprecated since Zope 2.4
......
......@@ -10,32 +10,16 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Defer and Lazy expression handler
"""Lazy expression handler
defer expressions can be usesd for a design pattern called deferred evaluation.
Example:
<div tal:define="xis defer:string:x is $x">
<p tal:repeat="x python:range(3)"
tal:content="xis"></p>
</div>
Output:
<div>
<p>x is 0</p>
<p>x is 1</p>
<p>x is 2</p>
</div>
A lazy expressions is implemented in a similar way but has a different result. While
a defer expression is evaluated every time it is used according to its context a lazy
expression is evaluted only the first time it is used. Lazy expression are known
under the name lazy initialization of variables, too.
A common use case for a lazy expression is a lazy binding of a costly expression.
While one could call an expression only when it's required it makes sense to define
it only one time when it could be used multiple times.
A lazy expressions is implemented similarly to the defer expression
but has a different result. While a defer expression is evaluated
every time it is used according to its context a lazy expression is
evaluted only the first time it is used. Lazy expression are known
under the name lazy initialization of variables, too. A common use
case for a lazy expression is a lazy binding of a costly expression.
While one could call an expression only when it's required it makes
sense to define it only one time when it could be used multiple times.
Example
......@@ -45,38 +29,11 @@ Example
<div tal:condition"python: not (foo or bar)">...</div>
</div>
"""
from zope.tales.expressions import DeferWrapper, DeferExpr
_marker = object()
# defer expression
class DeferWrapper:
"""Wrapper for defer: expression
"""
def __init__(self, expr, econtext):
self._expr = expr
self._econtext = econtext
def __str__(self):
return str(self())
def __call__(self):
return self._expr(self._econtext)
class DeferExpr:
"""defer: expression handler for deferred evaluation of the context
"""
def __init__(self, name, expr, compiler):
self._s = expr = expr.lstrip()
self._c = compiler.compile(expr)
def __call__(self, econtext):
return DeferWrapper(self._c, econtext)
def __repr__(self):
return 'defer:%s' % `self._s`
# lazy expression
# TODO These should really be integrated into the Zope 3 ZPT
# implementation (zope.tales)
class LazyWrapper(DeferWrapper):
"""Wrapper for lazy: expression
......@@ -99,4 +56,3 @@ class LazyExpr(DeferExpr):
def __repr__(self):
return 'lazy:%s' % `self._s`
......@@ -15,12 +15,11 @@
$Id$
"""
import re
import Products.Five.i18n
from DocumentTemplate.DT_Util import ustr
from TAL.TALDefs import NAME_RE
from zope.tal.taldefs import NAME_RE
class DummyTranslationService:
"""Translation service that doesn't know anything about translation."""
......@@ -30,13 +29,15 @@ class DummyTranslationService:
return ustr(mapping[m.group(m.lastindex)])
cre = re.compile(r'\$(?:(%s)|\{(%s)\})' % (NAME_RE, NAME_RE))
return cre.sub(repl, default or msgid)
# XXX Not all of Zope2.I18n.ITranslationService is implemented.
#
# As of Five 1.1, we're by default using Zope 3 Message Catalogs for
# translation, but we allow fallback translation services such as PTS
# and Localizer
#
# TODO We should really deprecate Zope2-style translation service and
# only support Zope3-style i18n in the future.
#
Products.Five.i18n._fallback_translation_service = DummyTranslationService()
fiveTranslationService = Products.Five.i18n.FiveTranslationService()
......
......@@ -12,65 +12,47 @@
##############################################################################
"""Page Template module
HTML- and XML-based template objects using TAL, TALES, and METAL.
$Id$
"""
import sys
import ExtensionClass
import zope.pagetemplate.pagetemplate
from zope.pagetemplate.pagetemplate import _error_start, PTRuntimeError
from zope.pagetemplate.pagetemplate import PageTemplateTracebackSupplement
from zope.tales.expressions import SimpleModuleImporter
from Products.PageTemplates.Expressions import getEngine
__version__='$Revision: 1.31 $'[11:-2]
import sys, types
from TAL.TALParser import TALParser
from TAL.HTMLTALParser import HTMLTALParser
from TAL.TALGenerator import TALGenerator
# Do not use cStringIO here! It's not unicode aware. :(
from TAL.TALInterpreter import TALInterpreter, FasterStringIO
from Expressions import getEngine
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 StringIO(self):
# Third-party products wishing to provide a full Unicode-aware
# StringIO can do so by monkey-patching this method.
return FasterStringIO()
##############################################################################
# BBB 2005/05/01 -- to be removed after 12 months
_ModuleImporter = SimpleModuleImporter
ModuleImporter = SimpleModuleImporter()
import zope.deprecation
zope.deprecation.deprecated(
('ModuleImporter', '_ModuleImporter'),
"Zope 2 uses the Zope 3 ZPT engine now. ModuleImporter has moved "
"to zope.pagetemplate.pagetemplate.SimpleModuleImporter (this is a "
"class, not an instance)."
)
zope.deprecation.deprecated(
('PTRuntimeError', 'PageTemplateTracebackSupplement'),
"Zope 2 uses the Zope 3 ZPT engine now. The object you're importing "
"has moved to zope.pagetemplate.pagetemplate. This reference will "
"be gone in Zope 2.12.",
)
##############################################################################
def macros(self):
return self.pt_macros()
macros = ComputedAttribute(macros, 1)
class PageTemplate(ExtensionClass.Base,
zope.pagetemplate.pagetemplate.PageTemplate):
def pt_edit(self, text, content_type):
if content_type:
self.content_type = str(content_type)
if hasattr(text, 'read'):
text = text.read()
charset = getattr(self, 'management_page_charset', None)
if charset and type(text) == types.StringType:
try:
unicode(text,'us-ascii')
except UnicodeDecodeError:
text = unicode(text, charset)
self.write(text)
def pt_getEngine(self):
return getEngine()
def pt_getContext(self):
c = {'template': self,
'options': {},
'nothing': None,
'request': None,
'modules': ModuleImporter,
'modules': SimpleModuleImporter(),
}
parent = getattr(self, 'aq_parent', None)
if parent is not None:
......@@ -83,73 +65,43 @@ class PageTemplate(Base):
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)
@property
def macros(self):
return self.pt_macros()
# sub classes may override this to do additional stuff for macro access
def pt_macros(self):
self._cook_check()
if self._v_errors:
e = str(self._v_errors)
__traceback_supplement__ = (PageTemplateTracebackSupplement, self, {})
raise PTRuntimeError, (
'Page Template %s has errors: %s' % (self.id, e))
output = self.StringIO()
c = self.pt_getContext()
c.update(extra_context)
'Page Template %s has errors: %s' % (
self.id, self._v_errors
))
return self._v_macros
TALInterpreter(self._v_program, self._v_macros,
getEngine().getContext(c),
output,
tal=not source, strictinsert=0)()
return output.getvalue()
# these methods are reimplemented or duplicated here because of
# different call signatures in the Zope 2 world
def __call__(self, *args, **kwargs):
if not kwargs.has_key('args'):
kwargs['args'] = args
return self.pt_render(extra_context={'options': kwargs})
def pt_render(self, source=False, extra_context={}):
c = self.pt_getContext()
c.update(extra_context)
return super(PageTemplate, self).pt_render(c, source=source)
def pt_errors(self):
if not self._v_cooked:
self._cook()
def pt_errors(self, namespace={}):
self._cook_check()
err = self._v_errors
if err:
return err
if not self.expand: return
try:
self.pt_render(source=1)
self.pt_render(source=True, extra_context=namespace)
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: %s' % (
self.id,
self._v_errors
))
return self._v_macros
def pt_source_file(self):
return None # Unknown.
def write(self, text):
assert type(text) in types.StringTypes
if text[:len(self._error_start)] == self._error_start:
errend = text.find('-->')
if errend >= 0:
text = text[errend + 4:]
if self._text != text:
self._text = text
self._cook()
def __call__(self, *args, **kwargs):
if not kwargs.has_key('args'):
kwargs['args'] = args
return self.pt_render(extra_context={'options': kwargs})
def read(self):
self._cook_check()
......@@ -157,71 +109,21 @@ class PageTemplate(Base):
if not self.expand:
return self._text
try:
return self.pt_render(source=1)
return self.pt_render(source=True)
except:
return ('%s\n Macro expansion failed\n %s\n-->\n%s' %
(self._error_start, "%s: %s" % sys.exc_info()[:2],
(_error_start, "%s: %s" % sys.exc_info()[:2],
self._text) )
return ('%s\n %s\n-->\n%s' % (self._error_start,
return ('%s\n %s\n-->\n%s' % (_error_start,
'\n '.join(self._v_errors),
self._text))
def _cook_check(self):
if not self._v_cooked:
self._cook()
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
# convenience method for the ZMI which allows to explicitly
# specify the HTMLness of a template. The old Zope 2
# implementation had this as well, but arguably on the wrong class
# (this should be a ZopePageTemplate thing if at all)
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 = module.split('.')
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
......@@ -10,32 +10,35 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Filesystem Page Template module
Zope object encapsulating a Page Template from the filesystem.
"""
__version__ = '$Revision: 1.30 $'[11:-2]
import os, AccessControl
import os
from logging import getLogger
from Globals import package_home, DevelopmentMode
import AccessControl
from Globals import package_home, InitializeClass, DevelopmentMode
from App.config import getConfiguration
from Acquisition import aq_parent, aq_inner
from ComputedAttribute import ComputedAttribute
from OFS.SimpleItem import SimpleItem
from OFS.Traversable import Traversable
from Shared.DC.Scripts.Script import Script
from Shared.DC.Scripts.Signature import FuncCode
from AccessControl import getSecurityManager
from OFS.Traversable import Traversable
from PageTemplate import PageTemplate
from Expressions import SecureModuleImporter
from ComputedAttribute import ComputedAttribute
from Acquisition import aq_parent, aq_inner
from App.config import getConfiguration
from OFS.SimpleItem import Item_w__name__
from Products.PageTemplates.Expressions import SecureModuleImporter
from Products.PageTemplates.PageTemplate import PageTemplate
from zope.contenttype import guess_content_type
from zope.pagetemplate.pagetemplatefile import sniff_type
LOG = getLogger('PageTemplateFile')
class PageTemplateFile(Item_w__name__, Script, PageTemplate, Traversable):
"Zope wrapper for filesystem Page Template using TAL, TALES, and METAL"
def guess_type(filename, text):
content_type, dummy = guess_content_type(filename, text)
if content_type in ('text/html', 'text/xml'):
return content_type
return sniff_type(text) or 'text/html'
class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
"""Zope 2 implementation of a PageTemplate loaded from a file."""
meta_type = 'Page Template (File)'
......@@ -53,29 +56,35 @@ class PageTemplateFile(Item_w__name__, Script, PageTemplate, Traversable):
security.declareProtected('View management screens',
'read', 'document_src')
_default_bindings = {'name_subpath': 'traverse_subpath'}
def __init__(self, filename, _prefix=None, **kw):
self.ZBindings_edit(self._default_bindings)
if _prefix is None:
_prefix = getConfiguration().softwarehome
elif not isinstance(_prefix, str):
_prefix = package_home(_prefix)
name = kw.get('__name__')
name = None
if kw.has_key('__name__'):
name = kw['__name__']
del kw['__name__']
basepath, ext = os.path.splitext(filename)
if name:
self._need__name__ = 0
self.__name__ = name
self.id = self.__name__ = name
else:
self.__name__ = os.path.basename(basepath)
self.id = self.__name__ = os.path.basename(basepath)
if _prefix:
if isinstance(_prefix, str):
filename = os.path.join(_prefix, filename)
else:
filename = os.path.join(package_home(_prefix), filename)
if not ext:
# XXX This is pretty bogus, but can't be removed since
# it's been released this way.
filename = filename + '.zpt'
self.filename = os.path.join(_prefix, filename)
def getId(self):
"""return the ID of this object"""
return self.__name__
self.filename = filename
content = open(filename).read()
self.pt_edit( content, guess_type(filename, content))
def pt_getContext(self):
root = self.getPhysicalRoot()
context = self._getContext()
......@@ -106,10 +115,13 @@ class PageTemplateFile(Item_w__name__, Script, PageTemplate, Traversable):
pass
# Execute the template in a new security context.
security = getSecurityManager()
security = AccessControl.getSecurityManager()
bound_names['user'] = security.getUser()
security.addContext(self)
try:
context = self.pt_getContext()
context.update(bound_names)
return self.pt_render(extra_context=bound_names)
finally:
security.removeContext(self)
......@@ -187,6 +199,7 @@ class PageTemplateFile(Item_w__name__, Script, PageTemplate, Traversable):
raise StorageError, ("Instance of AntiPersistent class %s "
"cannot be stored." % self.__class__.__name__)
InitializeClass(PageTemplateFile)
XML_PREFIXES = [
"<?xml", # ascii, utf-8
......
......@@ -10,37 +10,16 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Path Iterator
A TALES Iterator with the ability to use first() and last() on
subpaths of elements.
"""
__version__='$Revision: 1.4 $'[11:-2]
BBB 2005/05/01 -- to be removed after 12 months
import TALES
from Expressions import restrictedTraverse, Undefs, getSecurityManager
class Iterator(TALES.Iterator):
def __bobo_traverse__(self, REQUEST, name):
if name in ('first', 'last'):
path = REQUEST['TraversalRequestNameStack']
names = list(path)
names.reverse()
path[:] = [tuple(names)]
return getattr(self, name)
def same_part(self, name, ob1, ob2):
if name is None:
return ob1 == ob2
if isinstance(name, type('')):
name = name.split('/')
name = filter(None, name)
securityManager = getSecurityManager()
try:
ob1 = restrictedTraverse(ob1, name, securityManager)
ob2 = restrictedTraverse(ob2, name, securityManager)
except Undefs:
return 0
return ob1 == ob2
$Id$
"""
import zope.deferredimport
zope.deferredimport.deprecated(
"It has been renamed to PathIterator and moved to the "
"Products.PageTemplates.Expressions module. This reference will be "
"gone in Zope 2.12.",
PathIterator = "Products.PageTemplates.Expressions:PathIterator"
)
......@@ -10,77 +10,10 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Generic Python Expression Handler
"""
__version__='$Revision: 1.13 $'[11:-2]
from TALES import CompilerError
from sys import exc_info
from DeferExpr import DeferWrapper
class getSecurityManager:
'''Null security manager'''
def validate(self, *args, **kwargs):
return 1
addContext = removeContext = validate
class PythonExpr:
def __init__(self, name, expr, engine):
self.expr = expr = expr.strip().replace('\n', ' ')
try:
d = {}
exec 'def f():\n return %s\n' % expr.strip() in d
self._f = d['f']
except:
raise CompilerError, ('Python expression error:\n'
'%s: %s') % exc_info()[:2]
self._get_used_names()
def _get_used_names(self):
self._f_varnames = vnames = []
for vname in self._f.func_code.co_names:
if vname[0] not in '$_':
vnames.append(vname)
def _bind_used_names(self, econtext, _marker=[]):
# Bind template variables
names = {'CONTEXTS': econtext.contexts}
vars = econtext.vars
getType = econtext.getCompiler().getTypes().get
for vname in self._f_varnames:
val = vars.get(vname, _marker)
if val is _marker:
has = val = getType(vname)
if has:
val = ExprTypeProxy(vname, val, econtext)
names[vname] = val
else:
names[vname] = val
for key, val in names.items():
if isinstance(val, DeferWrapper):
names[key] = val()
return names
def __call__(self, econtext):
__traceback_info__ = self.expr
f = self._f
f.func_globals.update(self._bind_used_names(econtext))
return f()
def __str__(self):
return 'Python expression "%s"' % self.expr
def __repr__(self):
return '<PythonExpr %s>' % self.expr
class ExprTypeProxy:
'''Class that proxies access to an expression type handler'''
def __init__(self, name, handler, econtext):
self._name = name
self._handler = handler
self._econtext = econtext
def __call__(self, text):
return self._handler(self._name, text,
self._econtext.getCompiler())(self._econtext)
$Id$
"""
# BBB 2005/05/01 -- remove after 12 months
import zope.deprecation
zope.deprecation.moved("zope.tales.pythonexpr", "2.12")
See <a href="http://dev.zope.org/Wikis/DevSite/Projects/ZPT">the
ZPT project Wiki</a> for more information about Page Templates, or
<a href="http://www.zope.org/Members/4am/ZPT">the download page</a>
for installation instructions and the most recent version of the software.
This Product requires the TAL and ZTUtils packages to be installed in
your Python path (not Products). See the links above for more information.
......@@ -12,40 +12,15 @@
##############################################################################
"""TALES
An implementation of a generic TALES engine
"""
BBB 2005/05/01 -- to be removed after 12 months
__version__='$Revision: 1.39 $'[11:-2]
$Id$
"""
from zope.tales.tests.simpleexpr import SimpleExpr
from zope.tales.tales import ExpressionEngine as Engine
from zope.tales.tales import _default as Default
import re, sys, ZTUtils
from weakref import ref
from MultiMapping import MultiMapping
from DocumentTemplate.DT_Util import ustr
from GlobalTranslationService import getGlobalTranslationService
from zExceptions import Unauthorized
StringType = type('')
NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
_parse_expr = re.compile(r"(%s):" % NAME_RE).match
_valid_name = re.compile('%s$' % NAME_RE).match
class TALESError(Exception):
"""Error during TALES expression evaluation"""
class Undefined(TALESError):
'''Exception raised on traversal of an undefined path'''
class RegistrationError(Exception):
'''TALES Type Registration Error'''
class CompilerError(Exception):
'''TALES Compiler Error'''
class Default:
'''Retain Default'''
Default = Default()
class SafeMapping(MultiMapping):
'''Mapping with security declarations and limited method exposure.
......@@ -60,241 +35,5 @@ class SafeMapping(MultiMapping):
_push = MultiMapping.push
_pop = MultiMapping.pop
class Iterator(ZTUtils.Iterator):
def __init__(self, name, seq, context):
ZTUtils.Iterator.__init__(self, seq)
self.name = name
self._context_ref = ref(context)
def next(self):
if ZTUtils.Iterator.next(self):
context = self._context_ref()
if context is not None:
context.setLocal(self.name, self.item)
return 1
return 0
class ErrorInfo:
"""Information about an exception passed to an on-error handler."""
__allow_access_to_unprotected_subobjects__ = 1
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]
class Engine:
'''Expression Engine
An instance of this class keeps a mutable collection of expression
type handlers. It can compile expression strings by delegating to
these handlers. It can provide an expression Context, which is
capable of holding state and evaluating compiled expressions.
'''
Iterator = Iterator
def __init__(self, Iterator=None):
self.types = {}
if Iterator is not None:
self.Iterator = Iterator
def registerType(self, name, handler):
if not _valid_name(name):
raise RegistrationError, 'Invalid Expression type "%s".' % name
types = self.types
if types.has_key(name):
raise RegistrationError, (
'Multiple registrations for Expression type "%s".' %
name)
types[name] = handler
def getTypes(self):
return self.types
def compile(self, expression):
m = _parse_expr(expression)
if m:
type = m.group(1)
expr = expression[m.end():]
else:
type = "standard"
expr = expression
try:
handler = self.types[type]
except KeyError:
raise CompilerError, (
'Unrecognized expression type "%s".' % type)
return handler(type, expr, self)
def getContext(self, contexts=None, **kwcontexts):
if contexts is not None:
if kwcontexts:
kwcontexts.update(contexts)
else:
kwcontexts = contexts
return Context(self, kwcontexts)
def getCompilerError(self):
return CompilerError
class Context:
'''Expression Context
An instance of this class holds context information that it can
use to evaluate compiled expressions.
'''
_context_class = SafeMapping
position = (None, None)
source_file = None
def __init__(self, compiler, contexts):
self._compiler = compiler
self.contexts = contexts
contexts['nothing'] = None
contexts['default'] = Default
self.repeat_vars = rv = {}
# Wrap this, as it is visible to restricted code
contexts['repeat'] = rep = self._context_class(rv)
contexts['loop'] = rep # alias
self.global_vars = gv = contexts.copy()
self.local_vars = lv = {}
self.vars = self._context_class(gv, lv)
# Keep track of what needs to be popped as each scope ends.
self._scope_stack = []
def getCompiler(self):
return self._compiler
def beginScope(self):
self._scope_stack.append([self.local_vars.copy()])
def endScope(self):
scope = self._scope_stack.pop()
self.local_vars = lv = scope[0]
v = self.vars
v._pop()
v._push(lv)
# Pop repeat variables, if any
i = len(scope) - 1
while i:
name, value = scope[i]
if value is None:
del self.repeat_vars[name]
else:
self.repeat_vars[name] = value
i = i - 1
def setLocal(self, name, value):
self.local_vars[name] = value
def setGlobal(self, name, value):
self.global_vars[name] = value
def setRepeat(self, name, expr):
expr = self.evaluate(expr)
if not expr:
return self._compiler.Iterator(name, (), self)
it = self._compiler.Iterator(name, expr, self)
old_value = self.repeat_vars.get(name)
self._scope_stack[-1].append((name, old_value))
self.repeat_vars[name] = it
return it
def evaluate(self, expression,
isinstance=isinstance, StringType=StringType):
if isinstance(expression, StringType):
expression = self._compiler.compile(expression)
__traceback_supplement__ = (
TALESTracebackSupplement, self, expression)
return expression(self)
evaluateValue = evaluate
evaluateBoolean = evaluate
def evaluateText(self, expr):
text = self.evaluate(expr)
if text is Default or text is None:
return text
return ustr(text)
def evaluateStructure(self, expr):
return self.evaluate(expr)
evaluateStructure = evaluate
def evaluateMacro(self, expr):
# XXX Should return None or a macro definition
return self.evaluate(expr)
evaluateMacro = evaluate
def createErrorInfo(self, err, position):
return ErrorInfo(err, position)
def getDefault(self):
return Default
def setSourceFile(self, source_file):
self.source_file = source_file
def setPosition(self, position):
self.position = position
def translate(self, domain, msgid, mapping=None,
context=None, target_language=None, default=None):
if context is None:
context = self.contexts.get('here')
return getGlobalTranslationService().translate(
domain, msgid, mapping=mapping,
context=context,
default=default,
target_language=target_language)
def getValue(self, name, default=None):
return self.vars.get(name, default)
class TALESTracebackSupplement:
"""Implementation of ITracebackSupplement"""
def __init__(self, context, expression):
self.context = context
self.source_url = context.source_file
self.line = context.position[0]
self.column = context.position[1]
self.expression = repr(expression)
def getInfo(self, as_html=0):
import pprint
from cgi import escape
data = self.context.contexts.copy()
try:
s = pprint.pformat(data)
except Unauthorized, e:
s = ' - %s: %s' % (getattr(e, '__class__', type(e)), e)
if as_html:
s = escape(s)
return s
if not as_html:
return ' - Names:\n %s' % s.replace('\n', '\n ')
else:
return '<b>Names:</b><pre>%s</pre>' % (escape(s))
class SimpleExpr:
'''Simple example of an expression type handler'''
def __init__(self, name, expr, engine):
self._name = name
self._expr = expr
def __call__(self, econtext):
return self._name, self._expr
def __repr__(self):
return '<SimpleExpr %s %s>' % (self._name, `self._expr`)
import zope.deprecation
zope.deprecation.moved("zope.tales.tales", "2.12")
##############################################################################
#
# 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
#
##############################################################################
"""Old Zope-specific Python Expression Handler
Handler for Python expressions, using the pre-Python 2.1 restriction
machinery from PythonScripts.
"""
__version__='$Revision: 1.8 $'[11:-2]
from AccessControl import getSecurityManager
from Products.PythonScripts.Guarded import _marker, \
GuardedBlock, theGuard, safebin, WriteGuard, ReadGuard, UntupleFunction
from TALES import CompilerError
from PythonExpr import PythonExpr
class PythonExpr(PythonExpr):
def __init__(self, name, expr, engine):
self.expr = expr = expr.strip().replace('\n', ' ')
blk = GuardedBlock('def f():\n return \\\n %s\n' % expr)
if blk.errors:
raise CompilerError, ('Python expression error:\n%s' %
'\n'.join(blk.errors) )
guards = {'$guard': theGuard, '$write_guard': WriteGuard,
'$read_guard': ReadGuard, '__debug__': __debug__}
self._f = UntupleFunction(blk.t, guards, __builtins__=safebin)
self._get_used_names()
class _SecureModuleImporter:
__allow_access_to_unprotected_subobjects__ = 1
def __getitem__(self, module):
mod = safebin['__import__'](module)
path = module.split('.')
for name in path[1:]:
mod = getattr(mod, name)
return mod
from DocumentTemplate.DT_Util import TemplateDict, InstanceDict
def validate(accessed, container, name, value, dummy):
return getSecurityManager().validate(accessed, container, name, value)
def call_with_ns(f, ns, arg=1):
td = TemplateDict()
td.validate = validate
td.this = ns['here']
td._push(ns['request'])
td._push(InstanceDict(td.this, td))
td._push(ns)
try:
if arg==2:
return f(None, td)
else:
return f(td)
finally:
td._pop(3)
......@@ -10,20 +10,17 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Zope-specific Python Expression Handler
Handler for Python expressions that uses the RestrictedPython package.
"""
__version__='$Revision: 1.11 $'[11:-2]
$Id$
"""
from AccessControl import safe_builtins
from AccessControl.ZopeGuards import guarded_getattr, get_safe_globals
from RestrictedPython import compile_restricted_eval
from TALES import CompilerError
from PythonExpr import PythonExpr
from zope.tales.tales import CompilerError
from zope.tales.pythonexpr import PythonExpr
class PythonExpr(PythonExpr):
_globals = get_safe_globals()
......@@ -31,23 +28,23 @@ class PythonExpr(PythonExpr):
_globals['__debug__' ] = __debug__
def __init__(self, name, expr, engine):
self.expr = expr = expr.strip().replace('\n', ' ')
code, err, warn, use = compile_restricted_eval(expr, str(self))
self.text = text = expr.strip().replace('\n', ' ')
code, err, warn, use = compile_restricted_eval(text, str(self))
if err:
raise CompilerError, ('Python expression error:\n%s' %
'\n'.join(err) )
self._f_varnames = use.keys()
raise engine.getCompilerError()('Python expression error:\n%s' %
'\n'.join(err))
self._varnames = use.keys()
self._code = code
def __call__(self, econtext):
__traceback_info__ = self.expr
code = self._code
g = self._bind_used_names(econtext)
g.update(self._globals)
return eval(code, g, {})
__traceback_info__ = self.text
vars = self._bind_used_names(econtext, {})
vars.update(self._globals)
return eval(self._code, vars, {})
class _SecureModuleImporter:
__allow_access_to_unprotected_subobjects__ = 1
__allow_access_to_unprotected_subobjects__ = True
def __getitem__(self, module):
mod = safe_builtins['__import__'](module)
path = module.split('.')
......
This diff is collapsed.
......@@ -10,14 +10,13 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__doc__='''Package wrapper for Page Templates
"""Package wrapper for Page Templates
This wrapper allows the Page Template modules to be segregated in a
separate package.
$Id$'''
__version__='$$'[11:-2]
$Id$
"""
# Placeholder for Zope Product data
misc_ = {}
......
<html>
<head>
<title tal:content="template/title">The title</title>
</head>
<body>
<h2><span tal:replace="here/title_or_id">content title or id</span>
<span tal:condition="template/title"
tal:replace="template/title">optional template title</span></h2>
This is Page Template <em tal:content="template/id">template id</em>.
</body>
</html>
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add Page Template"
tal:replace="structure here/manage_form_title">Form Title</h2>
<p class="form-help">
Page Templates allow you to use simple HTML or XML attributes to
create dynamic templates. You may choose to upload the template text
from a local file by typing the file name or using the <em>browse</em>
button.
</p>
<form action="manage_addPageTemplate" method="post"
enctype="multipart/form-data">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
File
</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="25" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Encoding
</div>
</td>
<td align="left" valign="top">
<input type="text" name="encoding" size="25" value="utf-8" />
<em>(only used for non-XML and non-HTML content)</em>
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
<input class="form-element" type="submit" name="submit"
value=" Add and Edit " />
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
<h1 tal:replace="structure python: context.manage_page_header(management_page_charset='utf-8')">Header</h1>
<h2 tal:define="manage_tabs_message options/manage_tabs_message | nothing"
tal:replace="structure context/manage_tabs">Tabs</h2>
<tal:block define="global body request/other/text | request/form/text
| context/read" />
<form action="" method="post" tal:attributes="action request/URL1">
<input type="hidden" name=":default_method" value="pt_changePrefs">
<input type="hidden" name="encoding" value="utf-8"/>
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="middle">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="middle">
<input type="text" name="title" size="40"
tal:attributes="value request/title | context/title" />
</td>
<td align="left" valign="middle">
<div class="form-label"> Last Modified </div>
</td>
<td align="left" valign="middle">
<div class="form-text"
tal:content="python:context.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
</div>
</td>
</tr>
<tr>
<td align="left" valign="middle">
<div class="form-label">
Content-Type
</div>
</td>
<td align="left" valign="middle">
<select name="content_type" size="1" tal:define="ct context/content_type">
<option value="text/html" tal:attributes="SELECTED python: ct == 'text/html'">text/html</option>
<option value="text/xml" tal:attributes="SELECTED python: ct == 'text/xml'">text/xml</option>
</select>
</td>
<td align="left" valign="top" colspan=2>
<a href="source.html" tal:condition="context/html">Browse HTML source</a>
<a href="source.xml" tal:condition="not:context/html">Browse XML source</a>
<br>
<input type="hidden" name="expand:int:default" value="0">
<input type="checkbox" value="1" name="expand:int"
tal:attributes="checked request/expand | context/expand">
Expand macros when editing
</td>
</tr>
<!-- XXX: check if 'None' is a proper argument for 'namespace' -->
<tr tal:define="errors python: context.pt_errors(None)" tal:condition="errors">
<tal:block define="global body python:context.document_src({'raw':1})"/>
<td align="left" valign="middle" class="form-label">Errors</td>
<td align="left" valign="middle" style="background-color: #FFDDDD"
colspan="3">
<pre tal:content="python: '\n'.join(errors)">errors</pre>
</td>
</tr>
<tr tal:define="warnings context/pt_warnings" tal:condition="warnings">
<td align="left" valign="middle" class="form-label">Warnings</td>
<td align="left" valign="middle" style="background-color: #FFEEDD"
colspan="3">
<pre tal:content="python: '\n'.join(warnings)">errors</pre>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4"
tal:define="width request/dtpref_cols | string:100%;
relative_width python:str(width).endswith('%')">
<textarea name="text:text" wrap="off" style="width: 100%;" rows="20"
tal:condition="relative_width"
tal:attributes="style string:width: $width;;;
rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
<textarea name="text:text" wrap="off" rows="20" cols="50"
tal:condition="not:relative_width"
tal:attributes="cols width; rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4">
<div class="form-element">
<em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:context/wl_isLocked"
class="form-element" type="submit"
name="pt_editAction:method" value="Save Changes">
&nbsp;&nbsp;
<input class="form-element" type="submit" name="height" value="Taller">
<input class="form-element" type="submit" name="height" value="Shorter">
<input class="form-element" type="submit" name="width" value="Wider">
<input class="form-element" type="submit" name="width" value="Narrower">
</div>
</td>
</tr>
</table>
</form>
<p class="form-help">
You can upload the text for <span tal:replace="context/title_and_id" />
using the following form.
Choose an existing HTML or XML file from your local computer by clicking
<em>browse</em>. You can also <a href="document_src">click context</a>
to view or download the current text.
</p>
<form action="pt_upload" method="post"
enctype="multipart/form-data">
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
File &nbsp;
</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="40" value="">
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Encoding &nbsp;
</div>
</td>
<td align="left" valign="top" colspan="2">
<input name="encoding" value="utf-8"/>
</td>
<td align="left" valign="top" colspan="1">
<em>(only used for non-XML and non-XHTML content)</em>
</td>
</tr>
<tr>
<td></td>
<td align="left" valign="top">
<div class="form-element">
<em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:context/wl_isLocked"
class="form-element" type="submit" value="Upload File">
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure context/manage_page_footer">Footer</h1>
def all():
import testTALES
return testTALES.test_suite()
class harness1:
def __init__(self):
self.__callstack = []
def _assert_(self, name, *args, **kwargs):
self.__callstack.append((name, args, kwargs))
def _complete_(self):
assert len(self.__callstack) == 0, "Harness methods called"
def __getattr__(self, name):
cs = self.__callstack
assert len(cs), 'Unexpected harness method call "%s".' % name
assert cs[0][0] == name, (
'Harness method name "%s" called, "%s" expected.' %
(name, cs[0][0]) )
return self._method_
def _method_(self, *args, **kwargs):
name, aargs, akwargs = self.__callstack.pop(0)
assert aargs == args, "Harness method arguments"
assert akwargs == kwargs, "Harness method keyword args"
class harness2(harness1):
def _assert_(self, name, result, *args, **kwargs):
self.__callstack.append((name, result, args, kwargs))
def _method_(self, *args, **kwargs):
name, result, aargs, akwargs = self.__callstack.pop(0)
assert aargs == args, "Harness method arguments"
assert akwargs == kwargs, "Harness method keyword args"
return result
# make this directory a package
<p tal:define="now modules/DateTime/DateTime" tal:content="now/isCurrentYear" />
......@@ -4,7 +4,7 @@
<p>[foo](bar/{})</p>
<a href="foo" alt="[default](alttext/{})">link</a>
<p>[dom](${name} was born in ${country}./{'country':'Antarctica','name':'Lomax'})</p>
<p>[default](hmm/{'age':'25'})</p>
<p>[default](hmm/{'age':u'25'})</p>
</head>
</body>
</html>
......@@ -11,8 +11,10 @@
#
##############################################################################
import os, sys, unittest
import unittest
import zope.component.testing
from zope.traversing.adapters import DefaultTraversable
from Products.PageTemplates.tests import util
from Products.PageTemplates.PageTemplate import PageTemplate
from Acquisition import Implicit
......@@ -43,16 +45,20 @@ class UnitTestSecurityPolicy:
def checkPermission( self, permission, object, context) :
return 1
class DTMLTests(unittest.TestCase):
class DTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
def setUp(self):
self.t=(AqPageTemplate())
super(DTMLTests, self).setUp()
zope.component.provideAdapter(DefaultTraversable, (None,))
self.t = AqPageTemplate()
self.policy = UnitTestSecurityPolicy()
self.oldPolicy = SecurityManager.setSecurityPolicy( self.policy )
self.oldPolicy = SecurityManager.setSecurityPolicy(self.policy)
noSecurityManager() # Use the new policy.
def tearDown(self):
SecurityManager.setSecurityPolicy( self.oldPolicy )
super(DTMLTests, self).tearDown()
SecurityManager.setSecurityPolicy(self.oldPolicy)
noSecurityManager() # Reset to old policy.
def check1(self):
......
import os, sys, unittest
import unittest
import zope.component.testing
from zope.traversing.adapters import DefaultTraversable
from Products.PageTemplates import Expressions
from Products.PageTemplates.DeferExpr import LazyWrapper
......@@ -9,9 +12,12 @@ class Dummy:
def __call__(self):
return 'dummy'
class ExpressionTests(unittest.TestCase):
class ExpressionTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
def setUp(self):
super(ExpressionTests, self).setUp()
zope.component.provideAdapter(DefaultTraversable, (None,))
self.e = e = Expressions.getEngine()
self.ec = e.getContext(
one = 1,
......@@ -20,9 +26,6 @@ class ExpressionTests(unittest.TestCase):
dummy = Dummy()
)
def tearDown(self):
del self.e, self.ec
def testCompile(self):
'''Test expression compilation'''
e = self.e
......@@ -50,9 +53,11 @@ class ExpressionTests(unittest.TestCase):
'''Test advanced expression evaluation 1'''
ec = self.ec
assert ec.evaluate('x | nothing') is None
assert ec.evaluate('d/') == 'blank'
# empty path elements aren't supported anymore, for the lack
# of a use case
#assert ec.evaluate('d/') == 'blank'
assert ec.evaluate('d/_') == 'under'
assert ec.evaluate('d/ | nothing') == 'blank'
#assert ec.evaluate('d/ | nothing') == 'blank'
assert ec.evaluate('d/?blank') == 'blank'
def testHybrid(self):
......@@ -63,7 +68,7 @@ class ExpressionTests(unittest.TestCase):
assert ec.evaluate('x | string:x') == 'x'
assert ec.evaluate('x | string:$one') == '1'
assert ec.evaluate('x | not:exists:x')
def testWrappers(self):
"""Test if defer and lazy are returning their wrappers
"""
......
......@@ -11,8 +11,10 @@
#
##############################################################################
import os, sys, unittest
import unittest
import zope.component.testing
from zope.traversing.adapters import DefaultTraversable
from Products.PageTemplates.tests import util
from Products.PageTemplates.PageTemplate import PageTemplate
from Products.PageTemplates.GlobalTranslationService import \
......@@ -59,9 +61,12 @@ class UnitTestSecurityPolicy:
def checkPermission( self, permission, object, context) :
return 1
class HTMLTests(unittest.TestCase):
class HTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
def setUp(self):
super(HTMLTests, self).setUp()
zope.component.provideAdapter(DefaultTraversable, (None,))
self.folder = f = Folder()
f.laf = AqPageTemplate()
f.t = AqPageTemplate()
......@@ -70,6 +75,7 @@ class HTMLTests(unittest.TestCase):
noSecurityManager() # Use the new policy.
def tearDown(self):
super(HTMLTests, self).tearDown()
SecurityManager.setSecurityPolicy( self.oldPolicy )
noSecurityManager() # Reset to old policy.
......@@ -156,6 +162,9 @@ class HTMLTests(unittest.TestCase):
self.assert_expected(self.folder.t, 'CheckI18nTranslateHooked.html')
setGlobalTranslationService(old_ts)
def checkImportOldStyleClass(self):
self.assert_expected(self.folder.t, 'CheckImportOldStyleClass.html')
def test_suite():
return unittest.makeSuite(HTMLTests, 'check')
......
import os, sys, unittest
import unittest
# BBB 2005/05/01 -- to be changed after 12 months
# ignore deprecation warnings on import for now
import warnings
showwarning = warnings.showwarning
warnings.showwarning = lambda *a, **k: None
# this old import should remain here until the TALES.py module is
# completely removed, so that API backward compatibility is properly
# tested
from Products.PageTemplates import TALES
from Products.PageTemplates.tests import harness1
import string
# restore warning machinery
warnings.showwarning = showwarning
from zope.tales.tests.test_tales import Harness
class DummyUnicodeExpr:
'''Dummy expression type handler returning unicode'''
......@@ -18,14 +28,14 @@ class TALESTests(unittest.TestCase):
def testIterator0(self):
'''Test sample Iterator class'''
context = harness1()
context = Harness(self)
it = TALES.Iterator('name', (), context)
assert not it.next(), "Empty iterator"
context._complete_()
def testIterator1(self):
'''Test sample Iterator class'''
context = harness1()
context = Harness(self)
it = TALES.Iterator('name', (1,), context)
context._assert_('setLocal', 'name', 1)
assert it.next() and not it.next(), "Single-element iterator"
......@@ -33,7 +43,7 @@ class TALESTests(unittest.TestCase):
def testIterator2(self):
'''Test sample Iterator class'''
context = harness1()
context = Harness(self)
it = TALES.Iterator('text', 'text', context)
for c in 'text':
context._assert_('setLocal', 'text', c)
......@@ -104,23 +114,25 @@ class TALESTests(unittest.TestCase):
def testVariables(self):
'''Test variables'''
ctxt = self.getContext()
c = ctxt.vars
ctxt.beginScope()
ctxt.setLocal('v1', 1)
ctxt.setLocal('v2', 2)
c = ctxt.vars
assert c['v1'] == 1, 'Variable "v1"'
ctxt.beginScope()
ctxt.setLocal('v1', 3)
ctxt.setGlobal('g', 1)
c = ctxt.vars
assert c['v1'] == 3, 'Inner scope'
assert c['v2'] == 2, 'Outer scope'
assert c['g'] == 1, 'Global'
ctxt.endScope()
c = ctxt.vars
assert c['v1'] == 1, "Uncovered local"
assert c['g'] == 1, "Global from inner scope"
......
......@@ -10,9 +10,9 @@ Note: Tests require Zope >= 2.7
import unittest
import Zope2
import transaction
import zope.component.testing
from zope.traversing.adapters import DefaultTraversable
from Testing.makerequest import makerequest
from Products.PageTemplates.ZopePageTemplate import _default_content_fn
class ZPTRegressions(unittest.TestCase):
......@@ -35,7 +35,7 @@ class ZPTRegressions(unittest.TestCase):
def testAddWithoutParams(self):
pt = self._addPT('pt1')
default_text = open(_default_content_fn).read()
default_text = open(pt._default_content_fn).read()
self.assertEqual(pt.title, '')
self.assertEqual(pt.document_src().strip(), default_text.strip())
......@@ -58,8 +58,12 @@ class ZPTRegressions(unittest.TestCase):
pt = self.app.pt1
self.assertEqual(pt.document_src(), self.text)
class ZPTMacros(unittest.TestCase):
class ZPTMacros(zope.component.testing.PlacelessSetup, unittest.TestCase):
def setUp(self):
super(ZPTMacros, self).setUp()
zope.component.provideAdapter(DefaultTraversable, (None,))
transaction.begin()
self.app = makerequest(Zope2.app())
f = self.app.manage_addProduct['PageTemplates'].manage_addPageTemplate
......@@ -86,7 +90,13 @@ class ZPTMacros(unittest.TestCase):
This is in the slot
</p>
</div>
"""
"""
def tearDown(self):
super(ZPTMacros, self).tearDown()
transaction.abort()
self.app._p_jar.close()
def testMacroExpansion(self):
request = self.app.REQUEST
......@@ -98,9 +108,9 @@ class ZPTMacros(unittest.TestCase):
request = self.app.REQUEST
self._addPT('pt1', text=self.text, REQUEST=request)
pt = self.app.pt1
pt.pt_render(None, source=1)
self.assertEqual(pt.pt_errors(None), None)
pt.pt_render(source=True)
self.assertEqual(pt.pt_errors(), None)
class DummyFileUpload:
def __init__(self, data='', filename='', content_type=''):
......
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add Page Template"
tal:replace="structure here/manage_form_title">Form Title</h2>
<p class="form-help">
Page Templates allow you to use simple HTML or XML attributes to
create dynamic templates. You may choose to upload the template text
from a local file by typing the file name or using the <em>browse</em>
button.
</p>
<p class="form-help">Page Templates allow you to use simple HTML or
XML attributes to create dynamic templates. You may choose to upload
the template text from a local file by typing the file name or using
the <em>browse</em> button.</p>
<form action="manage_addPageTemplate" method="post"
enctype="multipart/form-data">
enctype="multipart/form-data">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
<div class="form-label">Id</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
File
</div>
<div class="form-optional">File</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="25" value="" />
<input type="file" name="file" size="25" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">Encoding</div>
</td>
<td align="left" valign="top">
<input type="text" name="encoding" size="25" value="utf-8" />
<em>(only used for non-XML and non-HTML content)</em>
</td>
</tr>
<tr>
<td align="left" valign="top"></td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
<input class="form-element" type="submit" name="submit"
value=" Add and Edit " />
</div>
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
<input class="form-element" type="submit" name="submit"
value=" Add and Edit " />
</div>
</td>
</tr>
</table>
......
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h1 tal:replace="structure python:context.manage_page_header(management_page_charset='utf-8')">Header</h1>
<h2 tal:define="manage_tabs_message options/manage_tabs_message | nothing"
tal:replace="structure here/manage_tabs">Tabs</h2>
tal:replace="structure context/manage_tabs">Tabs</h2>
<tal:block define="global body request/other/text | request/form/text
| here/read" />
| context/read" />
<form action="" method="post" tal:attributes="action request/URL1">
<input type="hidden" name=":default_method" value="pt_changePrefs">
<input type="hidden" name=":default_method" value="pt_changePrefs" />
<input type="hidden" name="encoding" value="utf-8" />
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="middle">
<div class="form-optional">
Title
</div>
<div class="form-optional">Title</div>
</td>
<td align="left" valign="middle">
<input type="text" name="title" size="40"
tal:attributes="value request/title | here/title" />
<input type="text" name="title" size="40"
tal:attributes="value request/title | context/title" />
</td>
<td align="left" valign="middle">
<div class="form-optional">
Content-Type
</div>
<div class="form-label">Content-Type</div>
</td>
<td align="left" valign="middle">
<input type="text" name="content_type" size="14"
tal:attributes="value request/content_type | here/content_type" />
<input type="text" name="content_type" size="14"
tal:attributes="value request/content_type | context/content_type" />
</td>
</tr>
<tr>
<td align="left" valign="middle">
<div class="form-label">
Last Modified
</div>
<div class="form-label">Last Modified</div>
</td>
<td align="left" valign="middle">
<div class="form-text"
tal:content="python:here.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
</div>
<div class="form-text"
tal:content="python:context.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
</div>
</td>
<td align="left" valign="top" colspan=2>
<a href="source.html" tal:condition="here/html">Browse HTML source</a>
<a href="source.xml" tal:condition="not:here/html">Browse XML source</a>
<br>
<input type="hidden" name="expand:int:default" value="0">
<td align="left" valign="top" colspan="2">
<a href="source.html" tal:condition="context/html">Browse HTML source</a>
<a href="source.xml" tal:condition="not:context/html">Browse XML source</a>
<br />
<input type="hidden" name="expand:int:default" value="0" />
<input type="checkbox" value="1" name="expand:int"
tal:attributes="checked request/expand | here/expand">
tal:attributes="checked request/expand | context/expand" />
Expand macros when editing
</td>
</tr>
<tr tal:define="errors here/pt_errors" tal:condition="errors">
<tal:block define="global body python:here.document_src({'raw':1})"/>
<tr tal:define="errors context/pt_errors" tal:condition="errors">
<tal:block define="global body python:context.document_src({'raw':1})" />
<td align="left" valign="middle" class="form-label">Errors</td>
<td align="left" valign="middle" style="background-color: #FFDDDD"
colspan="3">
<pre tal:content="python:modules['string'].join(errors, '\n')">errors</pre>
colspan="3">
<pre tal:content="python:'\n'.join(errors)">errors</pre>
</td>
</tr>
<tr tal:define="warnings here/pt_warnings" tal:condition="warnings">
<tr tal:define="warnings context/pt_warnings" tal:condition="warnings">
<td align="left" valign="middle" class="form-label">Warnings</td>
<td align="left" valign="middle" style="background-color: #FFEEDD"
colspan="3">
<pre tal:content="python:modules['string'].join(warnings, '\n')">errors</pre>
colspan="3">
<pre tal:content="python:'\n'.join(warnings)">errors</pre>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4"
tal:define="width request/dtpref_cols | string:100%;
relative_width python:str(width).endswith('%')">
tal:define="width request/dtpref_cols | string:100%;
relative_width python:str(width).endswith('%')">
<textarea name="text:text" wrap="off" style="width: 100%;" rows="20"
tal:condition="relative_width"
tal:attributes="style string:width: $width;;;
rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
tal:condition="relative_width"
tal:attributes="style string:width: $width;;;
rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
<textarea name="text:text" wrap="off" rows="20" cols="50"
tal:condition="not:relative_width"
tal:attributes="cols width; rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
tal:condition="not:relative_width"
tal:attributes="cols width; rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4">
<div class="form-element">
<em tal:condition="here/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:here/wl_isLocked"
class="form-element" type="submit"
name="pt_editAction:method" value="Save Changes">
&nbsp;&nbsp;
<input class="form-element" type="submit" name="height" value="Taller">
<input class="form-element" type="submit" name="height" value="Shorter">
<input class="form-element" type="submit" name="width" value="Wider">
<input class="form-element" type="submit" name="width" value="Narrower">
<em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:context/wl_isLocked"
class="form-element" type="submit"
name="pt_editAction:method" value="Save Changes">
&nbsp;&nbsp;
<input class="form-element" type="submit" name="height" value="Taller" />
<input class="form-element" type="submit" name="height" value="Shorter" />
<input class="form-element" type="submit" name="width" value="Wider" />
<input class="form-element" type="submit" name="width" value="Narrower" />
</div>
</td>
</tr>
</table>
</form>
<p class="form-help">
You can upload the text for <span tal:replace="here/title_and_id" />
using the following form.
Choose an existing HTML or XML file from your local computer by clicking
<em>browse</em>. You can also <a href="document_src">click here</a>
to view or download the current text.
</p>
<p class="form-help">You can upload the text for
<span tal:replace="context/title_and_id" /> using the following form.
Choose an existing HTML or XML file from your local computer by
clicking <em>browse</em>. You can also <a href="document_src">click
context</a> to view or download the current text.</p>
<form action="pt_upload" method="post"
enctype="multipart/form-data">
<form action="pt_upload" method="post" enctype="multipart/form-data">
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
File &nbsp;
</div>
<div class="form-label">File &nbsp;</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="25" value="">
<input type="file" name="file" size="40" value="" />
</td>
</tr>
<tr tal:condition="context/management_page_charset|nothing">
<tr>
<td align="left" valign="top">
<div class="form-label">
Encoding &nbsp;
</div>
<div class="form-label">Encoding &nbsp;</div>
</td>
<td align="left" valign="top">
<input name="charset" value=""
tal:attributes="value here/management_page_charset|default" />
<td align="left" valign="top" colspan="2">
<input name="encoding" value="utf-8" />
</td>
<td align="left" valign="top" colspan="1">
<em>(only used for non-XML and non-XHTML content)</em>
</td>
</tr>
<tr>
<td></td>
<td align="left" valign="top">
<div class="form-element">
<em tal:condition="here/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:here/wl_isLocked"
class="form-element" type="submit" value="Upload File">
<em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:context/wl_isLocked"
class="form-element" type="submit" value="Upload File" />
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
<h1 tal:replace="structure context/manage_page_footer">Footer</h1>
......@@ -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)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<div i18n:translate="">At the tone the time will be
<span i18n:data="here/currentTime"
i18n:translate="timefmt"
i18n:name="time">2:32 pm</span>... beep!</div>
i18n:name="time"
tal:omit-tag="">2:32 pm</span>... beep!</div>
......@@ -2,5 +2,5 @@
<span i18n:translate="">
<span tal:replace="string:<foo>" i18n:name="name1" />
<span tal:replace="structure string:<bar />" i18n:name="name2" />
<span i18n:name="name3"><b>some</b> <i>text</i></span>
<span i18n:name="name3" tal:omit-tag=""><b>some</b> <i>text</i></span>
</span>
<div>AT THE TONE THE TIME WILL BE 59 MINUTES AFTER 6 PM... BEEP!</div>
<div>AT THE TONE THE TIME WILL BE 59 minutes after 6 PM... BEEP!</div>
......@@ -22,7 +22,7 @@
<span metal:use-macro="OUTER2">
AAA
<xxx metal:fill-slot="OUTERSLOT">
<xxx>
<span>INNER</span>
</xxx>
BBB
......@@ -48,7 +48,7 @@
<span metal:use-macro="OUTER3">
AAA
<xxx metal:fill-slot="OUTERSLOT">
<xxx>
<span>INNER
<xxx>INNERSLOT</xxx>
</span>
......@@ -63,7 +63,7 @@
</span>
<span metal:use-macro="INNER3">INNER
<xxx metal:fill-slot="INNERSLOT">INNERSLOT</xxx>
<xxx>INNERSLOT</xxx>
</span>
<span metal:use-macro="INNER3">INNER
......
......@@ -2,5 +2,5 @@
<x metal:define-slot="title" />
</html>
<html metal:use-macro="page" i18n:domain="zope">
<x metal:fill-slot="title" />
<x />
</html>
......@@ -8,7 +8,7 @@ import glob
from TAL.tests import utils
import unittest
from TAL import runtest
from zope.tal import runtest
class FileTestCase(unittest.TestCase):
......
This diff is collapsed.
......@@ -6,10 +6,20 @@ import unittest
from StringIO import StringIO
# BBB 2005/05/01 -- to be changed after 12 months
# ignore deprecation warnings on import for now
import warnings
showwarning = warnings.showwarning
warnings.showwarning = lambda *a, **k: None
# this old import should remain here until the TAL package is
# completely removed, so that API backward compatibility is properly
# tested
from TAL.HTMLTALParser import HTMLTALParser
from TAL.TALInterpreter import TALInterpreter
from TAL.TALGenerator import TALGenerator
from TAL.DummyEngine import DummyEngine
# restore warning machinery
warnings.showwarning = showwarning
page1 = '''<html metal:use-macro="main"><body>
......
This diff is collapsed.
......@@ -7,7 +7,17 @@ import sys
from TAL.tests import utils
import unittest
# BBB 2005/05/01 -- to be changed after 12 months
# ignore deprecation warnings on import for now
import warnings
showwarning = warnings.showwarning
warnings.showwarning = lambda *a, **k: None
# this old import should remain here until the TAL package is
# completely removed, so that API backward compatibility is properly
# tested
from TAL import XMLParser
# restore warning machinery
warnings.showwarning = showwarning
class EventCollector(XMLParser.XMLParser):
......
This diff is collapsed.
This diff is collapsed.
......@@ -14,8 +14,12 @@
$Id$
"""
# BBB 2005/05/01 -- to be removed after 12 months
import zope.deferredimport
zope.deferredimport.define(
Iterator = 'ZTUtils.Iterator:Iterator'
)
from Iterator import Iterator
from Tree import encodeExpansion, decodeExpansion, a2b, b2a
from SimpleTree import SimpleTreeMaker
......
This diff is collapsed.
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