pax_global_header00006660000000000000000000000064142007520410014505gustar00rootroot0000000000000052 comment=b4018f001638e23dbd24a755a5d9291f48e2b4eb genshi-0.7.6/000077500000000000000000000000001420075204100127745ustar00rootroot00000000000000genshi-0.7.6/.github/000077500000000000000000000000001420075204100143345ustar00rootroot00000000000000genshi-0.7.6/.github/workflows/000077500000000000000000000000001420075204100163715ustar00rootroot00000000000000genshi-0.7.6/.github/workflows/release.yml000066400000000000000000000042351420075204100205400ustar00rootroot00000000000000name: Build sdist and wheels on: workflow_dispatch: inputs: upload_to_pypi: description: "Upload to PyPI? Y/[N]" default: "N" jobs: build_sdist: name: Build sdist runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 name: Install Python with: python-version: "3.6" - name: Install pip build run: | python -m pip install "build" - name: Build sdist tarball shell: bash run: | python -m build --sdist . - uses: actions/upload-artifact@v2 with: name: sdist path: | dist/*.tar.gz if-no-files-found: error build_generic_wheel: name: Build generic wheel (without speedups) runs-on: ubuntu-latest env: # Build a wheel without speedups that can run on pure Python GENSHI_BUILD_SPEEDUP: 0 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 name: Install Python with: python-version: "3.6" - name: Install pip build run: | python -m pip install "build" - name: Build wheel shell: bash run: | python -m build --wheel . - uses: actions/upload-artifact@v2 with: name: wheels path: | dist/*.whl if-no-files-found: error deploy: name: "Upload to PyPI if selected" if: github.event.inputs.upload_to_pypi == 'Y' needs: [build_sdist, build_generic_wheel] runs-on: ubuntu-latest env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} TWINE_NON_INTERACTIVE: 1 TWINE_REPOSITORY: pypi steps: - name: Download build artifacts to local runner uses: actions/download-artifact@v2 - uses: actions/setup-python@v2 name: Install Python with: python-version: "3.10" - name: Install twine run: | python -m pip install "twine" - name: Upload sdist and wheel to PyPI run: | python -m twine upload --verbose wheels/*.whl sdist/*.tar.gz genshi-0.7.6/.github/workflows/tests.yml000066400000000000000000000007501420075204100202600ustar00rootroot00000000000000name: Run test suite on: [push, pull_request] jobs: tests: runs-on: ubuntu-latest strategy: matrix: python-version: [2.7, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11-dev", pypy2, pypy3] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Run test suite run: | python setup.py test genshi-0.7.6/.gitignore000066400000000000000000000000411420075204100147570ustar00rootroot00000000000000*.egg-info build *.so __pycache__genshi-0.7.6/COPYING000066400000000000000000000026111420075204100140270ustar00rootroot00000000000000Copyright (C) 2006-2010 Edgewall Software All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. genshi-0.7.6/ChangeLog000066400000000000000000000735001420075204100145530ustar00rootroot00000000000000Version 0.7.6 https://github.com/edgewall/genshi/releases/tag/0.7.6 (Feb 9 2022, from branches/stable/0.7.x) * Added support for Python 3.10 and 3.11 (#54, #56, #58 by Brandt Bucher, Felix Schwarz & Simon Cross) * Replaced assertEquals with assertEqual. assertEquals was deprecated in Python 3.2. (#42 by Simon Cross) * Removed used of element.getchildren() which has been removed from the Python standard library elementtree in Python 3.9. (#57 by Jan Vollmer) * Added support for Python 3.10 by using CodeType.replace in `build_code_chunk` to make code object updates more robust against changes in CodeType. (#49 by Felix Schwarz) * Moved tests and releases workflows to GitHub Actions (#61, #51 by Felix Schwarz and Simon Cross) * Fixed reference leak in Markup.join C implementation. (#47 by Simon Cross) * Sort directives only by directive index. Previously they were sorted by the class, namespace and arguments of the directives. This was acceptable in Python 2, but is a bug in Python 3 since some the arguments may not be comparable. (#44 by Cédric Krier) * Add support for msgctxt to i18n. (#13 by Eric O'Connell) * Implemented skipping of empty attributes during translation to match the behaviour during translation extraction (i.e. don't try to translate empty strings that are not extracted). (#38 by Jun Omae) * Ported setuptools options to declarative config in setup.cfg. (#40 by Eli Schwartz) * Removed used of deprecated setuptools Feature in setup.py. (#39 by Eli Schwartz) Version 0.7.5 https://github.com/edgewall/genshi/releases/tag/0.7.5 (Nov 18 2020, from branches/stable/0.7.x) * Fix handling of slices containing function call, variable name and attribute lookup AST nodes in Python 3.9 in template scripts (template expressions already correctly handled these cases). Thank you to Roger Leigh for finding this issue and contributing the fix for it. * C speedup module now available for Python >= 3.3. Support was added for PEP 393 (flexible string representation). Thank you to Inada Naoki for contributing this major enhancement. * Remove the custom 2to3 fixers (no longer used since the removal of 2to3 in 0.7.4). Version 0.7.4 https://github.com/edgewall/genshi/releases/tag/0.7.4 (Nov 3 2020, from branches/stable/0.7.x) * Add support for deprecation of ast classes slice, Index and ExtSlice in Python 3.9. See https://bugs.python.org/issue34822 for details of the changes. * Update the project URL in setup.py to point to GitHub. * Remove use of 2to3 for generating Python 3 compatible code. Version 0.7.3 https://github.com/edgewall/genshi/releases/tag/0.7.3 (May 27 2019, from branches/stable/0.7.x) * Add support for PEP 570 (positional-only keyword parameters) changes to CodeType in Python 3.8. Version 0.7.2 https://github.com/edgewall/genshi/releases/tag/0.7.2 (Apr 27 2019, from branches/stable/0.7.x) * Add support for Python 3.8. Version 0.7.1 https://github.com/edgewall/genshi/releases/tag/0.7.1 (Sep 1 2018, from branches/stable/0.7.x) * Add support for Python 3.5, 3.6 and 3.7. * Move to GitHub and Travis CI. * Add support for iterator arguments to _speedups Markup.join implementation so that it matches the Python implementation (fixes #574). * Add HTML5 input placeholder attribute to list of translatable attributes (fixes #577). * Add missing boolean attributes to XHTML and HTML serializers (fixes #570). * Fix infinite recursion in template inlining (fixes #584). * Support slash escaped of CRLF newlines (fixes #569). * Disable the speedups C extension on CPython >= 3.3 since Genshi doesn't support the new Unicode C API yet. * Fix handling of case where a translation has text after a closing tag (fixes #566). * Fix assert with side-effect in xi:fallback directive processing (see #565). Version 0.7 http://svn.edgewall.org/repos/genshi/tags/0.7.0/ (Jan 27 2013, from branches/stable/0.7.x) * Add support for Python 3.1, 3.2 and 3.3 (via 2to3) and for PyPy. The majority of the coding was done in a sprint run by the Cape Town Python Users Group with financial assistance from the Python Software Foundation. * Default input and output encodings changed from UTF-8 to None (i.e. unicode strings). * Skip Mako benchmarks if Mako isn't installed (rather than failing completely). Version 0.6.1 http://svn.edgewall.org/repos/genshi/tags/0.6.1/ (Jan 27 2013, from branches/stable/0.6.x) * Security fix to enhance sanitizing of CSS in style attributes. Genshi's `HTMLSanitizer` disallows style attributes by default (this remains unchanged) and warns against such attacks in its documentation, but the provided CSS santizing is now less lacking (see #455). * Fix for error in how `HTMLFormFiller` would handle `textarea` elements if no value was not supplied form them. * The `HTMLFormFiller` now correctly handles check boxes and radio buttons with an empty `value` attribute. * Template `Context` objects now have a `.copy` method. * Added a simple `tox.ini` file for using tox to test against multiple verions of Python. * Fix for bug in `QName` comparison (see #413). * Fix for bug in handling of trailing events in match template matches (see #399). * Fix i18n namespace declaration in documentation (see #400). * Fix for bug in caching of events in serializers by no longer caching `(TEXT, Markup)` events (see #429). * Fix handling of `None` by `Markup.escape` in `_speedups.c` (see #439). * Fix handling of internal state by match templates (relevant when multiple templates match the same part of the stream, see #370). * Fix handling of multiple events between or on either side of start and end tags in translated messages (see #404). * Fix test failures caused by changes in HTMLParser in Python 2.7 (see #501). * Fix infinite loop in interplotation lexing that was introduced by a change in Python 2.7's tokenizer (see #540). * Fix handling of processing instructions without data (see #368). * Updated MANIFEST.in so as not to rely on build from Subersion 1.6. Version 0.6 http://svn.edgewall.org/repos/genshi/tags/0.6.0/ (Apr 22 2010, from branches/stable/0.6.x) * Support for Python 2.3 has been dropped. * Rewrite of the XPath evaluation engine for better performance and improved correctness. This is the result of integrating work done by Marcin Kurczych during GSoC 2008. * Updated the Python AST processing for template code evaluation to use the `_ast` module instead of the deprecated `compiler` package, including an adapter layer for Python 2.4. This, too, is the result of integrating work done by Marcin Kurczych during GSoC 2008. * Added caching in the serialization stage for improved performance in some cases. * Various improvements to the HTML sanitization filter. * Fix problem with I18n filter that would get confused by expressions in attribute values when inside an `i18n:msg` block (ticket #250). * Fix problem with the transformation filter dropping events after the selection (ticket #290). * `for` loops in template code blocks no longer establish their own locals scope, meaning you can now access variables assigned in the loop outside of the loop, just as you can in regular Python code (ticket #259). * Import statements inside function definitions in template code blocks no longer result in an UndefinedError when the imported name is accessed (ticket #276). * Fixed handling of relative URLs with fragment identifiers containing colons in the `HTMLSanitizer` (ticket #274). * Added an option to the `HTMLFiller` to also populate password fields. * Match template processing no longer produces unwanted duplicate output in some cases (ticket #254). * Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback (ticket #320). * Added documentation for the `TemplateLoader`. * Enhanced documentation for internationalization. Version 0.5.1 http://svn.edgewall.org/repos/genshi/tags/0.5.1/ (Jul 9 2008, from branches/stable/0.5.x) * Fix problem with nested match templates not being applied when buffering on the outer `py:match` is disabled. Thanks to Erik Bray for reporting the problem and providing a test case! * Fix problem in `Translator` filter that would cause the translation of text nodes to fail if the translation function returned an object that was not directly a string, but rather something like an instance of the `LazyProxy` class in Babel (ticket #145). * Fix problem with match templates incorrectly being applied multiple times. * Includes from templates loaded via an absolute path now include the correct file in nested directories as long if no search path has been configured (ticket #240). * Unbuffered match templates could result in parts of the matched content being included in the output if the match template didn't actually consume it via one or more calls to the `select()` function (ticket #243). Version 0.5 http://svn.edgewall.org/repos/genshi/tags/0.5.0/ (Jun 9 2008, from branches/stable/0.5.x) * Added #include directive for text templates (ticket #115). * Added new markup transformation filter contributed by Alec Thomas. This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions. * When using HTML or XHTML serialization, the `xml:lang` attribute is automatically translated to the `lang` attribute which HTML user agents understand. * Added support for the XPath 2 `matches()` function in XPath expressions, which allow matching against regular expressions. * Support for Python code blocks in templates can now be disabled (ticket #123). * Includes are now processed when the template is parsed if possible, but only if the template loader is not set to do automatic reloading. Included templates are basically inlined into the including template, which can speed up rendering of that template a bit. * Added new syntax for text templates, which is more powerful and flexible with respect to white-space and line breaks. It also supports Python code blocks. The old syntax is still available and the default for now, but in a future release the new syntax will become the default, and some time after that the old syntax will be removed. * Added support for passing optimization hints to `` directives, which can speed up match templates in many cases, for example when a match template should only be applied once to a stream, or when it should not be applied recursively. * Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. * XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101). * Python code blocks inside match templates are now executed (ticket #155). * The template engine plugin no longer adds the `default_doctype` when the `fragment` parameter is `True`. * The `striptags` function now also removes HTML/XML-style comments (ticket #150). * The `py:replace` directive can now also be used as an element, with an attribute named `value` (ticket #144). * The `TextSerializer` class no longer strips all markup in text by default, so that it is still possible to use the Genshi `escape` function even with text templates. The old behavior is available via the `strip_markup` option of the serializer (ticket #146). * Assigning to a variable named `data` in a Python code block no longer breaks context lookup. * The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it. * The XHTML serializer now strips `xml:space` attributes as they are only allowed on very few tags. * Match templates are now applied in a more controlled fashion: in the order they are declared in the template source, all match templates up to (and including) the matching template itself are applied to the matched content, whereas the match templates declared after the matching template are only applied to the generated content (ticket #186). * The `TemplateLoader` class now provides an `_instantiate()` method that can be overridden by subclasses to implement advanced template instantiation logic (ticket #204). * The search path of the `TemplateLoader` class can now contain ''load functions'' in addition to path strings. A load function is passed the name of the requested template file, and should return a file-like object and some metadata. New load functions are supplied for loading from egg package data, and loading from different loaders depending on the path prefix of the requested filename (ticket #182). * Match templates can now be processed without keeping the complete matched content in memory, which could cause excessive memory use on long pages. The buffering can be disabled using the new `buffer` optimization hint on the `` directive. * Improve error reporting when accessing an attribute in a Python expression raises an `AttributeError` (ticket #191). * The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class (ticket #211). * The `Template` class and its subclasses, as well as the interpolation API, now take an `filepath` parameter instead of `basedir` (ticket #207). * The `XHTMLSerializer` now has a `drop_xml_decl` option that defaults to `True`. Setting it to `False` will cause any XML decl in the serialized stream to be included in the output as it would for XML serialization. * Add support for a protocol that would allow interoperability of different Python packages that generate and/or consume markup, based on the special `__html__()` method (ticket #202). Version 0.4.4 http://svn.edgewall.org/repos/genshi/tags/0.4.4/ (Aug 14, 2007, from branches/stable/0.4.x) * Fixed augmented assignment to local variables in Python code blocks. * Fixed handling of nested function and class definitions in Python code blocks. * Includes were not raising `TemplateNotFound` exceptions even when no fallback has been specified. That has been corrected. * The template loader now raises a `TemplateNotFound` error when a previously cached template is removed or renamed, where it previously was passing up an `OSError`. * The Genshi I18n filter can be configured to only extract messages found in `gettext` function calls, ignoring any text nodes and attribute values (ticket #138). Version 0.4.3 http://svn.edgewall.org/repos/genshi/tags/0.4.3/ (Jul 17 2007, from branches/stable/0.4.x) * The I18n filter no longer extracts or translates literal strings in attribute values that also contain expressions. * Added `loader_callback` option to plugin interface, which allows specifying a callback function that the template loader should invoke whenever a new template is loaded (ticket #130). Note that the value for this option can not be specified as a string, only as an actual function object, which means it is not available for use through configuration files. * The I18n filter now extracts messages from gettext functions even inside ignored tags (ticket #132). * The HTML sanitizer now strips any CSS comments in style attributes, which could previously be used to hide malicious property values. * The HTML sanitizer now also removes any HTML comments encountered, as those may be used to hide malicious payloads targetting a certain "innovative" browser that goes and interprets the content of specially prepared comments. * Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor. Version 0.4.2 http://svn.edgewall.org/repos/genshi/tags/0.4.2/ (Jun 20 2007, from branches/stable/0.4.x) * The `doctype` parameter of the markup serializers now also accepts the "name" of the doctype as string, in addition to the `(name, pubid, sysid)` tuple. * The I18n filter was not replacing the original attributes with the translation, but instead adding a second attribute with the same name. * `TextTemplate` can now handle unicode source (ticket #125). * A `` processing instruction containing trailing whitespace no longer causes a syntax error (ticket #127). * The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization. * Added plugin for message extraction via Babel (http://babel.edgewall.org/). Version 0.4.1 http://svn.edgewall.org/repos/genshi/tags/0.4.1/ (May 21 2007, from branches/stable/0.4.x) * Fix incorrect reference to translation function in the I18N filter. * The `ET()` function now correctly handles attributes with a namespace. * XML declarations are now processed internally, as well as written to the output when XML serialization is used (ticket #111). * Added the functions `encode()` and `get_serializer()` to the `genshi.output` module, which provide a lower-level API to the functionality previously only available through `Stream.render()` and `Stream.serialize()`. * The `DocType` class now has a `get(name)` function that returns a `DOCTYPE` tuple for a given string. * Added frameset variants to the `DocType` constants for HTML 4.01 and XHTML 1.0. * Improved I18n extraction for pluralizable messages: for any translation function with multiple string arguments (such as ``ngettext``), a single item with a tuple of strings is yielded, instead an item for each string argument. * The `HTMLFormFiller` stream filter no longer alters form elements for which the data element contains no corresponding item. * Code in `` processing instructions no longer gets the special treatment as Python code in template expressions, i.e. item and attribute access are no longer interchangeable (which was broken in a number of ways anyway, see ticket #113). This change does not affect expressions. * Numerous fixes for the execution of Python code in `` processing instructions (tickets #113 and #114). * The `py:def` (and `#def`) directive now supports "star args" (i.e. `*args` and `**kwargs`) in the function declaration (ticket #116). Version 0.4 http://svn.edgewall.org/repos/genshi/tags/0.4.0/ (Apr 16 2007, from branches/stable/0.4.x) * New example applications for CherryPy and web.py. * The template loader now uses a LRU cache to limit the number of cached templates to a configurable maximum. Also, a race condition in the template loader was fixed by adding locking. * A new filter (genshi.filters.HTMLFormFiller) was added, which can populate HTML forms based on a dictionary of values. * The set of permitted tag and attribute names for the HTMLSanitizer can now be configured per instance. * The template engine plugin now supports a range of options for configuration, for example to set the default serialization method, the default output encoding, or the default DOCTYPE. * The ElementTree adaptation function `ET()` has moved into the `genshi.input` module. * Allow `when` directives to omit the test expression as long as the associated choose directive does have one. In that case, the when branch is followed if the expression of the choose directive evaluates to a truth value. * Unsuccessful attribute or item lookups now return `Undefined` objects for nicer error messages. * Split up the `genshi.template` module into multiple modules inside the new `genshi.template` package. * Results of expression evaluation are no longer implicitly called if they are callable. * Instances of the `genshi.core.Attrs` class are now immutable (they are subclasses of `tuple` instead of `list`). * `MarkupTemplate`s can now be instantiated from markup streams, in addition to strings and file-like objects (ticket #69). * Improve handling of incorrectly nested tags in the HTML parser. * Template includes can now be nested inside fallback content. * Expressions can now contain dict literals (ticket #37). * It is now possible to have one or more escaped dollar signs in front of a full expression (ticket #92). * The `Markup` class is now available by default in template expressions (ticket #67). * The handling of namespace declarations in XML/XHTML output has been improved. * The `Attrs` class no longer automatically wraps all attribute names in `QName` objects. This is now the responsibility of whoever is instantiating `Attrs` objects (for example, stream filters and generators). * Python code blocks are now supported using the `` processing instruction (ticket #84). * The way errors in template expressions are handled can now be configured. The option `LenientLookup` provides the same forgiving mode used in previous Genshi versions, while `StrictLookup` raises exceptions when undefined variables or members are accessed. The lenient mode is still the default in this version, but that may change in the future. (ticket #88) * If a variable is not necessarily defined at the top level of the template data, the new built-in functions `defined(key)` and `value_of(key, default)` can be used so that the template also works in strict lookup mode. These functions were previously only available when using Genshi via the template engine plugin (for compatibility with Kid). * `style` attributes are no longer allowed by the `HTMLSanitizer` by default. If they are explicitly added to the set of safe attributes, any unicode escapes in the attribute value are now handled properly. * Namespace declarations on conditional elements (for example using a `py:if` directive`) are no longer moved to the following element when the element originally carrying the declaration is removed from the stream (ticket #107). * Added basic built-in support for internationalizing templates by providing a new `Translator` class that can both extract localizable strings from a stream, and replace those strings with their localizations at render time. The code for this was largely taken from previous work done by Matt Good and David Fraser. Version 0.3.6 http://svn.edgewall.org/repos/genshi/tags/0.3.6/ (Dec 11 2006, from branches/stable/0.3.x) * The builder API now accepts streams as children of elements and fragments. Version 0.3.5 http://svn.edgewall.org/repos/genshi/tags/0.3.5/ (Nov 22 2006, from branches/stable/0.3.x) * Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children. * Preserve whitespace in HTML `
` elements also when they contain child
   elements.
 * Match templates no longer match their own output (ticket #77).
 * Blank lines before directives in text templates are now preserved as
   expected (ticket #62).


Version 0.3.4
http://svn.edgewall.org/repos/genshi/tags/0.3.4/
(Nov 2 2006, from branches/stable/0.3.x)

 * The encoding of HTML and XML files, as well as markup and text templates,
   can now be specified. Also, the encoding specified in XML declarations is
   now respected unless an expiclit encoding is requested.
 * Expressions used as arguments for `py:with`, `py:def`, and `py:for`
   directives can now contain non-ASCII strings.


Version 0.3.3
http://svn.edgewall.org/repos/genshi/tags/0.3.3/
(Oct 16 2006, from branches/stable/0.3.x)

 * Fixed bug introduced in 0.3.2 that broke the parsing of templates which
   declare the same namespace more than once in a nested fashion.
 * Fixed the parsing of HTML entity references inside attribute values, both
   in the `XMLParser` and the `HTMLParser` classes.
 * Some changes to usage of absolute vs. relative template paths to ensure that
   the filenamed-keyed cache employed by the TemplateLoader doesn't mix up
   templates with the same name, but from different subdirectories.


Version 0.3.2
http://svn.edgewall.org/repos/genshi/tags/0.3.2/
(Oct 12 2006, from branches/stable/0.3.x)

 * Exceptions from templates now contain the absolute path to the template file
   when a search path is used. This enables tracebacks to display the line in
   question.
 * The template engine plugin now provides three different types: "genshi" and
   "genshi-markup" map to markup templates, while "genshi-text" maps to text
   templates.
 * Fixed the namespace context used by XPath patterns in py:match templates.
   The were erroneously using the namespace context of the elements being
   matched, where they should rather use the context in which they were
   defined.
 * The contents of `
  ... """)
  >>> sanitize = HTMLSanitizer()
  >>> print(html | sanitize)
  

Innocent looking text.

In this example, the ```` element. Both ````. Also, it will normalize any boolean attributes values that are minimized in HTML, so that for example ``
`` becomes ``
``. This serializer supports the use of namespaces for compound documents, for example to use inline SVG inside an XHTML document. ``html`` The ``HTMLSerializer`` produces proper HTML markup. The main differences compared to ``xhtml`` serialization are that boolean attributes are minimized, empty tags are not self-closing (so it's ``
`` instead of ``
``), and that the contents of ``') >>> print(tmpl.generate()) On the other hand, Genshi will always replace two dollar signs in text with a single dollar sign, so you'll need to use three dollar signs to get two in the output: .. code-block:: pycon >>> tmpl = MarkupTemplate('') >>> print(tmpl.generate()) .. _`code blocks`: Code Blocks =========== Templates also support full Python code blocks, using the ```` processing instruction in XML templates: .. code-block:: genshi
${greeting('world')}
This will produce the following output: .. code-block:: xml
Hello, world!
In text templates (although only those using the new syntax introduced in Genshi 0.5), code blocks use the special ``{% python %}`` directive: .. code-block:: genshitext {% python from genshi.builder import tag def greeting(name): return 'Hello, %s!' % name %} ${greeting('world')} This will produce the following output:: Hello, world! Code blocks can import modules, define classes and functions, and basically do anything you can do in normal Python code. What code blocks can *not* do is to produce content that is emitted directly tp the generated output. .. note:: Using the ``print`` statement will print to the standard output stream, just as it does for other Python code in your application. Unlike expressions, Python code in ```` processing instructions can not use item and attribute access in an interchangeable manner. That means that “dotted notation” is always attribute access, and vice-versa. The support for Python code blocks in templates is not supposed to encourage mixing application code into templates, which is generally considered bad design. If you're using many code blocks, that may be a sign that you should move such code into separate Python modules. If you'd rather not allow the use of Python code blocks in templates, you can simply set the ``allow_exec`` parameter (available on the ``Template`` and the ``TemplateLoader`` initializers) to ``False``. In that case Genshi will raise a syntax error when a ```` processing instruction is encountered. But please note that disallowing code blocks in templates does not turn Genshi into a sandboxable template engine; there are sufficient ways to do harm even using plain expressions. .. _`error handling`: Error Handling ============== By default, Genshi raises an ``UndefinedError`` if a template expression attempts to access a variable that is not defined: .. code-block:: pycon >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('

${doh}

') >>> tmpl.generate().render('xhtml') Traceback (most recent call last): ... UndefinedError: "doh" not defined You can change this behavior by setting the variable lookup mode to "lenient". In that case, accessing undefined variables returns an `Undefined` object, meaning that the expression does not fail immediately. See below for details. If you need to check whether a variable exists in the template context, use the defined_ or the value_of_ function described below. To check for existence of attributes on an object, or keys in a dictionary, use the ``hasattr()``, ``getattr()`` or ``get()`` functions, or the ``in`` operator, just as you would in regular Python code: >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('

${defined("doh")}

') >>> print(tmpl.generate().render('xhtml'))

False

.. note:: Lenient error handling was the default in Genshi prior to version 0.5. Strict mode was introduced in version 0.4, and became the default in 0.5. The reason for this change was that the lenient error handling was masking actual errors in templates, thereby also making it harder to debug some problems. .. _`lenient`: Lenient Mode ------------ If you instruct Genshi to use the lenient variable lookup mode, it allows you to access variables that are not defined, without raising an ``UndefinedError``. This mode can be chosen by passing the ``lookup='lenient'`` keyword argument to the template initializer, or by passing the ``variable_lookup='lenient'`` keyword argument to the ``TemplateLoader`` initializer: .. code-block:: pycon >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('

${doh}

', lookup='lenient') >>> print(tmpl.generate().render('xhtml'))

You *will* however get an exception if you try to call an undefined variable, or do anything else with it, such as accessing its attributes: .. code-block:: pycon >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('

${doh.oops}

', lookup='lenient') >>> print(tmpl.generate().render('xhtml')) Traceback (most recent call last): ... UndefinedError: "doh" not defined If you need to know whether a variable is defined, you can check its type against the ``Undefined`` class, for example in a conditional directive: .. code-block:: pycon >>> from genshi.template import MarkupTemplate >>> tmpl = MarkupTemplate('

${type(doh) is not Undefined}

', ... lookup='lenient') >>> print(tmpl.generate().render('xhtml'))

False

Alternatively, the built-in functions defined_ or value_of_ can be used in this case. Custom Modes ------------ In addition to the built-in "lenient" and "strict" modes, it is also possible to use a custom error handling mode. For example, you could use lenient error handling in a production environment, while also logging a warning when an undefined variable is referenced. See the API documentation of the ``genshi.template.eval`` module for details. Built-in Functions & Types ========================== The following functions and types are available by default in template code, in addition to the standard built-ins that are available to all Python code. .. _`defined`: ``defined(name)`` ----------------- This function determines whether a variable of the specified name exists in the context data, and returns ``True`` if it does. .. _`value_of`: ``value_of(name, default=None)`` -------------------------------- This function returns the value of the variable with the specified name if such a variable is defined, and returns the value of the ``default`` parameter if no such variable is defined. .. _`Markup`: ``Markup(text)`` ---------------- The ``Markup`` type marks a given string as being safe for inclusion in markup, meaning it will *not* be escaped in the serialization stage. Use this with care, as not escaping a user-provided string may allow malicious users to open your web site to cross-site scripting attacks. .. _`Undefined`: ``Undefined`` ---------------- The ``Undefined`` type can be used to check whether a reference variable is defined, as explained in `error handling`_. .. _`directives`: ------------------- Template Directives ------------------- Directives provide control flow functionality for templates, such as conditions or iteration. As the syntax for directives depends on whether you're using markup or text templates, refer to the `XML Template Language `_ or `Text Template Language `_ pages for information. genshi-0.7.6/doc/text-templates.txt000066400000000000000000000227671420075204100173000ustar00rootroot00000000000000.. -*- mode: rst; encoding: utf-8 -*- ============================= Genshi Text Template Language ============================= In addition to the XML-based template language, Genshi provides a simple text-based template language, intended for basic plain text generation needs. The language is similar to the Django_ template language. This document describes the template language and will be most useful as reference to those developing Genshi text templates. Templates are text files of some kind that include processing directives_ that affect how the template is rendered, and template expressions that are dynamically substituted by variable data. See `Genshi Templating Basics `_ for general information on embedding Python code in templates. .. note:: Actually, Genshi currently has two different syntaxes for text templates languages: One implemented by the class ``OldTextTemplate`` and another implemented by ``NewTextTemplate``. This documentation concentrates on the latter, which is planned to completely replace the older syntax. The older syntax is briefly described under legacy_. .. _django: http://www.djangoproject.com/ .. contents:: Contents :depth: 3 .. sectnum:: .. _`directives`: ------------------- Template Directives ------------------- Directives are template commands enclosed by ``{% ... %}`` characters. They can affect how the template is rendered in a number of ways: Genshi provides directives for conditionals and looping, among others. Each directive must be terminated using an ``{% end %}`` marker. You can add a string inside the ``{% end %}`` marker, for example to document which directive is being closed, or even the expression associated with that directive. Any text after ``end`` inside the delimiters is ignored, and effectively treated as a comment. If you want to include a literal delimiter in the output, you need to escape it by prepending a backslash character (``\``). Conditional Sections ==================== .. _`if`: ``{% if %}`` ------------ The content is only rendered if the expression evaluates to a truth value: .. code-block:: genshitext {% if foo %} ${bar} {% end %} Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this would produce:: Hello .. _`choose`: .. _`when`: .. _`otherwise`: ``{% choose %}`` ---------------- The ``choose`` directive, in combination with the directives ``when`` and ``otherwise``, provides advanced contional processing for rendering one of several alternatives. The first matching ``when`` branch is rendered, or, if no ``when`` branch matches, the ``otherwise`` branch is be rendered. If the ``choose`` directive has no argument the nested ``when`` directives will be tested for truth: .. code-block:: genshitext The answer is: {% choose %} {% when 0 == 1 %}0{% end %} {% when 1 == 1 %}1{% end %} {% otherwise %}2{% end %} {% end %} This would produce the following output:: The answer is: 1 If the ``choose`` does have an argument, the nested ``when`` directives will be tested for equality to the parent ``choose`` value: .. code-block:: genshitext The answer is: {% choose 1 %}\ {% when 0 %}0{% end %}\ {% when 1 %}1{% end %}\ {% otherwise %}2{% end %}\ {% end %} This would produce the following output:: The answer is: 1 Looping ======= .. _`for`: ``{% for %}`` ------------- The content is repeated for every item in an iterable: .. code-block:: genshitext Your items: {% for item in items %}\ * ${item} {% end %} Given ``items=[1, 2, 3]`` in the context data, this would produce:: Your items * 1 * 2 * 3 Snippet Reuse ============= .. _`def`: .. _`macros`: ``{% def %}`` ------------- The ``def`` directive can be used to create macros, i.e. snippets of template text that have a name and optionally some parameters, and that can be inserted in other places: .. code-block:: genshitext {% def greeting(name) %} Hello, ${name}! {% end %} ${greeting('world')} ${greeting('everyone else')} The above would be rendered to:: Hello, world! Hello, everyone else! If a macro doesn't require parameters, it can be defined without the parenthesis. For example: .. code-block:: genshitext {% def greeting %} Hello, world! {% end %} ${greeting()} The above would be rendered to:: Hello, world! .. _includes: .. _`include`: ``{% include %}`` ----------------- To reuse common parts of template text across template files, you can include other files using the ``include`` directive: .. code-block:: genshitext {% include base.txt %} Any content included this way is inserted into the generated output. The included template sees the context data as it exists at the point of the include. `Macros`_ in the included template are also available to the including template after the point it was included. Include paths are relative to the filename of the template currently being processed. So if the example above was in the file "``myapp/mail.txt``" (relative to the template search path), the include directive would look for the included file at "``myapp/base.txt``". You can also use Unix-style relative paths, for example "``../base.txt``" to look in the parent directory. Just like other directives, the argument to the ``include`` directive accepts any Python expression, so the path to the included template can be determined dynamically: .. code-block:: genshitext {% include ${'%s.txt' % filename} %} Note that a ``TemplateNotFound`` exception is raised if an included file can't be found. .. note:: The include directive for text templates was added in Genshi 0.5. Variable Binding ================ .. _`with`: ``{% with %}`` -------------- The ``{% with %}`` directive lets you assign expressions to variables, which can be used to make expressions inside the directive less verbose and more efficient. For example, if you need use the expression ``author.posts`` more than once, and that actually results in a database query, assigning the results to a variable using this directive would probably help. For example: .. code-block:: genshitext Magic numbers! {% with y=7; z=x+10 %} $x $y $z {% end %} Given ``x=42`` in the context data, this would produce:: Magic numbers! 42 7 52 Note that if a variable of the same name already existed outside of the scope of the ``with`` directive, it will **not** be overwritten. Instead, it will have the same value it had prior to the ``with`` assignment. Effectively, this means that variables are immutable in Genshi. .. _whitespace: --------------------------- White-space and Line Breaks --------------------------- Note that space or line breaks around directives is never automatically removed. Consider the following example: .. code-block:: genshitext {% for item in items %} {% if item.visible %} ${item} {% end %} {% end %} This will result in two empty lines above and beneath every item, plus the spaces used for indentation. If you want to supress a line break, simply end the line with a backslash: .. code-block:: genshitext {% for item in items %}\ {% if item.visible %}\ ${item} {% end %}\ {% end %}\ Now there would be no empty lines between the items in the output. But you still get the spaces used for indentation, and because the line breaks are removed, they actually continue and add up between lines. There are numerous ways to control white-space in the output while keeping the template readable, such as moving the indentation into the delimiters, or moving the end delimiter on the next line, and so on. .. _comments: -------- Comments -------- Parts in templates can be commented out using the delimiters ``{# ... #}``. Any content in comments are removed from the output. .. code-block:: genshitext {# This won't end up in the output #} This will. Just like directive delimiters, these can be escaped by prefixing with a backslash. .. code-block:: genshitext \{# This *will* end up in the output, including delimiters #} This too. .. _legacy: --------------------------- Legacy Text Template Syntax --------------------------- The syntax for text templates was redesigned in version 0.5 of Genshi to make the language more flexible and powerful. The older syntax is based on line starting with dollar signs, similar to e.g. Cheetah_ or Velocity_. .. _cheetah: http://cheetahtemplate.org/ .. _velocity: http://jakarta.apache.org/velocity/ A simple template using the old syntax looked like this: .. code-block:: genshitext Dear $name, We have the following items for you: #for item in items * $item #end All the best, Foobar Beyond the requirement of putting directives on separate lines prefixed with dollar signs, the language itself is very similar to the new one. Except that comments are lines that start with two ``#`` characters, and a line-break at the end of a directive is removed automatically. .. note:: If you're using this old syntax, it is strongly recommended to migrate to the new syntax. Simply replace any references to ``TextTemplate`` by ``NewTextTemplate`` (and also change the text templates, of course). On the other hand, if you want to stick with the old syntax for a while longer, replace references to ``TextTemplate`` by ``OldTextTemplate``; while ``TextTemplate`` is still an alias for the old language at this point, that will change in a future release. But also note that the old syntax may be dropped entirely in a future release. genshi-0.7.6/doc/upgrade.txt000066400000000000000000000150121420075204100157300ustar00rootroot00000000000000================ Upgrading Genshi ================ .. contents:: Contents :depth: 2 .. sectnum:: ------------------------------------------- Upgrading from Genshi 0.6.x to Genshi 0.7.x ------------------------------------------- Genshi 0.7.x now supports both Python 2 and Python 3. The most noticable API change in the Genshi development version is that the default encoding in numerous places is now None (i.e. unicode) instead of UTF-8. This change was made in order to ease the transition to Python 3 where strings are unicode strings by default. If your application relies on the default UTF-8 encoding a simple way to have it work both with Genshi 0.6.x and the development version is to specify the encoding explicitly in calls to the following classes, methods and functions: * genshi.HTML * genshi.Stream.render * genshi.input.HTMLParser * genshi.template.MarkupTemplate * genshi.template.TemplateLoader * genshi.template.TextTemplate (and genshi.template.NewTextTemplate) * genshi.template.OldTextTemplate Whether you explicitly specify UTF-8 or explicitly specify None (unicode) is a matter of personal taste, although working with unicode may make porting your own application to Python 3 easier. ------------------------------------ Upgrading from Genshi 0.5.x to 0.6.x ------------------------------------ Required Python Version ----------------------- Support for Python 2.3 has been dropped in this release. Python 2.4 is now the minimum version of Python required to run Genshi. The XPath engine has been completely overhauled for this version. Some patterns that previously matched incorrectly will no longer match, and the other way around. In such cases, the XPath expressions need to be fixed in your application and templates. ------------------------------------ Upgrading from Genshi 0.4.x to 0.5.x ------------------------------------ Error Handling -------------- The default error handling mode has been changed to "strict". This means that accessing variables not defined in the template data will now generate an immediate exception, as will accessing object attributes or dictionary keys that don't exist. If your templates rely on the old lenient behavior, you can configure Genshi to use that instead. See the documentation for details on how to do that. But be warned that lenient error handling may be removed completely in a future release. Match Template Processing ------------------------- There has also been a subtle change to how ``py:match`` templates are processed: in previous versions, all match templates would be applied to the content generated by the matching template, and only the matching template itself was applied recursively to the original content. This behavior resulted in problems with many kinds of recursive matching, and hence was changed for 0.5: now, all match templates declared before the matching template are applied to the original content, and match templates declared after the matching template are applied to the generated content. This change should not have any effect on most applications, but you may want to check your use of match templates to make sure. Text Templates -------------- Genshi 0.5 introduces a new, alternative syntax for text templates, which is more flexible and powerful compared to the old syntax. For backwards compatibility, this new syntax is not used by default, though it will be in a future version. It is recommended that you migrate to using this new syntax. To do so, simply rename any references in your code to ``TextTemplate`` to ``NewTextTemplate``. To explicitly use the old syntax, use ``OldTextTemplate`` instead, so that you can be sure you'll be using the same language when the default in Genshi is changed (at least until the old implementation is completely removed). ``Markup`` Constructor ---------------------- The ``Markup`` class no longer has a specialized constructor. The old (undocumented) constructor provided a shorthand for doing positional substitutions. If you have code like this: .. code-block:: python Markup('%s', name) You must replace it by the more explicit: .. code-block:: python Markup('%s') % name ``Template`` Constructor ------------------------ The constructor of the ``Template`` class and its subclasses has changed slightly: instead of the optional ``basedir`` parameter, it now expects an (also optional) ``filepath`` parameter, which specifies the absolute path to the template. You probably aren't using those constructors directly, anyway, but using the ``TemplateLoader`` API instead. ------------------------------------ Upgrading from Genshi 0.3.x to 0.4.x ------------------------------------ The modules ``genshi.filters`` and ``genshi.template`` have been refactored into packages containing multiple modules. While code using the regular APIs should continue to work without problems, you should make sure to remove any leftover traces of the files ``filters.py`` and ``template.py`` in the ``genshi`` package on the installation path (including the corresponding ``.pyc`` files). This is not necessary when Genshi was installed as a Python egg. Results of evaluating template expressions are no longer implicitly called if they are callable. If you have been using that feature, you will need to add the parenthesis to actually call the function. Instances of ``genshi.core.Attrs`` are now immutable. Filters manipulating the attributes in a stream may need to be updated. Also, the ``Attrs`` class no longer automatically wraps all attribute names in ``QName`` objects, so users of the ``Attrs`` class need to do this themselves. See the documentation of the ``Attrs`` class for more information. --------------------- Upgrading from Markup --------------------- Prior to version 0.3, the name of the Genshi project was "Markup". The name change means that you will have to adjust your import statements and the namespace URI of XML templates, among other things: * The package name was changed from "markup" to "genshi". Please adjust any import statements referring to the old package name. * The namespace URI for directives in Genshi XML templates has changed from ``http://markup.edgewall.org/`` to ``http://genshi.edgewall.org/``. Please update the ``xmlns:py`` declaration in your template files accordingly. Furthermore, due to the inclusion of a text-based template language, the class:: markup.template.Template has been renamed to:: genshi.template.MarkupTemplate If you've been using the Template class directly, you'll need to update your code (a simple find/replace should do—the API itself did not change). genshi-0.7.6/doc/xml-templates.txt000066400000000000000000000424401420075204100171020ustar00rootroot00000000000000.. -*- mode: rst; encoding: utf-8 -*- ============================ Genshi XML Template Language ============================ Genshi provides a XML-based template language that is heavily inspired by Kid_, which in turn was inspired by a number of existing template languages, namely XSLT_, TAL_, and PHP_. .. _kid: http://kid-templating.org/ .. _python: http://www.python.org/ .. _xslt: http://www.w3.org/TR/xslt .. _tal: http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL .. _php: http://www.php.net/ This document describes the template language and will be most useful as reference to those developing Genshi XML templates. Templates are XML files of some kind (such as XHTML) that include processing directives_ (elements or attributes identified by a separate namespace) that affect how the template is rendered, and template expressions that are dynamically substituted by variable data. See `Genshi Templating Basics `_ for general information on embedding Python code in templates. .. contents:: Contents :depth: 3 .. sectnum:: .. _`directives`: ------------------- Template Directives ------------------- Directives are elements and/or attributes in the template that are identified by the namespace ``http://genshi.edgewall.org/``. They can affect how the template is rendered in a number of ways: Genshi provides directives for conditionals and looping, among others. To use directives in a template, the namespace must be declared, which is usually done on the root element: .. code-block:: genshi ... In this example, the default namespace is set to the XHTML namespace, and the namespace for Genshi directives is bound to the prefix “py”. All directives can be applied as attributes, and some can also be used as elements. The ``if`` directives for conditionals, for example, can be used in both ways: .. code-block:: genshi ...

Bar

... This is basically equivalent to the following: .. code-block:: genshi ...

Bar

... The rationale behind the second form is that directives do not always map naturally to elements in the template. In such cases, the ``py:strip`` directive can be used to strip off the unwanted element, or the directive can simply be used as an element. Conditional Sections ==================== .. _`py:if`: ``py:if`` --------- The element and its content is only rendered if the expression evaluates to a truth value: .. code-block:: genshi
${bar}
Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this would produce: .. code-block:: xml
Hello
But setting ``foo=False`` would result in the following output: .. code-block:: xml
This directive can also be used as an element: .. code-block:: genshi
${bar}
.. _`py:choose`: .. _`py:when`: .. _`py:otherwise`: ``py:choose`` ------------- The ``py:choose`` directive, in combination with the directives ``py:when`` and ``py:otherwise`` provides advanced conditional processing for rendering one of several alternatives. The first matching ``py:when`` branch is rendered, or, if no ``py:when`` branch matches, the ``py:otherwise`` branch is rendered. If the ``py:choose`` directive is empty the nested ``py:when`` directives will be tested for truth: .. code-block:: genshi
0 1 2
This would produce the following output: .. code-block:: xml
1
If the ``py:choose`` directive contains an expression the nested ``py:when`` directives will be tested for equality to the parent ``py:choose`` value: .. code-block:: genshi
0 1 2
This would produce the following output: .. code-block:: xml
1
These directives can also be used as elements: .. code-block:: genshi 0 1 2 Looping ======= .. _`py:for`: ``py:for`` ---------- The element is repeated for every item in an iterable: .. code-block:: genshi
  • ${item}
Given ``items=[1, 2, 3]`` in the context data, this would produce: .. code-block:: xml
  • 1
  • 2
  • 3
This directive can also be used as an element: .. code-block:: genshi
  • ${item}
Snippet Reuse ============= .. _`py:def`: .. _`macros`: ``py:def`` ---------- The ``py:def`` directive can be used to create macros, i.e. snippets of template code that have a name and optionally some parameters, and that can be inserted in other places: .. code-block:: genshi

Hello, ${name}!

${greeting('world')} ${greeting('everyone else')}
The above would be rendered to: .. code-block:: xml

Hello, world!

Hello, everyone else!

If a macro doesn't require parameters, it can be defined without the parenthesis. For example: .. code-block:: genshi

Hello, world!

${greeting()}
The above would be rendered to: .. code-block:: xml

Hello, world!

This directive can also be used as an element: .. code-block:: genshi

Hello, ${name}!

.. _Match Templates: .. _`py:match`: ``py:match`` ------------ This directive defines a *match template*: given an XPath expression, it replaces any element in the template that matches the expression with its own content. For example, the match template defined in the following template matches any element with the tag name “greeting”: .. code-block:: genshi
Hello ${select('@name')}
This would result in the following output: .. code-block:: xml
Hello Dude
Inside the body of a ``py:match`` directive, the ``select(path)`` function is made available so that parts or all of the original element can be incorporated in the output of the match template. See `Using XPath`_ for more information about this function. .. _`Using XPath`: streams.html#using-xpath Match templates are applied both to the original markup as well to the generated markup. The order in which they are applied depends on the order they are declared in the template source: a match template defined after another match template is applied to the output generated by the first match template. The match templates basically form a pipeline. This directive can also be used as an element: .. code-block:: genshi
Hello ${select('@name')}
When used this way, the ``py:match`` directive can also be annotated with a couple of optimization hints. For example, the following informs the matching engine that the match should only be applied once: .. code-block:: genshi ${select("*|text()")} The following optimization hints are recognized: +---------------+-----------+-----------------------------------------------+ | Attribute | Default | Description | +===============+===========+===============================================+ | ``buffer`` | ``true`` | Whether the matched content should be | | | | buffered in memory. Buffering can improve | | | | performance a bit at the cost of needing more | | | | memory during rendering. Buffering is | | | | ''required'' for match templates that contain | | | | more than one invocation of the ``select()`` | | | | function. If there is only one call, and the | | | | matched content can potentially be very long, | | | | consider disabling buffering to avoid | | | | excessive memory use. | +---------------+-----------+-----------------------------------------------+ | ``once`` | ``false`` | Whether the engine should stop looking for | | | | more matching elements after the first match. | | | | Use this on match templates that match | | | | elements that can only occur once in the | | | | stream, such as the ```` or ```` | | | | elements in an HTML template, or elements | | | | with a specific ID. | +---------------+-----------+-----------------------------------------------+ | ``recursive`` | ``true`` | Whether the match template should be applied | | | | to its own output. Note that ``once`` implies | | | | non-recursive behavior, so this attribute | | | | only needs to be set for match templates that | | | | don't also have ``once`` set. | +---------------+-----------+-----------------------------------------------+ .. note:: The ``py:match`` optimization hints were added in the 0.5 release. In earlier versions, the attributes have no effect. Variable Binding ================ .. _`with`: ``py:with`` ----------- The ``py:with`` directive lets you assign expressions to variables, which can be used to make expressions inside the directive less verbose and more efficient. For example, if you need use the expression ``author.posts`` more than once, and that actually results in a database query, assigning the results to a variable using this directive would probably help. For example: .. code-block:: genshi
$x $y $z
Given ``x=42`` in the context data, this would produce: .. code-block:: xml
42 7 52
This directive can also be used as an element: .. code-block:: genshi
$x $y $z
Note that if a variable of the same name already existed outside of the scope of the ``py:with`` directive, it will **not** be overwritten. Instead, it will have the same value it had prior to the ``py:with`` assignment. Effectively, this means that variables are immutable in Genshi. Structure Manipulation ====================== .. _`py:attrs`: ``py:attrs`` ------------ This directive adds, modifies or removes attributes from the element: .. code-block:: genshi
  • Bar
Given ``foo={'class': 'collapse'}`` in the template context, this would produce: .. code-block:: xml
  • Bar
Attributes with the value ``None`` are omitted, so given ``foo={'class': None}`` in the context for the same template this would produce: .. code-block:: xml
  • Bar
This directive can only be used as an attribute. .. _`py:content`: ``py:content`` -------------- This directive replaces any nested content with the result of evaluating the expression: .. code-block:: genshi
  • Hello
Given ``bar='Bye'`` in the context data, this would produce: .. code-block:: xml
  • Bye
This directive can only be used as an attribute. .. _`py:replace`: ``py:replace`` -------------- This directive replaces the element itself with the result of evaluating the expression: .. code-block:: genshi
Hello
Given ``bar='Bye'`` in the context data, this would produce: .. code-block:: xml
Bye
This directive can also be used as an element (since version 0.5): .. code-block:: genshi
Placeholder
.. _`py:strip`: ``py:strip`` ------------ This directive conditionally strips the top-level element from the output. When the value of the ``py:strip`` attribute evaluates to ``True``, the element is stripped from the output: .. code-block:: genshi
foo
This would be rendered as: .. code-block:: xml
foo
As a shorthand, if the value of the ``py:strip`` attribute is empty, that has the same effect as using a truth value (i.e. the element is stripped). .. _order: Processing Order ================ It is possible to attach multiple directives to a single element, although not all combinations make sense. When multiple directives are encountered, they are processed in the following order: #. `py:def`_ #. `py:match`_ #. `py:when`_ #. `py:otherwise`_ #. `py:for`_ #. `py:if`_ #. `py:choose`_ #. `py:with`_ #. `py:replace`_ #. `py:content`_ #. `py:attrs`_ #. `py:strip`_ .. _includes: -------- Includes -------- To reuse common snippets of template code, you can include other files using XInclude_. .. _xinclude: http://www.w3.org/TR/xinclude/ For this, you need to declare the XInclude namespace (commonly bound to the prefix “xi”) and use the ```` element where you want the external file to be pulled in: .. code-block:: genshi ... Include paths are relative to the filename of the template currently being processed. So if the example above was in the file "``myapp/index.html``" (relative to the template search path), the XInclude processor would look for the included file at "``myapp/base.html``". You can also use Unix-style relative paths, for example "``../base.html``" to look in the parent directory. Any content included this way is inserted into the generated output instead of the ```` element. The included template sees the same context data. `Match templates`_ and `macros`_ in the included template are also available to the including template after the point it was included. By default, an error will be raised if an included file is not found. If that's not what you want, you can specify fallback content that should be used if the include fails. For example, to to make the include above fail silently, you'd write: .. code-block:: genshi See the `XInclude specification`_ for more about fallback content. Note though that Genshi currently only supports a small subset of XInclude. .. _`xinclude specification`: http://www.w3.org/TR/xinclude/ Dynamic Includes ================ Incudes in Genshi are fully dynamic: Just like normal attributes, the `href` attribute accepts expressions, and directives_ can be used on the ```` element just as on any other element, meaning you can do things like conditional includes: .. code-block:: genshi Including Text Templates ======================== The ``parse`` attribute of the ```` element can be used to specify whether the included template is an XML template or a text template (using the new syntax added in Genshi 0.5): .. code-block:: genshi This example would load the ``myscript.js`` file as a ``NewTextTemplate``. See `text templates`_ for details on the syntax of text templates. .. _`text templates`: text-templates.html .. _comments: -------- Comments -------- Normal XML/HTML comment syntax can be used in templates: .. code-block:: genshi However, such comments get passed through the processing pipeline and are by default included in the final output. If that's not desired, prefix the comment text with an exclamation mark: .. code-block:: genshi Note that it does not matter whether there's whitespace before or after the exclamation mark, so the above could also be written as follows: .. code-block:: genshi genshi-0.7.6/doc/xpath.txt000066400000000000000000000050631420075204100154320ustar00rootroot00000000000000.. -*- mode: rst; encoding: utf-8 -*- ===================== Using XPath in Genshi ===================== Genshi provides basic XPath_ support for matching and querying event streams. .. _xpath: http://www.w3.org/TR/xpath .. contents:: Contents :depth: 2 .. sectnum:: ----------- Limitations ----------- Due to the streaming nature of the processing model, Genshi uses only a subset of the `XPath 1.0`_ language. .. _`XPath 1.0`: http://www.w3.org/TR/xpath In particular, only the following axes are supported: * ``attribute`` * ``child`` * ``descendant`` * ``descendant-or-self`` * ``self`` This means you can't use the ``parent``, ancestor, or sibling axes in Genshi (the ``namespace`` axis isn't supported either, but what you'd ever need that for I don't know). Basically, any path expression that would require buffering of the stream is not supported. Predicates are of course supported, but path expressions *inside* predicates are restricted to attribute lookups (again due to the lack of buffering). Most of the XPath functions and operators are supported, however they (currently) only work inside predicates. The following functions are **not** supported: * ``count()`` * ``id()`` * ``lang()`` * ``last()`` * ``position()`` * ``string()`` * ``sum()`` The mathematical operators (``+``, ``-``, ``*``, ``div``, and ``mod``) are not yet supported, whereas sub-expressions and the various comparison and logical operators should work as expected. You can also use XPath variable references (``$var``) inside predicates. ---------------- Querying Streams ---------------- The ``Stream`` class provides a ``select(path)`` function that can be used to retrieve subsets of the stream: .. code-block:: pycon >>> from genshi.input import XML >>> doc = XML(''' ... ... ... Foo ... ... ... Bar ... ... ... Baz ... ... ... Waz ... ... ... ''') >>> print(doc.select('items/item[@status="closed" and ' ... '(@resolution="invalid" or not(@resolution))]/summary/text()')) BarBaz --------------------- Matching in Templates --------------------- See the directive ``py:match`` in the `XML Template Language Specification`_. .. _`XML Template Language Specification`: xml-templates.html genshi-0.7.6/examples/000077500000000000000000000000001420075204100146125ustar00rootroot00000000000000genshi-0.7.6/examples/basic/000077500000000000000000000000001420075204100156735ustar00rootroot00000000000000genshi-0.7.6/examples/basic/kidrun.py000077500000000000000000000024221420075204100175440ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import print_function import os import sys import time import kid def test(): base_path = os.path.dirname(os.path.abspath(__file__)) kid.path = kid.TemplatePath([base_path]) ctxt = dict(hello='', hey='ZYX', bozz=None, items=['Number %d' % num for num in range(1, 15)], prefix='#') start = time.clock() template = kid.Template(file='test.kid', **ctxt) print(' --> parse stage: %.4f ms' % ((time.clock() - start) * 1000)) for output in template.generate(): sys.stdout.write(output) print() times = [] for i in range(1000): start = time.clock() list(template.generate()) times.append(time.clock() - start) sys.stdout.write('.') sys.stdout.flush() print() print(' --> render stage: %s ms (average)' % ( (sum(times) / len(times) * 1000))) if __name__ == '__main__': if '-p' in sys.argv: import hotshot, hotshot.stats prof = hotshot.Profile("template.prof") benchtime = prof.runcall(test) stats = hotshot.stats.load("template.prof") stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats() else: test() genshi-0.7.6/examples/basic/layout.html000066400000000000000000000010251420075204100200740ustar00rootroot00000000000000
Hello ${hello}
reference me, please
Hello ${name.title()}
Hello ${select('@name')}
genshi-0.7.6/examples/basic/layout.kid000066400000000000000000000011641420075204100177030ustar00rootroot00000000000000
Hello ${hello}
reference me, please
Hello ${name.title()}
Hello ${item.get('name')}
genshi-0.7.6/examples/basic/run.py000077500000000000000000000024441420075204100170600ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import print_function import os import sys import time from genshi.template import TemplateLoader def test(): base_path = os.path.dirname(os.path.abspath(__file__)) loader = TemplateLoader([base_path], auto_reload=True) start = time.clock() tmpl = loader.load('test.html') print(' --> parse stage: %.4f ms' % ((time.clock() - start) * 1000)) data = dict(hello='', skin='default', hey='ZYX', bozz=None, items=['Number %d' % num for num in range(1, 15)], prefix='#') print(tmpl.generate(**data).render(method='html')) times = [] for i in range(1000): start = time.clock() list(tmpl.generate(**data)) times.append(time.clock() - start) sys.stdout.write('.') sys.stdout.flush() print() print(' --> render stage: %s ms (average)' % ( (sum(times) / len(times) * 1000))) if __name__ == '__main__': if '-p' in sys.argv: import hotshot, hotshot.stats prof = hotshot.Profile("template.prof") benchtime = prof.runcall(test) stats = hotshot.stats.load("template.prof") stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats() else: test() genshi-0.7.6/examples/basic/test.html000066400000000000000000000014731420075204100175450ustar00rootroot00000000000000
  • Item $prefix${item.split()[-1]}
${macro1()} ${macro1()} ${macro1()} ${macro2('john')} ${macro2('kate', classname='collapsed')}
Replace me
Hello Silicon genshi-0.7.6/examples/basic/test.kid000066400000000000000000000013211420075204100173400ustar00rootroot00000000000000
  • Item $prefix${item.split()[-1]}
  • XYZ ${hey}
${macro1()} ${macro1()} ${macro1()} ${macro2('john')} ${macro2('kate', classname='collapsed')}
Replace me
Hello Silicon genshi-0.7.6/examples/bench/000077500000000000000000000000001420075204100156715ustar00rootroot00000000000000genshi-0.7.6/examples/bench/basic.py000066400000000000000000000156171420075204100173360ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Template language benchmarks # # Objective: Test general templating features using a small template from __future__ import print_function from cgi import escape import os from StringIO import StringIO import sys import timeit __all__ = ['clearsilver', 'mako', 'django', 'kid', 'genshi', 'genshi_text', 'simpletal'] def genshi(dirname, verbose=False): from genshi.template import TemplateLoader loader = TemplateLoader([dirname], auto_reload=False) template = loader.load('template.html') def render(): data = dict(title='Just a test', user='joe', items=['Number %d' % num for num in range(1, 15)]) return template.generate(**data).render('xhtml') if verbose: print(render()) return render def genshi_text(dirname, verbose=False): from genshi.core import escape from genshi.template import TemplateLoader, NewTextTemplate loader = TemplateLoader([dirname], auto_reload=False) template = loader.load('template.txt', cls=NewTextTemplate) def render(): data = dict(escape=escape, title='Just a test', user='joe', items=['Number %d' % num for num in range(1, 15)]) return template.generate(**data).render('text') if verbose: print(render()) return render def mako(dirname, verbose=False): try: from mako.lookup import TemplateLookup except ImportError: print('Mako not installed, skipping', file=sys.stderr) return lambda: None lookup = TemplateLookup(directories=[dirname], filesystem_checks=False) template = lookup.get_template('template.html') def render(): data = dict(title='Just a test', user='joe', list_items=['Number %d' % num for num in range(1, 15)]) return template.render(**data) if verbose: print(render()) return render def cheetah(dirname, verbose=False): # FIXME: infinite recursion somewhere... WTF? try: from Cheetah.Template import Template except ImportError: print('Cheetah not installed, skipping', file=sys.stderr) return lambda: None class MyTemplate(Template): def serverSidePath(self, path): return os.path.join(dirname, path) filename = os.path.join(dirname, 'template.tmpl') template = MyTemplate(file=filename) def render(): template = MyTemplate(file=filename, searchList=[{'title': 'Just a test', 'user': 'joe', 'items': [u'Number %d' % num for num in range(1, 15)]}]) return template.respond() if verbose: print(render()) return render def clearsilver(dirname, verbose=False): try: import neo_cgi except ImportError: print('ClearSilver not installed, skipping', file=sys.stderr) return lambda: None neo_cgi.update() import neo_util import neo_cs def render(): hdf = neo_util.HDF() hdf.setValue('hdf.loadpaths.0', dirname) hdf.setValue('title', escape('Just a test')) hdf.setValue('user', escape('joe')) for num in range(1, 15): hdf.setValue('items.%d' % (num - 1), escape('Number %d' % num)) cs = neo_cs.CS(hdf) cs.parseFile('template.cs') return cs.render() if verbose: print(render()) return render def django(dirname, verbose=False): try: from django.conf import settings settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')]) except ImportError: print('Django not installed, skipping', file=sys.stderr) return lambda: None from django import template, templatetags from django.template import loader templatetags.__path__.append(os.path.join(dirname, 'templatetags')) tmpl = loader.get_template('template.html') def render(): data = {'title': 'Just a test', 'user': 'joe', 'items': ['Number %d' % num for num in range(1, 15)]} return tmpl.render(template.Context(data)) if verbose: print(render()) return render def kid(dirname, verbose=False): try: import kid except ImportError: print("Kid not installed, skipping", file=sys.stderr) return lambda: None kid.path = kid.TemplatePath([dirname]) template = kid.load_template('template.kid').Template def render(): return template( title='Just a test', user='joe', items=['Number %d' % num for num in range(1, 15)] ).serialize(output='xhtml') if verbose: print(render()) return render def simpletal(dirname, verbose=False): try: from simpletal import simpleTAL, simpleTALES except ImportError: print("SimpleTAL not installed, skipping", file=sys.stderr) return lambda: None fileobj = open(os.path.join(dirname, 'base.html')) base = simpleTAL.compileHTMLTemplate(fileobj) fileobj.close() fileobj = open(os.path.join(dirname, 'template.html')) template = simpleTAL.compileHTMLTemplate(fileobj) fileobj.close() def render(): ctxt = simpleTALES.Context(allowPythonPath=1) ctxt.addGlobal('base', base) ctxt.addGlobal('title', 'Just a test') ctxt.addGlobal('user', 'joe') ctxt.addGlobal('items', ['Number %d' % num for num in range(1, 15)]) buf = StringIO() template.expand(ctxt, buf) return buf.getvalue() if verbose: print(render()) return render def run(engines, number=2000, verbose=False): basepath = os.path.abspath(os.path.dirname(__file__)) for engine in engines: dirname = os.path.join(basepath, engine) if verbose: print('%s:' % engine.capitalize()) print('--------------------------------------------------------') else: print('%s:' % engine.capitalize(), end=' ') t = timeit.Timer(setup='from __main__ import %s; render = %s(r"%s", %s)' % (engine, engine, dirname, verbose), stmt='render()') time = t.timeit(number=number) / number if verbose: print('--------------------------------------------------------') print('%.2f ms' % (1000 * time)) if verbose: print('--------------------------------------------------------') if __name__ == '__main__': engines = [arg for arg in sys.argv[1:] if arg[0] != '-'] if not engines: engines = __all__ verbose = '-v' in sys.argv if '-p' in sys.argv: import cProfile, pstats prof = cProfile.Profile() prof.run('run(%r, number=200, verbose=%r)' % (engines, verbose)) stats = pstats.Stats(prof) stats.strip_dirs() stats.sort_stats('calls') stats.print_stats(25) if verbose: stats.print_callees() stats.print_callers() else: run(engines, verbose=verbose) genshi-0.7.6/examples/bench/bigtable.py000066400000000000000000000147411420075204100200230ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Template language benchmarks # # Objective: Generate a 1000x10 HTML table as fast as possible. # # Author: Jonas Borgström from __future__ import print_function import cgi import sys import timeit from StringIO import StringIO from genshi.builder import tag from genshi.filters.i18n import Translator from genshi.filters.tests.i18n import DummyTranslations from genshi.template import MarkupTemplate, NewTextTemplate try: from elementtree import ElementTree as et except ImportError: et = None try: import cElementTree as cet except ImportError: cet = None try: import neo_cgi, neo_cs, neo_util except ImportError: neo_cgi = None try: import kid except ImportError: kid = None try: from django.conf import settings settings.configure() from django.template import Context as DjangoContext from django.template import Template as DjangoTemplate except ImportError: DjangoContext = DjangoTemplate = None try: from mako.template import Template as MakoTemplate except ImportError: MakoTemplate = None table = [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)] genshi_tmpl = MarkupTemplate("""
""") genshi_tmpl_i18n = MarkupTemplate("""
${c}
""") t = Translator(DummyTranslations()) t.setup(genshi_tmpl_i18n) genshi_tmpl2 = MarkupTemplate(""" $table
""") genshi_text_tmpl = NewTextTemplate(""" {% for row in table %} {% for c in row.values() %}{% end %} {% end %}
$c
""") if DjangoTemplate: django_tmpl = DjangoTemplate(""" {% for row in table %} {% for col in row.values %}{{ col|escape }}{% endfor %} {% endfor %}
""") def test_django(): """Djange template""" context = DjangoContext({'table': table}) django_tmpl.render(context) if MakoTemplate: mako_tmpl = MakoTemplate(""" % for row in table: % for col in row.values(): % endfor % endfor
${ col | h }
""") def test_mako(): """Mako Template""" mako_tmpl.render(table=table) def test_genshi(): """Genshi template""" stream = genshi_tmpl.generate(table=table) stream.render('html', strip_whitespace=False) def test_genshi_i18n(): """Genshi template w/ i18n""" stream = genshi_tmpl_i18n.generate(table=table) stream.render('html', strip_whitespace=False) def test_genshi_text(): """Genshi text template""" stream = genshi_text_tmpl.generate(table=table) stream.render('text') def test_genshi_builder(): """Genshi template + tag builder""" stream = tag.TABLE([ tag.tr([tag.td(c) for c in row.values()]) for row in table ]).generate() stream = genshi_tmpl2.generate(table=stream) stream.render('html', strip_whitespace=False) def test_builder(): """Genshi tag builder""" stream = tag.TABLE([ tag.tr([ tag.td(c) for c in row.values() ]) for row in table ]).generate() stream.render('html', strip_whitespace=False) if kid: kid_tmpl = kid.Template("""
""") kid_tmpl2 = kid.Template(""" $table """) def test_kid(): """Kid template""" kid_tmpl.table = table kid_tmpl.serialize(output='html') if cet: def test_kid_et(): """Kid template + cElementTree""" _table = cet.Element('table') for row in table: td = cet.SubElement(_table, 'tr') for c in row.values(): cet.SubElement(td, 'td').text=str(c) kid_tmpl2.table = _table kid_tmpl2.serialize(output='html') if et: def test_et(): """ElementTree""" _table = et.Element('table') for row in table: tr = et.SubElement(_table, 'tr') for c in row.values(): et.SubElement(tr, 'td').text=str(c) et.tostring(_table) if cet: def test_cet(): """cElementTree""" _table = cet.Element('table') for row in table: tr = cet.SubElement(_table, 'tr') for c in row.values(): cet.SubElement(tr, 'td').text=str(c) cet.tostring(_table) if neo_cgi: def test_clearsilver(): """ClearSilver""" hdf = neo_util.HDF() for i, row in enumerate(table): for j, c in enumerate(row.values()): hdf.setValue("rows.%d.cell.%d" % (i, j), cgi.escape(str(c))) cs = neo_cs.CS(hdf) cs.parseStr("""
""") cs.render() def run(which=None, number=10): tests = ['test_builder', 'test_genshi', 'test_genshi_i18n', 'test_genshi_text', 'test_genshi_builder', 'test_mako', 'test_kid', 'test_kid_et', 'test_et', 'test_cet', 'test_clearsilver', 'test_django'] if which: tests = filter(lambda n: n[5:] in which, tests) for test in [t for t in tests if hasattr(sys.modules[__name__], t)]: t = timeit.Timer(setup='from __main__ import %s;' % test, stmt='%s()' % test) time = t.timeit(number=number) / number if time < 0.00001: result = ' (not installed?)' else: result = '%16.2f ms' % (1000 * time) print('%-35s %s' % (getattr(sys.modules[__name__], test).__doc__, result)) if __name__ == '__main__': which = [arg for arg in sys.argv[1:] if arg[0] != '-'] if '-p' in sys.argv: import cProfile, pstats prof = cProfile.Profile() prof.run('run(%r, number=1)' % which) stats = pstats.Stats(prof) stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats(25) if '-v' in sys.argv: stats.print_callees() stats.print_callers() else: run(which) genshi-0.7.6/examples/bench/cheetah/000077500000000000000000000000001420075204100172725ustar00rootroot00000000000000genshi-0.7.6/examples/bench/cheetah/footer.tmpl000066400000000000000000000000311420075204100214600ustar00rootroot00000000000000 genshi-0.7.6/examples/bench/cheetah/header.tmpl000066400000000000000000000000531420075204100214160ustar00rootroot00000000000000 genshi-0.7.6/examples/bench/cheetah/template.tmpl000066400000000000000000000007111420075204100220020ustar00rootroot00000000000000 ${title} #include "cheetah/header.tmpl"

Loop

#if $items
    #for $item in $items
  • $item
  • #end for
#end if #include "cheetah/footer.tmpl" genshi-0.7.6/examples/bench/clearsilver/000077500000000000000000000000001420075204100202045ustar00rootroot00000000000000genshi-0.7.6/examples/bench/clearsilver/footer.cs000066400000000000000000000000311420075204100220230ustar00rootroot00000000000000 genshi-0.7.6/examples/bench/clearsilver/header.cs000066400000000000000000000002011420075204100217540ustar00rootroot00000000000000

Hello, !

genshi-0.7.6/examples/bench/clearsilver/template.cs000066400000000000000000000012261420075204100223470ustar00rootroot00000000000000 <?cs var:title ?>

Loop

    class="last">
genshi-0.7.6/examples/bench/django/000077500000000000000000000000001420075204100171335ustar00rootroot00000000000000genshi-0.7.6/examples/bench/django/templates/000077500000000000000000000000001420075204100211315ustar00rootroot00000000000000genshi-0.7.6/examples/bench/django/templates/base.html000066400000000000000000000006311420075204100227310ustar00rootroot00000000000000 {% block content %} {% block header %} {% endblock %} {% block footer %} {% endblock %} {% endblock %} genshi-0.7.6/examples/bench/django/templates/template.html000066400000000000000000000010461420075204100236330ustar00rootroot00000000000000{% extends "base.html" %} {% load bench %} {% block content %} {{title|escape}} {% block header %}{% endblock %}
{% greeting user %}
{% greeting "me" %}
{% greeting "world" %}

Loop

{% if items %}
    {% for item in items %} {{ item|escape }} {% endfor %}
{% endif %} {% block footer %}{% endblock %} {% endblock %} genshi-0.7.6/examples/bench/django/templatetags/000077500000000000000000000000001420075204100216255ustar00rootroot00000000000000genshi-0.7.6/examples/bench/django/templatetags/__init__.py000066400000000000000000000000001420075204100237240ustar00rootroot00000000000000genshi-0.7.6/examples/bench/django/templatetags/bench.py000066400000000000000000000003341420075204100232560ustar00rootroot00000000000000from django.template import Library, Node, resolve_variable from django.utils.html import escape register = Library() def greeting(name): return 'Hello, %s!' % escape(name) greeting = register.simple_tag(greeting) genshi-0.7.6/examples/bench/genshi/000077500000000000000000000000001420075204100171465ustar00rootroot00000000000000genshi-0.7.6/examples/bench/genshi/base.html000066400000000000000000000005231420075204100207460ustar00rootroot00000000000000

Hello, ${name}!

${select('*')}