========
z3c.pt
========
.. image:: https://img.shields.io/pypi/v/z3c.pt.svg
:target: https://pypi.python.org/pypi/z3c.pt/
:alt: Latest release
.. image:: https://img.shields.io/pypi/pyversions/z3c.pt.svg
:target: https://pypi.org/project/z3c.pt/
:alt: Supported Python versions
.. image:: https://github.com/zopefoundation/z3c.pt/actions/workflows/tests.yml/badge.svg
:target: https://github.com/zopefoundation/z3c.pt/actions/workflows/tests.yml
.. image:: https://coveralls.io/repos/github/zopefoundation/z3c.pt/badge.svg?branch=master
:target: https://coveralls.io/github/zopefoundation/z3c.pt?branch=master
.. image:: https://readthedocs.org/projects/z3cpt/badge/?version=latest
:target: https://z3cpt.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
This is a fast implementation of the ZPT template engine for Zope 3
which uses Chameleon to compile templates to byte-code.
The package provides application support equivalent to
``zope.pagetemplate``.
==========
Overview
==========
This section demonstrates the high-level template classes. All page
template classes in ``z3c.pt`` use path-expressions by default.
Page templates
==============
>>> from z3c.pt.pagetemplate import PageTemplate
>>> from z3c.pt.pagetemplate import PageTemplateFile
The ``PageTemplate`` class is initialized with a string.
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... Hello World!
... </div>""")
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
The ``PageTemplateFile`` class is initialized with an absolute
path to a template file on disk.
>>> template_file = PageTemplateFile('tests/helloworld.pt')
>>> print(template_file())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
>>> import os
>>> os.path.isabs(template_file.filename)
True
If a ``content_type`` is not informed and one is not present in the
request, it will be set to 'text/html'.
>>> class Response(object):
... def __init__(self):
... self.headers = {}
... self.getHeader = self.headers.get
... self.setHeader = self.headers.__setitem__
>>> class Request(object):
... def __init__(self):
... self.response = Response()
>>> template_file = PageTemplateFile('tests/helloworld.pt')
>>> request = Request()
>>> print(request.response.getHeader('Content-Type'))
None
>>> template = template_file.bind(None, request=request)
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
>>> print(request.response.getHeader('Content-Type'))
text/html
If a ``content_type`` is present in the request, then we don't override it.
>>> request = Request()
>>> request.response.setHeader('Content-Type', 'text/xml')
>>> print(request.response.getHeader('Content-Type'))
text/xml
>>> template = template_file.bind(None, request=request)
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
>>> print(request.response.getHeader('Content-Type'))
text/xml
A ``content_type`` can be also set at instantiation time, and it will
be respected.
>>> template_file = PageTemplateFile('tests/helloworld.pt',
... content_type='application/rdf+xml')
>>> request = Request()
>>> print(request.response.getHeader('Content-Type'))
None
>>> template = template_file.bind(None, request=request)
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
>>> print(request.response.getHeader('Content-Type'))
application/rdf+xml
Both may be used as class attributes (properties).
>>> class MyClass(object):
... template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... Hello World!
... </div>""")
...
... template_file = PageTemplateFile('tests/helloworld.pt')
>>> instance = MyClass()
>>> print(instance.template())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
>>> print(instance.template_file())
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>
View page templates
===================
>>> from z3c.pt.pagetemplate import ViewPageTemplate
>>> from z3c.pt.pagetemplate import ViewPageTemplateFile
>>> class View(object):
... request = u'request'
... context = u'context'
...
... def __repr__(self):
... return 'view'
>>> view = View()
As before, we can initialize view page templates with a string (here
incidentally loaded from disk).
>>> from z3c.pt import tests
>>> path = tests.__path__[0]
>>> with open(path + '/view.pt') as f:
... template = ViewPageTemplate(f.read())
To render the template in the context of a view, we bind the template
passing the view as an argument (view page templates derive from the
``property``-class and are usually defined as an attribute on a view
class).
>>> print(template.bind(view)(test=u'test'))
<div xmlns="http://www.w3.org/1999/xhtml">
<span>view</span>
<span>context</span>
<span>request</span>
<span>test</span>
<span>test</span>
</div>
The exercise is similar for the file-based variant.
>>> template = ViewPageTemplateFile('tests/view.pt')
>>> print(template.bind(view)(test=u'test'))
<div xmlns="http://www.w3.org/1999/xhtml">
<span>view</span>
<span>context</span>
<span>request</span>
<span>test</span>
<span>test</span>
</div>
For compatibility reasons, view templates may be called with an
alternative context and request.
>>> print(template(view, u"alt_context", "alt_request", test=u'test'))
<div xmlns="http://www.w3.org/1999/xhtml">
<span>view</span>
<span>alt_context</span>
<span>alt_request</span>
<span>test</span>
<span>test</span>
</div>
Non-keyword arguments
=====================
These are passed in as ``options/args``, when using the ``__call__`` method.
>>> print(PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <div tal:repeat="arg options/args">
... <span tal:content="arg" />
... </div>
... </div>""").__call__(1, 2, 3))
<div xmlns="http://www.w3.org/1999/xhtml">
<div>
<span>1</span>
</div>
<div>
<span>2</span>
</div>
<div>
<span>3</span>
</div>
</div>
Global 'path' Function
======================
Just like ``zope.pagetemplate``, it is possible to use a globally
defined ``path()`` function in a ``python:`` expression in ``z3c.pt``:
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:content="options/test" />
... <span tal:content="python: path('options/test')" />
... </div>""")
>>> print(template(test='test'))
<div xmlns="http://www.w3.org/1999/xhtml">
<span>test</span>
<span>test</span>
</div>
Global 'exists' Function
========================
The same applies to the ``exists()`` function:
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:content="python: exists('options/test') and 'Yes' or 'No'" />
... </div>""")
>>> print(template(test='test'))
<div xmlns="http://www.w3.org/1999/xhtml">
<span>Yes</span>
</div>
'default' and path expressions
==============================
Another feature from standard ZPT: using 'default' means whatever the
the literal HTML contains will be output if the condition is not met.
This works for attributes:
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:attributes="class options/not-existing | default"
... class="blue">i'm blue</span>
... </div>""")
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
<span class="blue">i'm blue</span>
</div>
And also for contents:
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:content="options/not-existing | default">default content</span>
... </div>""")
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
<span>default content</span>
</div>
'exists'-type expression
========================
Using 'exists()' function on non-global name and global name:
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:content="python: exists('options/nope') and 'Yes' or 'No'">do I exist?</span>
... <span tal:content="python: exists('nope') and 'Yes' or 'No'">do I exist?</span>
... </div>""")
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
<span>No</span>
<span>No</span>
</div>
Using 'exists:' expression on non-global name and global name
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:define="yup exists:options/nope"
... tal:content="python: yup and 'Yes' or 'No'">do I exist?</span>
... <span tal:define="yup exists:nope"
... tal:content="python: yup and 'Yes' or 'No'">do I exist?</span>
... </div>""")
>>> print(template())
<div xmlns="http://www.w3.org/1999/xhtml">
<span>No</span>
<span>No</span>
</div>
Using 'exists:' in conjunction with a negation:
>>> print(PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:condition="not:exists:options/nope">I don't exist?</span>
... </div>""")())
<div xmlns="http://www.w3.org/1999/xhtml">
<span>I don't exist?</span>
</div>
path expression with dictionaries
=================================
Path expressions give preference to dictionary items instead of
dictionary attributes.
>>> print(PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml"
... tal:define="links python:{'copy':'XXX', 'delete':'YYY'}">
... <span tal:content="links/copy">ZZZ</span>
... </div>""")())
<div xmlns="http://www.w3.org/1999/xhtml">
<span>XXX</span>
</div>
Variable from one tag never leak into another
=============================================
>>> body = """\
... <div xmlns="http://www.w3.org/1999/xhtml"
... xmlns:tal="http://xml.zope.org/namespaces/tal"
... xmlns:metal="http://xml.zope.org/namespaces/metal">
... <div class="macro" metal:define-macro="greeting"
... tal:define="greeting greeting|string:'Hey'">
... <span tal:replace="greeting" />
... </div>
... <div tal:define="greeting string:'Hello'">
... <metal:block metal:use-macro="python:template.macros['greeting']" />
... </div>
... <div>
... <metal:block metal:use-macro="python:template.macros['greeting']" />
... </div>
... </div>"""
>>> print(PageTemplate(body)())
<div xmlns="http://www.w3.org/1999/xhtml">
<div class="macro">
'Hey'
</div>
<div>
<div class="macro">
'Hello'
</div>
<BLANKLINE>
</div>
<div>
<div class="macro">
'Hey'
</div>
<BLANKLINE>
</div>
</div>
TALES Function Namespaces
=========================
As described on http://wiki.zope.org/zope3/talesns.html, it is
possible to implement custom TALES Namespace Adapters. We also support
low-level TALES Function Namespaces (which the TALES Namespace
Adapters build upon).
>>> import datetime
>>> import zope.interface
>>> import zope.component
>>> from zope.traversing.interfaces import ITraversable
>>> from zope.traversing.interfaces import IPathAdapter
>>> from zope.tales.interfaces import ITALESFunctionNamespace
>>> from z3c.pt.namespaces import function_namespaces
>>> @zope.interface.implementer(ITALESFunctionNamespace)
... class ns1(object):
... def __init__(self, context):
... self.context = context
... def parent(self):
... return self.context.parent
>>> function_namespaces.namespaces['ns1'] = ns1
>>> class ns2(object):
... def __init__(self, context):
... self.context = context
... def upper(self):
... return self.context.upper()
>>> zope.component.getGlobalSiteManager().registerAdapter(
... ns2, [zope.interface.Interface], IPathAdapter, 'ns2')
>>> class ns3(object):
... def __init__(self, context):
... self.context = context
... def fullDateTime(self):
... return self.context.strftime('%Y-%m-%d %H:%M:%S')
>>> zope.component.getGlobalSiteManager().registerAdapter(
... ns3, [zope.interface.Interface], IPathAdapter, 'ns3')
A really corner-ish case from a legacy application: the TALES
Namespace Adapter doesn't have a callable function but traverses the
remaining path instead::
>>> from zope.traversing.interfaces import TraversalError
>>> @zope.interface.implementer(ITraversable)
... class ns4(object):
...
... def __init__(self, context):
... self.context = context
...
... def traverse(self, name, furtherPath):
... if name == 'page':
... if len(furtherPath) == 1:
... pagetype = furtherPath.pop()
... elif not furtherPath:
... pagetype = 'default'
... else:
... raise TraversalError("Max 1 path segment after ns4:page")
... return self._page(pagetype)
... if len(furtherPath) == 1:
... name = '%s/%s' % (name, furtherPath.pop())
... return 'traversed: ' + name
...
... def _page(self, pagetype):
... return 'called page: ' + pagetype
>>> zope.component.getGlobalSiteManager().registerAdapter(
... ns4, [zope.interface.Interface], IPathAdapter, 'ns4')
>>> @zope.interface.implementer(ITraversable)
... class ns5(object):
...
... def __init__(self, context):
... self.context = context
...
... def traverse(self, name, furtherPath):
... name = '/'.join([name] + furtherPath[::-1])
... del furtherPath[:]
... return 'traversed: ' + name
>>> zope.component.getGlobalSiteManager().registerAdapter(
... ns5, [zope.interface.Interface], IPathAdapter, 'ns5')
>>> class Ob(object):
... def __init__(self, title, date, parent=None, child=None):
... self.title = title
... self.date = date
... self.parent = parent
... self.child = child
>>> child = Ob('child', datetime.datetime(2008, 12, 30, 13, 48, 0, 0))
>>> father = Ob('father', datetime.datetime(1978, 12, 30, 13, 48, 0, 0))
>>> grandpa = Ob('grandpa', datetime.datetime(1948, 12, 30, 13, 48, 0, 0))
>>> child.parent = father
>>> father.child = child
>>> father.parent = grandpa
>>> grandpa.child = father
>>> class View(object):
... request = u'request'
... context = father
...
... def __repr__(self):
... return 'view'
>>> view = View()
>>> template = ViewPageTemplateFile('tests/function_namespaces.pt')
>>> print(template.bind(view)())
<div xmlns="http://www.w3.org/1999/xhtml">
<span>GRANDPA</span>
<span>2008-12-30 13:48:00</span>
<span>traversed: link:main</span>
<span>called page: default</span>
<span>called page: another</span>
<span></span>
<span>traversed: zope.Public</span>
<span>traversed: text-to-html</span>
<span>traversed: page/yet/even/another</span>
</div>
===========
Changelog
===========
4.4 (2024-08-07)
================
- Extend boolean html attribute list to include all html5 boolean attributes.
4.3 (2024-02-01)
================
- Add support for Python 3.12.
- Fix Windows test compatibility.
4.2 (2024-01-31)
================
- Add support for "structure" expression type.
(`Issue #17 <https://github.com/zopefoundation/z3c.pt/issues/17>`_).
- Updated test suite to be compatible with newer Chameleon releases.
4.1 (2024-01-09)
================
- Provide own interfaces, since Chameleon will not provide those in a
future release.
4.0 (2023-03-27)
================
- Add support for Python 3.11.
- Drop support for Python 2.7, 3.5, 3.6.
3.3.1 (2021-12-17)
==================
- Add support for Python 3.9, and 3.10.
3.3.0 (2020-03-31)
==================
- Drop support for Python 3.4
- Add support for Python 3.8.
- Prevent interpolation (i.e. ``$``*var*, ``${``*path*``}`` replacements)
inside comments
(`Zope #716 <https://github.com/zopefoundation/Zope/issues/716>`_).
3.2.0 (2019-01-05)
==================
- Add support for Python 3.7.
- Drop support for running the tests using `python setup.py test`.
3.1.0 (2017-10-17)
==================
- Add support for Python 3.6.
- Drop support for Python 3.3.
- Use the adapter namespace from ``zope.pagetemplate`` if it's
available, instead of the backwards compatibility shim in
``zope.app.pagetemplate``. See `issue 3
<https://github.com/zopefoundation/z3c.pt/issues/3>`_.
- Add the ``string`` and ``nocall`` functions for use inside Python
expressions. See `issue 2
<https://github.com/zopefoundation/z3c.pt/issues/2>`_.
- Make bound page templates have ``__self__`` and ``__func__``
attributes to be more like Python 3 bound methods. (``im_func`` and
``im_self`` remain available.) See `issue 9
<https://github.com/zopefoundation/z3c.pt/issues/9>`_.
3.0 (2016-09-02)
================
- Added support for Python 3.4, 3.5, PyPy and PyPy3.
- Dropped support for Python 2.6.
3.0.0a1 (2013-02-25)
====================
Compatibility:
- Added support for Python 3.3.
- Added a small patch to ``chameleon.i18n`` to define ``basestring``.
Bugfixes:
- Allow segments of path expressions to start with a digit.
2.2.3 (2012-06-01)
==================
Compatibility:
- The translation function now accepts (but ignores) a ``context``
argument. This fixes a compatibility issue with Chameleon 2.9.x.
2.2.2 (2012-04-24)
==================
Bugfixes:
- Do not rely on the "LANGUAGE" request key to skip language
negotiation. Instead, we assume that negotiation is cheap (and
probably cached).
2.2.1 (2012-02-15)
==================
- Only require Chameleon >= 2.4, was needlessly bumped in last release.
- Add test extra, remove versions from buildout.cfg.
2.2 (2012-01-08)
================
Features:
- Whitespace between attributes is now reduced to a single whitespace
character.
- The ``request`` symbol is no longer required to evaluate a path
expression; it now defaults to ``None`` if not present in the
namespace.
Bugfixes:
- The content provider expression now correctly applies TAL namespace
data.
Changes:
- The ``ZopeTraverser`` class has been removed and replaced with a
simple function.
2.1.5 (2011-11-24)
==================
- Use non-strict mode if available for compatibility with the
reference engine where expressions are only compiled at evaluation
time.
2.1.4 (2011-09-14)
==================
- The provider expression is now first evaluated as a string
expression, the result of which is used as the content provider
name.
This fixes an issue where (provider-) string expressions would not
get evaluated correctly, e.g. ``provider: ${mgr}``.
2.1.3 (2011-08-22)
==================
- Configure HTML boolean attributes (in HTML-mode only)::
"compact", "nowrap", "ismap", "declare", "noshade",
"checked", "disabled", "readonly", "multiple", "selected",
"noresize", "defer"
2.1.2 (2011-08-19)
==================
- Enable option ``literal_false`` to get the behavior that a value of
``False`` does not drop an attribute.
2.1.1 (2011-08-11)
==================
- Make sure the builtin names 'path' and 'exists' can be redefined.
- Guard ``sys.modules`` (mapped to the builtin variable "modules")
against import-time side effects using ``ProxyFactory``.
2.1 (2011-07-28)
================
- Use dynamic expression evaluation framework that comes included with
Chameleon.
2.0 (2011-07-14)
================
- Point release.
- Move implementation-specific context setup to ``render``
method. This allows use of template class with an already prepared
context.
- Fixed issue with the call flag on the Zope traverser compiler.
2.0-rc3 (2011-07-11)
====================
- Python-expressions are no longer TALES-expressions; previously, the
pipe operator would split Python expression clauses, allowing
fallbacks even for Python expressions, but this is not the standard
behavior of ZPT.
- Fixed an issue where an error which occurred inside a dynamic
``path`` or ``exists`` evaluation would fail to propagate due to a
missing remote context.
- Set variables ``here`` and ``context`` to the bound instance value
on ``PageTemplate`` instances.
2.0-rc2 (2011-03-24)
====================
- Fixed an issue with ``"exists:"`` expression where a callable would
be attempted called. It is meanwhile implied with this expression
types that it should use the ``"nocall:"`` pragma.
2.0-rc1 (2011-02-28)
====================
- Update to Chameleon 2.0.
This release includes many changes and is a complete rewrite of the
1.x series.
Platform:
* Python 2.5+ now required.
Notable changes:
* Expression interpolation is always enabled.
* Whitespace output is different, now closely aligned to the
template input.
* New language constructs:
1) tal:on-error
2) tal:switch
3) tal:case
Incompatibilities:
* The expression translation interface has been replaced with an
expression engine. This means that all expressions must be
rewritten.
- The exists expression evaluator should ignore KeyError exceptions
as well.
- Special-case handling of Zope2's Missing.MV as used by
Products.ZCatalog for LP#649343.
[rossp]
1.2.1 (2010/05/13)
------------------
- Bind template to the template object in the general case.
1.2 (2010/05/12)
----------------
- Fixed compatibility issue with recent change in Chameleon.
- Fixed regression introduced with ``args`` being passed
in. Incidentally, the name ``args`` was used as the star argument
name.
- Look at language set on request before invoking the zope.i18n
negotiator. This makes i18n work again on Zope2.
1.1.1 (2010/04/06)
------------------
- Fixed issue where arguments were not passed on to template as
``args``.
1.1.0 (2010/01/09)
------------------
- Update to combined Chameleon distribution.
1.0.1 (2009/07/06)
------------------
- Bind translation context (request) to translation method. Although
not required in newer versions of the translation machinery, some
versions will ask for a translation context in order to negotiate
language even when a language is explicitly passed in.
- Declare zope security settings for classes when zope.security is present
as the "class" ZCML directive was moved there.
1.0.0 (2009/07/06)
------------------
- First point release.
1.0b17 (2009/06/14)
-------------------
- Made the Zope security declaration for the repeat dictionary be conditional
on the presence of zope.app.security instead of zope.app.component.
1.0b16 (2009/05/20)
-------------------
- Updated run-time expression evaluator method to work after a recent
architectural change in Chameleon. [malthe]
- Check that we have a non-trivial response-object before trying to
set the content type. [malthe]
- Wrap ``sys.modules`` dictionary in an "opaque" dictionary class,
such that the representation string does not list all loaded
modules. [malthe]
1.0b15 (2009/04/24)
-------------------
- Removed lxml extra, as we do no longer depend on it. [malthe]
- Make sure the path expression is a simple string, not
unicode. [malthe]
- Detect path prefix properly for ViewPageTemplateFile usage in
doctests. [sidnei]
- The ``template`` symbol is already set by the template base
class. [malthe]
- Set Content-Type header, for backwards compatibility with
zope.app.pagetemplate. [sidnei]
1.0b14 (2009/03/31)
-------------------
- Updated language adapter to work with 'structure' meta
attribute. [malthe]
1.0b13 (2009/03/23)
-------------------
- When traversing on dictionaries, only exposes dictionary items
(never attributes); this is to avoid ambiguity. [sidnei, malthe]
- Path expressions need to pass further path items in reverse order to
traversePathElement, because that's what it expects. [sidnei]
1.0b12 (2009/03/09)
-------------------
- Insert initial variable context into dynamic scope. The presence of
these is expected by many application. [malthe]
1.0b11 (2009/03/05)
-------------------
- If a namespace-acquired object provides ``ITraversable``, use path
traversal. [malthe]
- Implemented TALES function namespaces. [sidnei, malthe]
- Catch ``NameError`` in exists-traverser (return false). [malthe]
- Catch ``NameError`` in exists-evaluator (return false). [malthe]
- If the supplied ``context`` and ``request`` parameters are trivial,
get them from the view instance. [malthe]
- Expressions in text templates are never escaped. [malthe]
- Do not bind template to a trivial instance. [malthe]
1.0b10 (2009/02/24)
-------------------
- Fixed exists-traverser such that it always returns a boolean
value. [malthe]
1.0b9 (2009/02/19)
------------------
- When evaluating path-expressions at runtime (e.g. the ``path``
method), run the source through the transform first to support
dynamic scope. [malthe]
1.0b8 (2009/02/17)
------------------
- Allow attribute access to ``__call__`` method on bound page
templates. [malthe]
1.0b7 (2009/02/13)
------------------
- Fixed issue where symbol mapping would not be carried through under
a negation (not). [malthe]
- Optimize simple case: if path expression is a single path and path
is 'nothing' or has 'nocall:', just return value as-is, without
going through path_traverse. [sidnei]
- Moved evaluate_path and evaluate_exists over from ``five.pt``, adds
support for global ``path()`` and ``exists()`` functions for use in
``python:`` expressions (LP #317967).
- Added Zope security declaration for the repeat dictionary (tales
iterator). [malthe]
1.0b6 (2008/12/18)
------------------
- The 'not' pragma acts recursively. [malthe]
1.0b5 (2008/12/15)
------------------
- View templates now support argument-passing for alternative context
and request (for compatibility with
``zope.app.pagetemplate``). [malthe]
- Switched off the $-interpolation feature per default; It may be activated
on a per-template basis using ``meta:interpolation='true'``. [seletz]
- Allow more flexibility in overriding the PathTranslator method. [hannosch]
- Removed the forced defaultencoding from the benchmark suite. [hannosch]
1.0b4 (2008/11/19)
------------------
- Split out content provider function call to allow modification
through subclassing. [malthe]
- Added language negotiation. [malthe]
- Simplified template class inheritance. [malthe]
- Added support for the question-mark operator in path-expressions. [malthe]
- Updated expressions to recent API changes. [malthe]
- Added 'exists' and 'not' translators. [malthe]
Bug fixes
- Adjusted the bigtable benchmark test to API changes. [hannosch]
1.0b3 (2008/11/12)
------------------
- Added ``PageTemplate`` and ``PageTemplateFile`` classes. [malthe]
1.0b2 (2008/11/03)
------------------
Bug fixes
- Allow '.' character in content provider expressions.
- Allow '+' character in path-expressions.
1.0b1 (2008/10/02)
------------------
Package changes
- Split out compiler to "Chameleon" package. [malthe]
Backwards incompatibilities
- Moved contents of ``z3c.pt.macro`` module into
``z3c.pt.template``. [malthe]
- Namespace attribute "xmlns" no longer rendered for templates with no
explicit document type. [malthe]
- Changes to template method signatures. [malthe]
- Engine now expects all strings to be unicode or contain ASCII
characters only, unless an encoding is provided. [malthe]
- The default path traverser no longer proxies objects. [malthe]
- Template output is now always converted to unicode. [malthe]
- The ``ViewPageTemplateFile`` class now uses 'path' as the default
expression type. [malthe]
- The compiler now expects an instantiated parser instance. [malthe]
Features
- Added expression translator "provider:" (which renders a content
provider as defined in the ``zope.contentprovider``
package). [malthe]
- Added template API to render macros. [malthe]
- Optimized template loader so only a single template is instantiated
per file. [malthe]
- Made ``z3c.pt`` a namespace package. [malthe]
- Added reduce and restore operation to the compilation and rendering
flow in the test examples to verify integrity. [malthe]
- The ZPT parser now supports prefixed native attributes,
e.g. <tal:foo tal:bar="" />. [malthe]
- Source-code is now written to disk in debug mode. [malthe]
- Custom validation error is now raised if inserted string does not
validate (when debug mode is enabled). [malthe]
- Added support for omitting rendering of HTML "toggle" attributes
(option's ``selected`` and input's ``checked``) within dynamic
attribute assignment. If the value of the expression in the
assignment evaluates equal to boolean False, the attribute will not
be rendered. If the value of the expression in the assignment
evaluates equal to boolean True, the attribute will be rendered and
the value of the attribute will be the value returned by the
expression. [chrism]
- XML namespace attribute is now always printed for root tag. [malthe]
- Allow standard HTML entities. [malthe]
- Added compiler option to specify an implicit doctype; this is
currently used by the template classes to let the loose XHTML
doctype be the default. [malthe]
- Added support for translation of tag body. [malthe]
- Added security configuration for the TALES iterator (repeat
dictionary). This is made conditional on the availability of the
application security framework. [malthe]
- Dynamic attributes are now ordered as they appear in the
template. [malthe]
- Added ``symbol_mapping`` attribute to code streams such that
function dependencies can be registered at compile-time. [malthe]
- Allow BaseTemplate-derived classes (PageTemplate, PageTemplateFile,
et. al) to accept a ``doctype`` argument, which will override the
doctype supplied by the source of the template if specified. [chrism]
- Language negotiation is left to the page template superclass, so we
don't need to pass in a translation context anymore. [malthe]
- The ``ViewPageTemplateFile`` class now uses the module path of the
calling class to get an absolute path to a relative filename passed
to the constructor. [malthe]
- Added limited support for the XInclude ``include`` directive. The
implemented subset corresponds to the Genshi implementation, except
Match-templates, which are not made available to the calling
template. [malthe]
- Use a global template registry for templates on the
file-system. This makes it inexpensive to have multiple template
class instances pointing to the same file. [malthe]
- Reimplemented the disk cache to correctly restore all template
data. This implementation keeps a cache in a pickled format in a
file next to the original template. [malthe]
- Refactored compilation classes to better separate concerns. [malthe]
- Genshi macros (py:def) are now available globally. [malthe]
- A syntax error is now raised when an interpolation expression is not
exhausted, e.g. only a part of the string is a valid
Python-expression. [malthe]
- System variables are now defined in a configuration class. [malthe]
- Improve performance of codegen by not repeatedly calling
an expensive "flatten" function. [chrism]
- Remove ``safe_render`` implementation detail. It hid information
in tracebacks. [chrism]
- Implemented TAL global defines. [malthe]
- Added support for variables with global scope. [malthe]
- Curly braces may now be omitted in an expression interpolation if
the expression is just a variable name; this complies with the
Genshi syntax. [malthe]
- UTF-8 encode Unicode attribute literals. [chrism]
- Substantially reduced compiler overhead for lxml CDATA
workaround. [malthe]
- Split out element compiler classes for Genshi and Zope language
dialects. [malthe]
- Make lxml a setuptools "extra". To install with lxml support
(currently required by Genshi), specify "z3c.pt [lxml]" in
any references you need to make to the package in buildout or
in setup.py install_requires. [chrism]
- Add test-nolxml and py-nolxml parts to buildout so the package's
tests can be run without lxml. [chrism]
- No longer require default namespace. [malthe]
- Changed source code debug mode files to be named <filename>.py instead of
<filename>.source.
- Generalized ElementTree-import to allow both Python 2.5's
``xml.etree`` module and the standalone ``ElementTree``
package. [malthe]
- Expression results are now validated for XML correctness when the
compiler is running in debug-mode. [malthe]
- Preliminary support for using ``xml.etree`` as fallback for
``lxml.etree``. [malthe]
- String-expressions may now contain semi-colons using a double
semi-colon literal (;;). [malthe]
- Preserve CDATA sections. [malthe]
- Get rid of package-relative magic in constructor of BaseTemplateFile
in favor of just requiring an absolute path or a path relative
to getcwd(). Rationale: it didn't work when called from __main__
when the template was relative to getcwd(), which is the 99% case
for people first trying it out. [chrism]
- Added support for METAL.
[malthe]
- Add a TemplateLoader class to have a convenient method to instantiate
templates. This is similar to the template loaders from other template
toolkits and makes integration with Pylons a lot simpler.
[wichert]
- Switch from hardcoding all options in config.py to using parameters
for the template. This also allows us to use the more logical
auto_reload flag instead of reusing PROD_MODE, which is also used
for other purposes.
[wichert]
- Treat comments, processing instructions, and named entities in the
source template as "literals", which will be rendered into the
output unchanged. [chrism]
Bugfixes
- Skip elements in a "define-slot" clause if its being filled by the
calling template. [malthe]
- Support "fill-slot" on elements with METAL namespace. [malthe]
- Omit element text when rendering macro. [malthe]
- ``Macros`` class should not return callable functions, but rather a
``Macro`` object, which has a ``render``-method. This makes it
possible to use a path-expression to get to a macro without calling
it. [malthe]
- Fixed bug where a repeat-clause would reset the repeat variable
before evaluating the expression. [malthe]
- Fixed an issue related to correct restoring of ghosted template
objects. [malthe]
- Implicit doctype is correctly reestablished from cache. [malthe]
- Remove namespace declaration on root tag to work around syntax error
raised when parsing an XML tree loaded from the file cache. [malthe]
- Attribute assignments with an expression value that started with the
characters ``in`` (e.g. ``info.somename``) would be rendered to the
generated Python without the ``in`` prefix (as
e.g. ``fo.somename``). [chrism]
- When filling METAL slots (possibly with a specific version of
libxml2, I am using 2.6.32) it was possible to cause the translator
to attempt to add a stringtype to a NoneType (on a line that reads
``variable = self.symbols.slot+element.node.fill_slot`` because an
XPath expression looking for fill-slot nodes did not work
properly). [chrism]
- Preserve whitespace in string translation expressions. [malthe]
- Fixed interpolation bug where multiple attributes with interpolation
expressions would result in corrupted output. [malthe]
- Support try-except operator ('|') when 'python' is the default
expression type. [malthe]
- METAL macros should render in the template where they're
defined. [malthe]
- Avoid printing a line-break when we repeat over a single item
only. [malthe]
- Corrected Genshi namespace (needs a trailing slash). [malthe]
- Fixed a few more UnicodeDecodeErrors (test contributed by Wiggy).
In particular, never upcast to unicode during transformation, and
utf-8 encode Unicode attribute keys and values in Assign expressions
(e.g. py:attrs). [chrism]
- Fixed off-by-one bug in interpolation routine. [malthe]
- The repeat-clause should not output tail with every iteration. [malthe]
- CDATA sections are now correctly handled when using the
ElementTree-parser. [malthe]
- Fixed bug in path-expressions where string instances would be
(attempted) called. [malthe]
- CDATA sections are now correctly preserved when using expression
interpolation. [malthe]
- The Genshi interpolation operator ${} should not have its result
escaped when used in the text or tail regions. [malthe]
- Fixed edge case bug where inserting both a numeric entity and a
literal set of unicode bytes into the same document would cause a
UnicodeDecodeError. See also
http://groups.google.com/group/z3c_pt/browse_thread/thread/aea963d25a1778d0?hl=en
[chrism]
- Static attributes are now properly overriden by py:attr-attributes.
[malthe]
0.9 (2008/08/07)
----------------
- Added support for Genshi-templates.
[malthe]
- Cleanup and refactoring of translation module.
[malthe]
- If the template source contains a DOCTYPE declaration, output it
during rendering. [chrism]
- Fixed an error where numeric entities specified in text or tail
portions of elements would cause a UnicodeDecodeError to be raised
on systems configured with an 'ascii' default encoding. [chrism]
- Refactored file system based cache a bit and added a simple benchmark for
the cache. The initial load speed for a template goes down significantly
with the cache. Compared to zope.pagetemplate we are only 3x slower,
compared to 50x slower when cooking each template on process startup.
- Got rid entirely of the _escape function and inlined the actual code
instead. We go up again to 12x for path and 19x for Python expressions :)
[hannosch]
- Avoid string concatenation and use multiple write statements instead. These
are faster now, since we use a list append internally.
[hannosch]
- Inline the _escape function, because function calls are expensive in Python.
Added missing escaping for Unicode values.
[fschulze, hannosch]
- When templates are instantiated outside of a class-definition, a
relative file path will be made absolute using the module path.
[malthe]
- Simplified the _escape function handling by pulling in the str call into the
function. Corrected the bigtable hotshot test to only benchmark rendering.
- Replaced the cgi.escape function by an optimized local version, we go up
to 11x for path and 16x for Python expressions :) In the bigtable benchmark
the enhancement is more noticable - we are the same speed as spitfire -O1
templates now and just half the speed of -O3 :))
- Added a new benchmark test called bigtable that produces results which are
directly comparable to those produced by the bigtable.py benchmark in the
spitfire project.
- Introduce a new config option called `Z3C_PT_DISABLE_I18N`. If this
environment variable is set to `true`, the template engine will not call
into the zope.i18n machinery anymore, but fall back to simple interpolation
in all cases. In a normal Zope environment that has the whole i18n
infrastructure set up, this will render the templates about 15x faster than
normal TAL, instead of only 10x faster at this point.
- Removed the `second rendering` tests from the benchmark suite. Since we
enable the file cache for the benchmarks, there's no difference between the
first and second rendering anymore after the cache file has been written.
- Require zope.i18n 3.5 and add support for using its new negotiate function.
If you use the `zope_i18n_allowed_languages` environment variable the target
language for a template is only negotiated once per template, instead of
once for each translate function call. This more than doubles the speed
and the benchmark is back at 9.2 times faster.
- Extended the i18n handling to respect the passed in translation context to
the template. Usually this is the request, which is passed on under the
internal name of `_context` into the render functions. After extending the
i18n tests to include a negotiator and message catalog the improvement is
only at 4.5 anymore, as most of the time is spent inside the i18n machinery.
- Added persistent file cache functionality. If the environment variable is
set, each file system based template will add a directory to the cache
(currently a SHA-1 of the file's absolute path is used as the folder name)
and in the folder one file per params for the template (cache filename is
the hash of the params). Once a template file is initialized, an instance
local registry is added, which then looks up all cached files and
pre-populates the registry with the render functions.
- Fixed interpolation edge case bugs.
[malthe]
- Added new `Z3C_PT_FILECACHE` environment variable pointing to a directory.
If set, this will be used to cache the compiled files.
- Added a second variation of the repeat clause, using a simple for loop. It
doesn't support the repeatdict, though and is therefor not used yet. Also
began work to add introspection facilities to clauses about the variables
being used in them. The simpler loop causes the benchmarks to go up to a
10.5 (old 9.5) for path expressions and 14.5 (12.5) for python expressions.
So the next step is to introduce an optimization phase, that can decide
which variant of the loops to use.
- Made the debug mode independent from the Python debug mode. You can now
specify an environment variable called `Z3C_PT_DEBUG` to enable it.
- Added some code in a filecache module that can later be used to write out
and reload the compiled Python code to and from the file system. We should
be able to avoid reparsing on Python process restart.
- Simplified the generated _escape code. cgi.escape's second argument is a
simple boolean and not a list of characters to quote.
- Use a simple list based BufferIO class instead of a cStringIO for the out
stream. Avoiding the need to encode Unicode data is a bigger win. We do
not support arbitrarily mixing of Unicode and non-ascii inside the engine.
- Merged two adjacent writes into one inside the Tag clause.
- Applied a bunch of micro-optimizations. ''.join({}) is slightly faster
than ''.join({}.keys()) and does the same. Avoid a try/except for error
handling in non-debug mode. Test against 'is None' instead of a boolean
check for the result of the template registry lookup. Made PROD_MODE
available defined as 'not DEBUG_MODE' in config.py, so we avoid the 'not'
in every cook-check.
- Added more benchmark tests for the file variants.
- Optimized 'is None' handling in Tag clause similar to the Write clause.
- Made the _out.write method directly available as _write in all scopes, so
we avoid the method lookup call each time.
- Optimized 'is None' handling in Write clause.
- Slightly refactored benchmark tests and added tests for the file variants.
- In debug mode the actual source code for file templates is written out to
a <filename>.source file, to make it easier to inspect it.
- Make debug mode setting explicit in a config.py. Currently it is bound to
Python's __debug__, which is False when run with -O and otherwise True.
- Use a simplified UnicodeWrite clause for the result of _translate calls,
as the result value is guaranteed to be Unicode.
- Added benchmark tests for i18n handling.
- Added more tests for i18n attributes handling.
- Don't generate empty mappings for expressions with a trailing semicolon.
- Fixed undefined name 'static' error in i18n attributes handling and added
quoting to i18n attributes.
- Added condition to the valid attributes on tags in the tal namespace.
- Made sure the traceback from the *first* template exception
is carried over to __traceback_info__
- Added template source annotations on exceptions raised while
rendering a template.
0.8 (2008/03/19)
----------------
- Added support for 'nocall' and 'not' (for path-expressions).
- Added support for path- and string-expressions.
- Abstracted expression translation engine. Expression implementations
are now pluggable. Expression name pragmas are supported throughout.
- Formalized expression types
- Added support for 'structure'-keyword for replace and content.
- Result of 'replace' and 'content' is now escaped by default.
- Benchmark is now built as a custom testrunner
0.7 (2008/03/10)
----------------
- Added support for comments; expressions are allowed
inside comments, i.e.
<!-- ${'Hello World!'} -->
Comments are always included.
0.7 (2008/02/24)
----------------
- Added support for text templates; these allow expression
interpolation in non-XML documents like CSS stylesheets and
javascript files.
0.5 (2008/02/23)
----------------
- Expression interpolation implemented.
0.4 (2008/02/22)
----------------
- Engine now uses cStringIO yielding a 2.5x performance
improvement. Unicode is now handled correctly.
0.3 (2007/12/23)
----------------
- Code optimization; bug fixing spree
- Added ``ViewPageTemplateFile`` class
- Added support for i18n
- Engine rewrite; improved code generation abstractions
0.2 (2007/12/05)
----------------
- Major optimizations to the generated code
0.1 (2007/12/03)
----------------
- First public release
Raw data
{
"_id": null,
"home_page": "https://github.com/zopefoundation/z3c.pt",
"name": "z3c.pt",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "tal tales pagetemplate zope chameleon",
"author": "Malthe Borch and the Zope Community",
"author_email": "zope-dev@zope.org",
"download_url": "https://files.pythonhosted.org/packages/a0/bc/ddce4fd09343f44a1479a425d8f04ec494311c03331044e37df0e6afa49e/z3c.pt-4.4.tar.gz",
"platform": null,
"description": "========\n z3c.pt\n========\n\n.. image:: https://img.shields.io/pypi/v/z3c.pt.svg\n :target: https://pypi.python.org/pypi/z3c.pt/\n :alt: Latest release\n\n.. image:: https://img.shields.io/pypi/pyversions/z3c.pt.svg\n :target: https://pypi.org/project/z3c.pt/\n :alt: Supported Python versions\n\n.. image:: https://github.com/zopefoundation/z3c.pt/actions/workflows/tests.yml/badge.svg\n :target: https://github.com/zopefoundation/z3c.pt/actions/workflows/tests.yml\n\n.. image:: https://coveralls.io/repos/github/zopefoundation/z3c.pt/badge.svg?branch=master\n :target: https://coveralls.io/github/zopefoundation/z3c.pt?branch=master\n\n.. image:: https://readthedocs.org/projects/z3cpt/badge/?version=latest\n :target: https://z3cpt.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\nThis is a fast implementation of the ZPT template engine for Zope 3\nwhich uses Chameleon to compile templates to byte-code.\n\nThe package provides application support equivalent to\n``zope.pagetemplate``.\n\n\n==========\n Overview\n==========\n\nThis section demonstrates the high-level template classes. All page\ntemplate classes in ``z3c.pt`` use path-expressions by default.\n\nPage templates\n==============\n\n >>> from z3c.pt.pagetemplate import PageTemplate\n >>> from z3c.pt.pagetemplate import PageTemplateFile\n\nThe ``PageTemplate`` class is initialized with a string.\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... Hello World!\n ... </div>\"\"\")\n\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\nThe ``PageTemplateFile`` class is initialized with an absolute\npath to a template file on disk.\n\n >>> template_file = PageTemplateFile('tests/helloworld.pt')\n >>> print(template_file())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\n >>> import os\n >>> os.path.isabs(template_file.filename)\n True\n\nIf a ``content_type`` is not informed and one is not present in the\nrequest, it will be set to 'text/html'.\n\n >>> class Response(object):\n ... def __init__(self):\n ... self.headers = {}\n ... self.getHeader = self.headers.get\n ... self.setHeader = self.headers.__setitem__\n\n >>> class Request(object):\n ... def __init__(self):\n ... self.response = Response()\n\n >>> template_file = PageTemplateFile('tests/helloworld.pt')\n >>> request = Request()\n >>> print(request.response.getHeader('Content-Type'))\n None\n\n >>> template = template_file.bind(None, request=request)\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\n >>> print(request.response.getHeader('Content-Type'))\n text/html\n\nIf a ``content_type`` is present in the request, then we don't override it.\n\n >>> request = Request()\n >>> request.response.setHeader('Content-Type', 'text/xml')\n >>> print(request.response.getHeader('Content-Type'))\n text/xml\n\n >>> template = template_file.bind(None, request=request)\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\n >>> print(request.response.getHeader('Content-Type'))\n text/xml\n\nA ``content_type`` can be also set at instantiation time, and it will\nbe respected.\n\n >>> template_file = PageTemplateFile('tests/helloworld.pt',\n ... content_type='application/rdf+xml')\n\n >>> request = Request()\n >>> print(request.response.getHeader('Content-Type'))\n None\n\n >>> template = template_file.bind(None, request=request)\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\n >>> print(request.response.getHeader('Content-Type'))\n application/rdf+xml\n\nBoth may be used as class attributes (properties).\n\n >>> class MyClass(object):\n ... template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... Hello World!\n ... </div>\"\"\")\n ...\n ... template_file = PageTemplateFile('tests/helloworld.pt')\n\n >>> instance = MyClass()\n >>> print(instance.template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\n >>> print(instance.template_file())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n Hello World!\n </div>\n\nView page templates\n===================\n\n >>> from z3c.pt.pagetemplate import ViewPageTemplate\n >>> from z3c.pt.pagetemplate import ViewPageTemplateFile\n\n >>> class View(object):\n ... request = u'request'\n ... context = u'context'\n ...\n ... def __repr__(self):\n ... return 'view'\n\n >>> view = View()\n\nAs before, we can initialize view page templates with a string (here\nincidentally loaded from disk).\n\n >>> from z3c.pt import tests\n >>> path = tests.__path__[0]\n >>> with open(path + '/view.pt') as f:\n ... template = ViewPageTemplate(f.read())\n\nTo render the template in the context of a view, we bind the template\npassing the view as an argument (view page templates derive from the\n``property``-class and are usually defined as an attribute on a view\nclass).\n\n >>> print(template.bind(view)(test=u'test'))\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>view</span>\n <span>context</span>\n <span>request</span>\n <span>test</span>\n <span>test</span>\n </div>\n\nThe exercise is similar for the file-based variant.\n\n >>> template = ViewPageTemplateFile('tests/view.pt')\n >>> print(template.bind(view)(test=u'test'))\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>view</span>\n <span>context</span>\n <span>request</span>\n <span>test</span>\n <span>test</span>\n </div>\n\nFor compatibility reasons, view templates may be called with an\nalternative context and request.\n\n >>> print(template(view, u\"alt_context\", \"alt_request\", test=u'test'))\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>view</span>\n <span>alt_context</span>\n <span>alt_request</span>\n <span>test</span>\n <span>test</span>\n </div>\n\n\nNon-keyword arguments\n=====================\n\nThese are passed in as ``options/args``, when using the ``__call__`` method.\n\n >>> print(PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <div tal:repeat=\"arg options/args\">\n ... <span tal:content=\"arg\" />\n ... </div>\n ... </div>\"\"\").__call__(1, 2, 3))\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <div>\n <span>1</span>\n </div>\n <div>\n <span>2</span>\n </div>\n <div>\n <span>3</span>\n </div>\n </div>\n\n\nGlobal 'path' Function\n======================\n\nJust like ``zope.pagetemplate``, it is possible to use a globally\ndefined ``path()`` function in a ``python:`` expression in ``z3c.pt``:\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:content=\"options/test\" />\n ... <span tal:content=\"python: path('options/test')\" />\n ... </div>\"\"\")\n\n >>> print(template(test='test'))\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>test</span>\n <span>test</span>\n </div>\n\nGlobal 'exists' Function\n========================\n\nThe same applies to the ``exists()`` function:\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:content=\"python: exists('options/test') and 'Yes' or 'No'\" />\n ... </div>\"\"\")\n\n >>> print(template(test='test'))\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>Yes</span>\n </div>\n\n'default' and path expressions\n==============================\n\nAnother feature from standard ZPT: using 'default' means whatever the\nthe literal HTML contains will be output if the condition is not met.\n\nThis works for attributes:\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:attributes=\"class options/not-existing | default\"\n ... class=\"blue\">i'm blue</span>\n ... </div>\"\"\")\n\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span class=\"blue\">i'm blue</span>\n </div>\n\nAnd also for contents:\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:content=\"options/not-existing | default\">default content</span>\n ... </div>\"\"\")\n\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>default content</span>\n </div>\n\n'exists'-type expression\n========================\n\nUsing 'exists()' function on non-global name and global name:\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:content=\"python: exists('options/nope') and 'Yes' or 'No'\">do I exist?</span>\n ... <span tal:content=\"python: exists('nope') and 'Yes' or 'No'\">do I exist?</span>\n ... </div>\"\"\")\n\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>No</span>\n <span>No</span>\n </div>\n\nUsing 'exists:' expression on non-global name and global name\n\n >>> template = PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:define=\"yup exists:options/nope\"\n ... tal:content=\"python: yup and 'Yes' or 'No'\">do I exist?</span>\n ... <span tal:define=\"yup exists:nope\"\n ... tal:content=\"python: yup and 'Yes' or 'No'\">do I exist?</span>\n ... </div>\"\"\")\n\n >>> print(template())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>No</span>\n <span>No</span>\n </div>\n\nUsing 'exists:' in conjunction with a negation:\n\n >>> print(PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ... <span tal:condition=\"not:exists:options/nope\">I don't exist?</span>\n ... </div>\"\"\")())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>I don't exist?</span>\n </div>\n\npath expression with dictionaries\n=================================\n\nPath expressions give preference to dictionary items instead of\ndictionary attributes.\n\n >>> print(PageTemplate(\"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\"\n ... tal:define=\"links python:{'copy':'XXX', 'delete':'YYY'}\">\n ... <span tal:content=\"links/copy\">ZZZ</span>\n ... </div>\"\"\")())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>XXX</span>\n </div>\n\n\nVariable from one tag never leak into another\n=============================================\n\n >>> body = \"\"\"\\\n ... <div xmlns=\"http://www.w3.org/1999/xhtml\"\n ... xmlns:tal=\"http://xml.zope.org/namespaces/tal\"\n ... xmlns:metal=\"http://xml.zope.org/namespaces/metal\">\n ... <div class=\"macro\" metal:define-macro=\"greeting\"\n ... tal:define=\"greeting greeting|string:'Hey'\">\n ... <span tal:replace=\"greeting\" />\n ... </div>\n ... <div tal:define=\"greeting string:'Hello'\">\n ...\t <metal:block metal:use-macro=\"python:template.macros['greeting']\" />\n ... </div>\n ... <div>\n ...\t <metal:block metal:use-macro=\"python:template.macros['greeting']\" />\n ... </div>\n ... </div>\"\"\"\n >>> print(PageTemplate(body)())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <div class=\"macro\">\n 'Hey'\n </div>\n <div>\n <div class=\"macro\">\n 'Hello'\n </div>\n <BLANKLINE>\n </div>\n <div>\n <div class=\"macro\">\n 'Hey'\n </div>\n <BLANKLINE>\n </div>\n </div>\n\n\n\nTALES Function Namespaces\n=========================\n\nAs described on http://wiki.zope.org/zope3/talesns.html, it is\npossible to implement custom TALES Namespace Adapters. We also support\nlow-level TALES Function Namespaces (which the TALES Namespace\nAdapters build upon).\n\n >>> import datetime\n >>> import zope.interface\n >>> import zope.component\n >>> from zope.traversing.interfaces import ITraversable\n >>> from zope.traversing.interfaces import IPathAdapter\n >>> from zope.tales.interfaces import ITALESFunctionNamespace\n >>> from z3c.pt.namespaces import function_namespaces\n\n >>> @zope.interface.implementer(ITALESFunctionNamespace)\n ... class ns1(object):\n ... def __init__(self, context):\n ... self.context = context\n ... def parent(self):\n ... return self.context.parent\n\n >>> function_namespaces.namespaces['ns1'] = ns1\n\n >>> class ns2(object):\n ... def __init__(self, context):\n ... self.context = context\n ... def upper(self):\n ... return self.context.upper()\n\n >>> zope.component.getGlobalSiteManager().registerAdapter(\n ... ns2, [zope.interface.Interface], IPathAdapter, 'ns2')\n\n >>> class ns3(object):\n ... def __init__(self, context):\n ... self.context = context\n ... def fullDateTime(self):\n ... return self.context.strftime('%Y-%m-%d %H:%M:%S')\n\n >>> zope.component.getGlobalSiteManager().registerAdapter(\n ... ns3, [zope.interface.Interface], IPathAdapter, 'ns3')\n\n\nA really corner-ish case from a legacy application: the TALES\nNamespace Adapter doesn't have a callable function but traverses the\nremaining path instead::\n\n >>> from zope.traversing.interfaces import TraversalError\n\n >>> @zope.interface.implementer(ITraversable)\n ... class ns4(object):\n ...\n ... def __init__(self, context):\n ... self.context = context\n ...\n ... def traverse(self, name, furtherPath):\n ... if name == 'page':\n ... if len(furtherPath) == 1:\n ...\t\t pagetype = furtherPath.pop()\n ...\t\t elif not furtherPath:\n ... pagetype = 'default'\n ... else:\n ... raise TraversalError(\"Max 1 path segment after ns4:page\")\n ... return self._page(pagetype)\n ... if len(furtherPath) == 1:\n ... name = '%s/%s' % (name, furtherPath.pop())\n ... return 'traversed: ' + name\n ...\n ... def _page(self, pagetype):\n ... return 'called page: ' + pagetype\n\n >>> zope.component.getGlobalSiteManager().registerAdapter(\n ... ns4, [zope.interface.Interface], IPathAdapter, 'ns4')\n\n >>> @zope.interface.implementer(ITraversable)\n ... class ns5(object):\n ...\n ... def __init__(self, context):\n ... self.context = context\n ...\n ... def traverse(self, name, furtherPath):\n ...\t name = '/'.join([name] + furtherPath[::-1])\n ...\t del furtherPath[:]\n ...\t return 'traversed: ' + name\n\n >>> zope.component.getGlobalSiteManager().registerAdapter(\n ... ns5, [zope.interface.Interface], IPathAdapter, 'ns5')\n\n >>> class Ob(object):\n ... def __init__(self, title, date, parent=None, child=None):\n ... self.title = title\n ... self.date = date\n ... self.parent = parent\n ... self.child = child\n\n >>> child = Ob('child', datetime.datetime(2008, 12, 30, 13, 48, 0, 0))\n >>> father = Ob('father', datetime.datetime(1978, 12, 30, 13, 48, 0, 0))\n >>> grandpa = Ob('grandpa', datetime.datetime(1948, 12, 30, 13, 48, 0, 0))\n\n >>> child.parent = father\n >>> father.child = child\n >>> father.parent = grandpa\n >>> grandpa.child = father\n\n >>> class View(object):\n ... request = u'request'\n ... context = father\n ...\n ... def __repr__(self):\n ... return 'view'\n\n >>> view = View()\n >>> template = ViewPageTemplateFile('tests/function_namespaces.pt')\n >>> print(template.bind(view)())\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n <span>GRANDPA</span>\n <span>2008-12-30 13:48:00</span>\n <span>traversed: link:main</span>\n <span>called page: default</span>\n <span>called page: another</span>\n <span></span>\n <span>traversed: zope.Public</span>\n <span>traversed: text-to-html</span>\n <span>traversed: page/yet/even/another</span>\n </div>\n\n\n===========\n Changelog\n===========\n\n4.4 (2024-08-07)\n================\n\n- Extend boolean html attribute list to include all html5 boolean attributes.\n\n\n4.3 (2024-02-01)\n================\n\n- Add support for Python 3.12.\n\n- Fix Windows test compatibility.\n\n4.2 (2024-01-31)\n================\n\n- Add support for \"structure\" expression type.\n (`Issue #17 <https://github.com/zopefoundation/z3c.pt/issues/17>`_).\n\n- Updated test suite to be compatible with newer Chameleon releases.\n\n4.1 (2024-01-09)\n================\n\n- Provide own interfaces, since Chameleon will not provide those in a\n future release.\n\n\n4.0 (2023-03-27)\n================\n\n- Add support for Python 3.11.\n\n- Drop support for Python 2.7, 3.5, 3.6.\n\n\n3.3.1 (2021-12-17)\n==================\n\n- Add support for Python 3.9, and 3.10.\n\n\n3.3.0 (2020-03-31)\n==================\n\n- Drop support for Python 3.4\n\n- Add support for Python 3.8.\n\n- Prevent interpolation (i.e. ``$``*var*, ``${``*path*``}`` replacements)\n inside comments\n (`Zope #716 <https://github.com/zopefoundation/Zope/issues/716>`_).\n\n\n3.2.0 (2019-01-05)\n==================\n\n- Add support for Python 3.7.\n\n- Drop support for running the tests using `python setup.py test`.\n\n\n3.1.0 (2017-10-17)\n==================\n\n- Add support for Python 3.6.\n- Drop support for Python 3.3.\n- Use the adapter namespace from ``zope.pagetemplate`` if it's\n available, instead of the backwards compatibility shim in\n ``zope.app.pagetemplate``. See `issue 3\n <https://github.com/zopefoundation/z3c.pt/issues/3>`_.\n- Add the ``string`` and ``nocall`` functions for use inside Python\n expressions. See `issue 2\n <https://github.com/zopefoundation/z3c.pt/issues/2>`_.\n- Make bound page templates have ``__self__`` and ``__func__``\n attributes to be more like Python 3 bound methods. (``im_func`` and\n ``im_self`` remain available.) See `issue 9\n <https://github.com/zopefoundation/z3c.pt/issues/9>`_.\n\n\n3.0 (2016-09-02)\n================\n\n- Added support for Python 3.4, 3.5, PyPy and PyPy3.\n\n- Dropped support for Python 2.6.\n\n\n3.0.0a1 (2013-02-25)\n====================\n\nCompatibility:\n\n- Added support for Python 3.3.\n\n- Added a small patch to ``chameleon.i18n`` to define ``basestring``.\n\nBugfixes:\n\n- Allow segments of path expressions to start with a digit.\n\n\n2.2.3 (2012-06-01)\n==================\n\nCompatibility:\n\n- The translation function now accepts (but ignores) a ``context``\n argument. This fixes a compatibility issue with Chameleon 2.9.x.\n\n2.2.2 (2012-04-24)\n==================\n\nBugfixes:\n\n- Do not rely on the \"LANGUAGE\" request key to skip language\n negotiation. Instead, we assume that negotiation is cheap (and\n probably cached).\n\n2.2.1 (2012-02-15)\n==================\n\n- Only require Chameleon >= 2.4, was needlessly bumped in last release.\n\n- Add test extra, remove versions from buildout.cfg.\n\n\n2.2 (2012-01-08)\n================\n\nFeatures:\n\n- Whitespace between attributes is now reduced to a single whitespace\n character.\n\n- The ``request`` symbol is no longer required to evaluate a path\n expression; it now defaults to ``None`` if not present in the\n namespace.\n\nBugfixes:\n\n- The content provider expression now correctly applies TAL namespace\n data.\n\nChanges:\n\n- The ``ZopeTraverser`` class has been removed and replaced with a\n simple function.\n\n2.1.5 (2011-11-24)\n==================\n\n- Use non-strict mode if available for compatibility with the\n reference engine where expressions are only compiled at evaluation\n time.\n\n2.1.4 (2011-09-14)\n==================\n\n- The provider expression is now first evaluated as a string\n expression, the result of which is used as the content provider\n name.\n\n This fixes an issue where (provider-) string expressions would not\n get evaluated correctly, e.g. ``provider: ${mgr}``.\n\n2.1.3 (2011-08-22)\n==================\n\n- Configure HTML boolean attributes (in HTML-mode only)::\n\n \"compact\", \"nowrap\", \"ismap\", \"declare\", \"noshade\",\n \"checked\", \"disabled\", \"readonly\", \"multiple\", \"selected\",\n \"noresize\", \"defer\"\n\n2.1.2 (2011-08-19)\n==================\n\n- Enable option ``literal_false`` to get the behavior that a value of\n ``False`` does not drop an attribute.\n\n2.1.1 (2011-08-11)\n==================\n\n- Make sure the builtin names 'path' and 'exists' can be redefined.\n\n- Guard ``sys.modules`` (mapped to the builtin variable \"modules\")\n against import-time side effects using ``ProxyFactory``.\n\n2.1 (2011-07-28)\n================\n\n- Use dynamic expression evaluation framework that comes included with\n Chameleon.\n\n2.0 (2011-07-14)\n================\n\n- Point release.\n\n- Move implementation-specific context setup to ``render``\n method. This allows use of template class with an already prepared\n context.\n\n- Fixed issue with the call flag on the Zope traverser compiler.\n\n2.0-rc3 (2011-07-11)\n====================\n\n- Python-expressions are no longer TALES-expressions; previously, the\n pipe operator would split Python expression clauses, allowing\n fallbacks even for Python expressions, but this is not the standard\n behavior of ZPT.\n\n- Fixed an issue where an error which occurred inside a dynamic\n ``path`` or ``exists`` evaluation would fail to propagate due to a\n missing remote context.\n\n- Set variables ``here`` and ``context`` to the bound instance value\n on ``PageTemplate`` instances.\n\n2.0-rc2 (2011-03-24)\n====================\n\n- Fixed an issue with ``\"exists:\"`` expression where a callable would\n be attempted called. It is meanwhile implied with this expression\n types that it should use the ``\"nocall:\"`` pragma.\n\n\n2.0-rc1 (2011-02-28)\n====================\n\n- Update to Chameleon 2.0.\n\n This release includes many changes and is a complete rewrite of the\n 1.x series.\n\n Platform:\n\n * Python 2.5+ now required.\n\n Notable changes:\n\n * Expression interpolation is always enabled.\n\n * Whitespace output is different, now closely aligned to the\n template input.\n\n * New language constructs:\n\n 1) tal:on-error\n 2) tal:switch\n 3) tal:case\n\n Incompatibilities:\n\n * The expression translation interface has been replaced with an\n expression engine. This means that all expressions must be\n rewritten.\n\n- The exists expression evaluator should ignore KeyError exceptions\n as well.\n\n- Special-case handling of Zope2's Missing.MV as used by\n Products.ZCatalog for LP#649343.\n [rossp]\n\n1.2.1 (2010/05/13)\n------------------\n\n- Bind template to the template object in the general case.\n\n1.2 (2010/05/12)\n----------------\n\n- Fixed compatibility issue with recent change in Chameleon.\n\n- Fixed regression introduced with ``args`` being passed\n in. Incidentally, the name ``args`` was used as the star argument\n name.\n\n- Look at language set on request before invoking the zope.i18n\n negotiator. This makes i18n work again on Zope2.\n\n1.1.1 (2010/04/06)\n------------------\n\n- Fixed issue where arguments were not passed on to template as\n ``args``.\n\n1.1.0 (2010/01/09)\n------------------\n\n- Update to combined Chameleon distribution.\n\n1.0.1 (2009/07/06)\n------------------\n\n- Bind translation context (request) to translation method. Although\n not required in newer versions of the translation machinery, some\n versions will ask for a translation context in order to negotiate\n language even when a language is explicitly passed in.\n\n- Declare zope security settings for classes when zope.security is present\n as the \"class\" ZCML directive was moved there.\n\n1.0.0 (2009/07/06)\n------------------\n\n- First point release.\n\n1.0b17 (2009/06/14)\n-------------------\n\n- Made the Zope security declaration for the repeat dictionary be conditional\n on the presence of zope.app.security instead of zope.app.component.\n\n1.0b16 (2009/05/20)\n-------------------\n\n- Updated run-time expression evaluator method to work after a recent\n architectural change in Chameleon. [malthe]\n\n- Check that we have a non-trivial response-object before trying to\n set the content type. [malthe]\n\n- Wrap ``sys.modules`` dictionary in an \"opaque\" dictionary class,\n such that the representation string does not list all loaded\n modules. [malthe]\n\n1.0b15 (2009/04/24)\n-------------------\n\n- Removed lxml extra, as we do no longer depend on it. [malthe]\n\n- Make sure the path expression is a simple string, not\n unicode. [malthe]\n\n- Detect path prefix properly for ViewPageTemplateFile usage in\n doctests. [sidnei]\n\n- The ``template`` symbol is already set by the template base\n class. [malthe]\n\n- Set Content-Type header, for backwards compatibility with\n zope.app.pagetemplate. [sidnei]\n\n1.0b14 (2009/03/31)\n-------------------\n\n- Updated language adapter to work with 'structure' meta\n attribute. [malthe]\n\n1.0b13 (2009/03/23)\n-------------------\n\n- When traversing on dictionaries, only exposes dictionary items\n (never attributes); this is to avoid ambiguity. [sidnei, malthe]\n\n- Path expressions need to pass further path items in reverse order to\n traversePathElement, because that's what it expects. [sidnei]\n\n1.0b12 (2009/03/09)\n-------------------\n\n- Insert initial variable context into dynamic scope. The presence of\n these is expected by many application. [malthe]\n\n1.0b11 (2009/03/05)\n-------------------\n\n- If a namespace-acquired object provides ``ITraversable``, use path\n traversal. [malthe]\n\n- Implemented TALES function namespaces. [sidnei, malthe]\n\n- Catch ``NameError`` in exists-traverser (return false). [malthe]\n\n- Catch ``NameError`` in exists-evaluator (return false). [malthe]\n\n- If the supplied ``context`` and ``request`` parameters are trivial,\n get them from the view instance. [malthe]\n\n- Expressions in text templates are never escaped. [malthe]\n\n- Do not bind template to a trivial instance. [malthe]\n\n1.0b10 (2009/02/24)\n-------------------\n\n- Fixed exists-traverser such that it always returns a boolean\n value. [malthe]\n\n1.0b9 (2009/02/19)\n------------------\n\n- When evaluating path-expressions at runtime (e.g. the ``path``\n method), run the source through the transform first to support\n dynamic scope. [malthe]\n\n1.0b8 (2009/02/17)\n------------------\n\n- Allow attribute access to ``__call__`` method on bound page\n templates. [malthe]\n\n1.0b7 (2009/02/13)\n------------------\n\n- Fixed issue where symbol mapping would not be carried through under\n a negation (not). [malthe]\n\n- Optimize simple case: if path expression is a single path and path\n is 'nothing' or has 'nocall:', just return value as-is, without\n going through path_traverse. [sidnei]\n\n- Moved evaluate_path and evaluate_exists over from ``five.pt``, adds\n support for global ``path()`` and ``exists()`` functions for use in\n ``python:`` expressions (LP #317967).\n\n- Added Zope security declaration for the repeat dictionary (tales\n iterator). [malthe]\n\n1.0b6 (2008/12/18)\n------------------\n\n- The 'not' pragma acts recursively. [malthe]\n\n1.0b5 (2008/12/15)\n------------------\n\n- View templates now support argument-passing for alternative context\n and request (for compatibility with\n ``zope.app.pagetemplate``). [malthe]\n\n- Switched off the $-interpolation feature per default; It may be activated\n on a per-template basis using ``meta:interpolation='true'``. [seletz]\n\n- Allow more flexibility in overriding the PathTranslator method. [hannosch]\n\n- Removed the forced defaultencoding from the benchmark suite. [hannosch]\n\n1.0b4 (2008/11/19)\n------------------\n\n- Split out content provider function call to allow modification\n through subclassing. [malthe]\n\n- Added language negotiation. [malthe]\n\n- Simplified template class inheritance. [malthe]\n\n- Added support for the question-mark operator in path-expressions. [malthe]\n\n- Updated expressions to recent API changes. [malthe]\n\n- Added 'exists' and 'not' translators. [malthe]\n\n Bug fixes\n\n- Adjusted the bigtable benchmark test to API changes. [hannosch]\n\n1.0b3 (2008/11/12)\n------------------\n\n- Added ``PageTemplate`` and ``PageTemplateFile`` classes. [malthe]\n\n1.0b2 (2008/11/03)\n------------------\n\n Bug fixes\n\n- Allow '.' character in content provider expressions.\n\n- Allow '+' character in path-expressions.\n\n1.0b1 (2008/10/02)\n------------------\n\n Package changes\n\n- Split out compiler to \"Chameleon\" package. [malthe]\n\n Backwards incompatibilities\n\n- Moved contents of ``z3c.pt.macro`` module into\n ``z3c.pt.template``. [malthe]\n\n- Namespace attribute \"xmlns\" no longer rendered for templates with no\n explicit document type. [malthe]\n\n- Changes to template method signatures. [malthe]\n\n- Engine now expects all strings to be unicode or contain ASCII\n characters only, unless an encoding is provided. [malthe]\n\n- The default path traverser no longer proxies objects. [malthe]\n\n- Template output is now always converted to unicode. [malthe]\n\n- The ``ViewPageTemplateFile`` class now uses 'path' as the default\n expression type. [malthe]\n\n- The compiler now expects an instantiated parser instance. [malthe]\n\n Features\n\n- Added expression translator \"provider:\" (which renders a content\n provider as defined in the ``zope.contentprovider``\n package). [malthe]\n\n- Added template API to render macros. [malthe]\n\n- Optimized template loader so only a single template is instantiated\n per file. [malthe]\n\n- Made ``z3c.pt`` a namespace package. [malthe]\n\n- Added reduce and restore operation to the compilation and rendering\n flow in the test examples to verify integrity. [malthe]\n\n- The ZPT parser now supports prefixed native attributes,\n e.g. <tal:foo tal:bar=\"\" />. [malthe]\n\n- Source-code is now written to disk in debug mode. [malthe]\n\n- Custom validation error is now raised if inserted string does not\n validate (when debug mode is enabled). [malthe]\n\n- Added support for omitting rendering of HTML \"toggle\" attributes\n (option's ``selected`` and input's ``checked``) within dynamic\n attribute assignment. If the value of the expression in the\n assignment evaluates equal to boolean False, the attribute will not\n be rendered. If the value of the expression in the assignment\n evaluates equal to boolean True, the attribute will be rendered and\n the value of the attribute will be the value returned by the\n expression. [chrism]\n\n- XML namespace attribute is now always printed for root tag. [malthe]\n\n- Allow standard HTML entities. [malthe]\n\n- Added compiler option to specify an implicit doctype; this is\n currently used by the template classes to let the loose XHTML\n doctype be the default. [malthe]\n\n- Added support for translation of tag body. [malthe]\n\n- Added security configuration for the TALES iterator (repeat\n dictionary). This is made conditional on the availability of the\n application security framework. [malthe]\n\n- Dynamic attributes are now ordered as they appear in the\n template. [malthe]\n\n- Added ``symbol_mapping`` attribute to code streams such that\n function dependencies can be registered at compile-time. [malthe]\n\n- Allow BaseTemplate-derived classes (PageTemplate, PageTemplateFile,\n et. al) to accept a ``doctype`` argument, which will override the\n doctype supplied by the source of the template if specified. [chrism]\n\n- Language negotiation is left to the page template superclass, so we\n don't need to pass in a translation context anymore. [malthe]\n\n- The ``ViewPageTemplateFile`` class now uses the module path of the\n calling class to get an absolute path to a relative filename passed\n to the constructor. [malthe]\n\n- Added limited support for the XInclude ``include`` directive. The\n implemented subset corresponds to the Genshi implementation, except\n Match-templates, which are not made available to the calling\n template. [malthe]\n\n- Use a global template registry for templates on the\n file-system. This makes it inexpensive to have multiple template\n class instances pointing to the same file. [malthe]\n\n- Reimplemented the disk cache to correctly restore all template\n data. This implementation keeps a cache in a pickled format in a\n file next to the original template. [malthe]\n\n- Refactored compilation classes to better separate concerns. [malthe]\n\n- Genshi macros (py:def) are now available globally. [malthe]\n\n- A syntax error is now raised when an interpolation expression is not\n exhausted, e.g. only a part of the string is a valid\n Python-expression. [malthe]\n\n- System variables are now defined in a configuration class. [malthe]\n\n- Improve performance of codegen by not repeatedly calling\n an expensive \"flatten\" function. [chrism]\n\n- Remove ``safe_render`` implementation detail. It hid information\n in tracebacks. [chrism]\n\n- Implemented TAL global defines. [malthe]\n\n- Added support for variables with global scope. [malthe]\n\n- Curly braces may now be omitted in an expression interpolation if\n the expression is just a variable name; this complies with the\n Genshi syntax. [malthe]\n\n- UTF-8 encode Unicode attribute literals. [chrism]\n\n- Substantially reduced compiler overhead for lxml CDATA\n workaround. [malthe]\n\n- Split out element compiler classes for Genshi and Zope language\n dialects. [malthe]\n\n- Make lxml a setuptools \"extra\". To install with lxml support\n (currently required by Genshi), specify \"z3c.pt [lxml]\" in\n any references you need to make to the package in buildout or\n in setup.py install_requires. [chrism]\n\n- Add test-nolxml and py-nolxml parts to buildout so the package's\n tests can be run without lxml. [chrism]\n\n- No longer require default namespace. [malthe]\n\n- Changed source code debug mode files to be named <filename>.py instead of\n <filename>.source.\n\n- Generalized ElementTree-import to allow both Python 2.5's\n ``xml.etree`` module and the standalone ``ElementTree``\n package. [malthe]\n\n- Expression results are now validated for XML correctness when the\n compiler is running in debug-mode. [malthe]\n\n- Preliminary support for using ``xml.etree`` as fallback for\n ``lxml.etree``. [malthe]\n\n- String-expressions may now contain semi-colons using a double\n semi-colon literal (;;). [malthe]\n\n- Preserve CDATA sections. [malthe]\n\n- Get rid of package-relative magic in constructor of BaseTemplateFile\n in favor of just requiring an absolute path or a path relative\n to getcwd(). Rationale: it didn't work when called from __main__\n when the template was relative to getcwd(), which is the 99% case\n for people first trying it out. [chrism]\n\n- Added support for METAL.\n [malthe]\n\n- Add a TemplateLoader class to have a convenient method to instantiate\n templates. This is similar to the template loaders from other template\n toolkits and makes integration with Pylons a lot simpler.\n [wichert]\n\n- Switch from hardcoding all options in config.py to using parameters\n for the template. This also allows us to use the more logical\n auto_reload flag instead of reusing PROD_MODE, which is also used\n for other purposes.\n [wichert]\n\n- Treat comments, processing instructions, and named entities in the\n source template as \"literals\", which will be rendered into the\n output unchanged. [chrism]\n\n Bugfixes\n\n- Skip elements in a \"define-slot\" clause if its being filled by the\n calling template. [malthe]\n\n- Support \"fill-slot\" on elements with METAL namespace. [malthe]\n\n- Omit element text when rendering macro. [malthe]\n\n- ``Macros`` class should not return callable functions, but rather a\n ``Macro`` object, which has a ``render``-method. This makes it\n possible to use a path-expression to get to a macro without calling\n it. [malthe]\n\n- Fixed bug where a repeat-clause would reset the repeat variable\n before evaluating the expression. [malthe]\n\n- Fixed an issue related to correct restoring of ghosted template\n objects. [malthe]\n\n- Implicit doctype is correctly reestablished from cache. [malthe]\n\n- Remove namespace declaration on root tag to work around syntax error\n raised when parsing an XML tree loaded from the file cache. [malthe]\n\n- Attribute assignments with an expression value that started with the\n characters ``in`` (e.g. ``info.somename``) would be rendered to the\n generated Python without the ``in`` prefix (as\n e.g. ``fo.somename``). [chrism]\n\n- When filling METAL slots (possibly with a specific version of\n libxml2, I am using 2.6.32) it was possible to cause the translator\n to attempt to add a stringtype to a NoneType (on a line that reads\n ``variable = self.symbols.slot+element.node.fill_slot`` because an\n XPath expression looking for fill-slot nodes did not work\n properly). [chrism]\n\n- Preserve whitespace in string translation expressions. [malthe]\n\n- Fixed interpolation bug where multiple attributes with interpolation\n expressions would result in corrupted output. [malthe]\n\n- Support try-except operator ('|') when 'python' is the default\n expression type. [malthe]\n\n- METAL macros should render in the template where they're\n defined. [malthe]\n\n- Avoid printing a line-break when we repeat over a single item\n only. [malthe]\n\n- Corrected Genshi namespace (needs a trailing slash). [malthe]\n\n- Fixed a few more UnicodeDecodeErrors (test contributed by Wiggy).\n In particular, never upcast to unicode during transformation, and\n utf-8 encode Unicode attribute keys and values in Assign expressions\n (e.g. py:attrs). [chrism]\n\n- Fixed off-by-one bug in interpolation routine. [malthe]\n\n- The repeat-clause should not output tail with every iteration. [malthe]\n\n- CDATA sections are now correctly handled when using the\n ElementTree-parser. [malthe]\n\n- Fixed bug in path-expressions where string instances would be\n (attempted) called. [malthe]\n\n- CDATA sections are now correctly preserved when using expression\n interpolation. [malthe]\n\n- The Genshi interpolation operator ${} should not have its result\n escaped when used in the text or tail regions. [malthe]\n\n- Fixed edge case bug where inserting both a numeric entity and a\n literal set of unicode bytes into the same document would cause a\n UnicodeDecodeError. See also\n http://groups.google.com/group/z3c_pt/browse_thread/thread/aea963d25a1778d0?hl=en\n [chrism]\n\n- Static attributes are now properly overriden by py:attr-attributes.\n [malthe]\n\n0.9 (2008/08/07)\n----------------\n\n- Added support for Genshi-templates.\n [malthe]\n\n- Cleanup and refactoring of translation module.\n [malthe]\n\n- If the template source contains a DOCTYPE declaration, output it\n during rendering. [chrism]\n\n- Fixed an error where numeric entities specified in text or tail\n portions of elements would cause a UnicodeDecodeError to be raised\n on systems configured with an 'ascii' default encoding. [chrism]\n\n- Refactored file system based cache a bit and added a simple benchmark for\n the cache. The initial load speed for a template goes down significantly\n with the cache. Compared to zope.pagetemplate we are only 3x slower,\n compared to 50x slower when cooking each template on process startup.\n\n- Got rid entirely of the _escape function and inlined the actual code\n instead. We go up again to 12x for path and 19x for Python expressions :)\n [hannosch]\n\n- Avoid string concatenation and use multiple write statements instead. These\n are faster now, since we use a list append internally.\n [hannosch]\n\n- Inline the _escape function, because function calls are expensive in Python.\n Added missing escaping for Unicode values.\n [fschulze, hannosch]\n\n- When templates are instantiated outside of a class-definition, a\n relative file path will be made absolute using the module path.\n [malthe]\n\n- Simplified the _escape function handling by pulling in the str call into the\n function. Corrected the bigtable hotshot test to only benchmark rendering.\n\n- Replaced the cgi.escape function by an optimized local version, we go up\n to 11x for path and 16x for Python expressions :) In the bigtable benchmark\n the enhancement is more noticable - we are the same speed as spitfire -O1\n templates now and just half the speed of -O3 :))\n\n- Added a new benchmark test called bigtable that produces results which are\n directly comparable to those produced by the bigtable.py benchmark in the\n spitfire project.\n\n- Introduce a new config option called `Z3C_PT_DISABLE_I18N`. If this\n environment variable is set to `true`, the template engine will not call\n into the zope.i18n machinery anymore, but fall back to simple interpolation\n in all cases. In a normal Zope environment that has the whole i18n\n infrastructure set up, this will render the templates about 15x faster than\n normal TAL, instead of only 10x faster at this point.\n\n- Removed the `second rendering` tests from the benchmark suite. Since we\n enable the file cache for the benchmarks, there's no difference between the\n first and second rendering anymore after the cache file has been written.\n\n- Require zope.i18n 3.5 and add support for using its new negotiate function.\n If you use the `zope_i18n_allowed_languages` environment variable the target\n language for a template is only negotiated once per template, instead of\n once for each translate function call. This more than doubles the speed\n and the benchmark is back at 9.2 times faster.\n\n- Extended the i18n handling to respect the passed in translation context to\n the template. Usually this is the request, which is passed on under the\n internal name of `_context` into the render functions. After extending the\n i18n tests to include a negotiator and message catalog the improvement is\n only at 4.5 anymore, as most of the time is spent inside the i18n machinery.\n\n- Added persistent file cache functionality. If the environment variable is\n set, each file system based template will add a directory to the cache\n (currently a SHA-1 of the file's absolute path is used as the folder name)\n and in the folder one file per params for the template (cache filename is\n the hash of the params). Once a template file is initialized, an instance\n local registry is added, which then looks up all cached files and\n pre-populates the registry with the render functions.\n\n- Fixed interpolation edge case bugs.\n [malthe]\n\n- Added new `Z3C_PT_FILECACHE` environment variable pointing to a directory.\n If set, this will be used to cache the compiled files.\n\n- Added a second variation of the repeat clause, using a simple for loop. It\n doesn't support the repeatdict, though and is therefor not used yet. Also\n began work to add introspection facilities to clauses about the variables\n being used in them. The simpler loop causes the benchmarks to go up to a\n 10.5 (old 9.5) for path expressions and 14.5 (12.5) for python expressions.\n So the next step is to introduce an optimization phase, that can decide\n which variant of the loops to use.\n\n- Made the debug mode independent from the Python debug mode. You can now\n specify an environment variable called `Z3C_PT_DEBUG` to enable it.\n\n- Added some code in a filecache module that can later be used to write out\n and reload the compiled Python code to and from the file system. We should\n be able to avoid reparsing on Python process restart.\n\n- Simplified the generated _escape code. cgi.escape's second argument is a\n simple boolean and not a list of characters to quote.\n\n- Use a simple list based BufferIO class instead of a cStringIO for the out\n stream. Avoiding the need to encode Unicode data is a bigger win. We do\n not support arbitrarily mixing of Unicode and non-ascii inside the engine.\n\n- Merged two adjacent writes into one inside the Tag clause.\n\n- Applied a bunch of micro-optimizations. ''.join({}) is slightly faster\n than ''.join({}.keys()) and does the same. Avoid a try/except for error\n handling in non-debug mode. Test against 'is None' instead of a boolean\n check for the result of the template registry lookup. Made PROD_MODE\n available defined as 'not DEBUG_MODE' in config.py, so we avoid the 'not'\n in every cook-check.\n\n- Added more benchmark tests for the file variants.\n\n- Optimized 'is None' handling in Tag clause similar to the Write clause.\n\n- Made the _out.write method directly available as _write in all scopes, so\n we avoid the method lookup call each time.\n\n- Optimized 'is None' handling in Write clause.\n\n- Slightly refactored benchmark tests and added tests for the file variants.\n\n- In debug mode the actual source code for file templates is written out to\n a <filename>.source file, to make it easier to inspect it.\n\n- Make debug mode setting explicit in a config.py. Currently it is bound to\n Python's __debug__, which is False when run with -O and otherwise True.\n\n- Use a simplified UnicodeWrite clause for the result of _translate calls,\n as the result value is guaranteed to be Unicode.\n\n- Added benchmark tests for i18n handling.\n\n- Added more tests for i18n attributes handling.\n\n- Don't generate empty mappings for expressions with a trailing semicolon.\n\n- Fixed undefined name 'static' error in i18n attributes handling and added\n quoting to i18n attributes.\n\n- Added condition to the valid attributes on tags in the tal namespace.\n\n- Made sure the traceback from the *first* template exception\n is carried over to __traceback_info__\n\n- Added template source annotations on exceptions raised while\n rendering a template.\n\n0.8 (2008/03/19)\n----------------\n\n- Added support for 'nocall' and 'not' (for path-expressions).\n\n- Added support for path- and string-expressions.\n\n- Abstracted expression translation engine. Expression implementations\n are now pluggable. Expression name pragmas are supported throughout.\n\n- Formalized expression types\n\n- Added support for 'structure'-keyword for replace and content.\n\n- Result of 'replace' and 'content' is now escaped by default.\n\n- Benchmark is now built as a custom testrunner\n\n0.7 (2008/03/10)\n----------------\n\n- Added support for comments; expressions are allowed\n inside comments, i.e.\n\n <!-- ${'Hello World!'} -->\n\n Comments are always included.\n\n0.7 (2008/02/24)\n----------------\n\n- Added support for text templates; these allow expression\n interpolation in non-XML documents like CSS stylesheets and\n javascript files.\n\n0.5 (2008/02/23)\n----------------\n\n- Expression interpolation implemented.\n\n0.4 (2008/02/22)\n----------------\n\n- Engine now uses cStringIO yielding a 2.5x performance\n improvement. Unicode is now handled correctly.\n\n0.3 (2007/12/23)\n----------------\n\n- Code optimization; bug fixing spree\n\n- Added ``ViewPageTemplateFile`` class\n\n- Added support for i18n\n\n- Engine rewrite; improved code generation abstractions\n\n0.2 (2007/12/05)\n----------------\n\n- Major optimizations to the generated code\n\n0.1 (2007/12/03)\n----------------\n\n- First public release\n",
"bugtrack_url": null,
"license": "ZPL",
"summary": "Fast ZPT engine.",
"version": "4.4",
"project_urls": {
"Homepage": "https://github.com/zopefoundation/z3c.pt",
"Issue Tracker": "https://github.com/zopefoundation/z3c.pt/issues",
"Sources": "https://github.com/zopefoundation/z3c.pt"
},
"split_keywords": [
"tal",
"tales",
"pagetemplate",
"zope",
"chameleon"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "6a5ff68a6b6a6cc1da57e3fa44ca7134b19ba7975adf9226458242968cc6be91",
"md5": "db8697a102388ad4901200f95bcceba5",
"sha256": "2ebe922a4bcc54ce2914230044eb190408b66b1f55a8407a3fe2ccb0a595bb98"
},
"downloads": -1,
"filename": "z3c.pt-4.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "db8697a102388ad4901200f95bcceba5",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 40449,
"upload_time": "2024-08-07T06:25:40",
"upload_time_iso_8601": "2024-08-07T06:25:40.071411Z",
"url": "https://files.pythonhosted.org/packages/6a/5f/f68a6b6a6cc1da57e3fa44ca7134b19ba7975adf9226458242968cc6be91/z3c.pt-4.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a0bcddce4fd09343f44a1479a425d8f04ec494311c03331044e37df0e6afa49e",
"md5": "411d4388a884ef973456dbf98891f451",
"sha256": "ba4292f1ce475d6da0efd5406d141a53bbca3a66bbedb4c97e43bd3f5bbf9190"
},
"downloads": -1,
"filename": "z3c.pt-4.4.tar.gz",
"has_sig": false,
"md5_digest": "411d4388a884ef973456dbf98891f451",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 68261,
"upload_time": "2024-08-07T06:25:42",
"upload_time_iso_8601": "2024-08-07T06:25:42.750733Z",
"url": "https://files.pythonhosted.org/packages/a0/bc/ddce4fd09343f44a1479a425d8f04ec494311c03331044e37df0e6afa49e/z3c.pt-4.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-07 06:25:42",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "zopefoundation",
"github_project": "z3c.pt",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "z3c.pt"
}